Remove fixed discounts correctly

This commit is contained in:
Mike Jolley 2017-08-10 12:06:03 +01:00
parent f23314a3c0
commit 3dc9f06f6a
4 changed files with 45 additions and 52 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -889,7 +889,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( $item_discounts ) {
foreach ( $item_discounts as $item_id => $amount ) {
$item = $this->get_item( $item_id );
$item->set_total( $amount );
$item->set_total( max( 0, $item->get_total() - $amount ) );
$item->save();
}
unset( $this->items['line_items'] ); // Remove read line items variable so new totals are loaded from DB.
@ -966,8 +966,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
* @since 3.2.0
*/
protected function recalculate_coupons() {
$coupons = $this->get_items( 'coupon' );
$items = $this->get_items();
$coupons = $this->get_items( 'coupon' );
$coupon_code_to_id = wc_list_pluck( $coupons, 'get_id', 'get_code' );
$items = $this->get_items();
// Reset line item totals.
foreach ( $items as $item ) {
@ -983,28 +984,27 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$discounts = new WC_Discounts( $this );
foreach ( $coupons as $coupon ) {
$applied = $discounts->apply_discount( $coupon->get_code(), $coupon->get_id() );
$discounts->apply_discount( $coupon->get_code(), $coupon->get_id() );
}
if ( $applied && ! is_wp_error( $applied ) ) {
$item_discounts = $discounts->get_discounts_by_item();
$coupon_discounts = $discounts->get_discounts_by_coupon();
$item_discounts = $discounts->get_discounts_by_item();
$coupon_discounts = $discounts->get_discounts_by_coupon();
// Add discounts to line items.
if ( $item_discounts ) {
foreach ( $item_discounts as $item_id => $amount ) {
$item = $items[ $item_id ];
$item->set_total( $amount );
$item->save();
}
}
// Add discounts to line items.
if ( $item_discounts ) {
foreach ( $item_discounts as $item_id => $amount ) {
$item = $items[ $item_id ];
$item->set_total( $amount );
$item->save();
}
}
if ( $coupon_discounts ) {
foreach ( $coupon_discounts as $item_id => $amount ) {
$item = $items[ $item_id ];
$item->set_discount( $amount ); // @todo discount tax.
$item->save();
}
}
if ( $coupon_discounts ) {
foreach ( $coupon_discounts as $coupon_code => $amount ) {
$item_id = $coupon_code_to_id[ $coupon_code ];
$item = $items[ $item_id ];
$item->set_discount( $amount ); // @todo discount tax.
$item->save();
}
}

View File

@ -261,7 +261,7 @@ class WC_Discounts {
*/
public function apply_discount( $raw_discount, $discount_id = null ) {
if ( is_a( $raw_discount, 'WC_Coupon' ) ) {
return $this->apply_coupon( $raw_discount, $discount_id );
return $this->apply_coupon( $raw_discount );
}
$discount = new WC_Discount;
@ -298,20 +298,17 @@ class WC_Discounts {
*
* @since 3.2.0
* @param WC_Coupon $coupon Coupon object being applied to the items.
* @param string $discount_id Optional ID for the discount. Generated from discount or coupon code if not defined.
* @return bool|WP_Error True if applied or WP_Error instance in failure.
*/
protected function apply_coupon( $coupon, $discount_id = null ) {
protected function apply_coupon( $coupon ) {
$is_coupon_valid = $this->is_coupon_valid( $coupon );
if ( is_wp_error( $is_coupon_valid ) ) {
return $is_coupon_valid;
}
$discount_id = $discount_id ? $discount_id : $coupon->get_code();
if ( ! isset( $this->discounts[ $discount_id ] ) ) {
$this->discounts[ $discount_id ] = array_fill_keys( array_keys( $this->items ), 0 );
if ( ! isset( $this->discounts[ $coupon->get_code() ] ) ) {
$this->discounts[ $coupon->get_code() ] = array_fill_keys( array_keys( $this->items ), 0 );
}
$items_to_apply = $this->get_items_to_apply_coupon( $coupon );
@ -320,13 +317,13 @@ class WC_Discounts {
// Core discounts are handled here as of 3.2.
switch ( $coupon->get_discount_type() ) {
case 'percent' :
$this->apply_coupon_percent( $coupon, $items_to_apply, $discount_id );
$this->apply_coupon_percent( $coupon, $items_to_apply );
break;
case 'fixed_product' :
$this->apply_coupon_fixed_product( $coupon, $items_to_apply, $discount_id );
$this->apply_coupon_fixed_product( $coupon, $items_to_apply );
break;
case 'fixed_cart' :
$this->apply_coupon_fixed_cart( $coupon, $items_to_apply, $discount_id );
$this->apply_coupon_fixed_cart( $coupon, $items_to_apply );
break;
default :
foreach ( $items_to_apply as $item ) {
@ -335,7 +332,7 @@ class WC_Discounts {
$discount = min( $discounted_price, wc_add_number_precision( $coupon->get_discount_amount( $price_to_discount ), $item->object ) );
// Store code and discount amount per item.
$this->discounts[ $discount_id ][ $item->key ] += $discount;
$this->discounts[ $coupon->get_code() ][ $item->key ] += $discount;
}
break;
}
@ -418,10 +415,9 @@ class WC_Discounts {
* @since 3.2.0
* @param WC_Coupon $coupon Coupon object. Passed through filters.
* @param array $items_to_apply Array of items to apply the coupon to.
* @param string $discount_id Optional ID for the discount. Generated from discount or coupon code if not defined.
* @return int Total discounted.
*/
protected function apply_coupon_percent( $coupon, $items_to_apply, $discount_id = null ) {
protected function apply_coupon_percent( $coupon, $items_to_apply ) {
$total_discount = 0;
$cart_total = 0;
@ -441,14 +437,14 @@ class WC_Discounts {
$total_discount += $discount;
// Store code and discount amount per item.
$this->discounts[ $discount_id ][ $item->key ] += $discount;
$this->discounts[ $coupon->get_code() ][ $item->key ] += $discount;
}
// Work out how much discount would have been given to the cart has a whole and compare to what was discounted on all line items.
$cart_total_discount = wc_cart_round_discount( $cart_total * ( $coupon->get_amount() / 100 ), 0 );
if ( $total_discount < $cart_total_discount ) {
$total_discount += $this->apply_coupon_remainder( $coupon, $items_to_apply, $discount_id, $cart_total_discount - $total_discount );
$total_discount += $this->apply_coupon_remainder( $coupon, $items_to_apply, $cart_total_discount - $total_discount );
}
return $total_discount;
@ -460,11 +456,10 @@ class WC_Discounts {
* @since 3.2.0
* @param WC_Coupon $coupon Coupon object. Passed through filters.
* @param array $items_to_apply Array of items to apply the coupon to.
* @param string $discount_id Optional ID for the discount. Generated from discount or coupon code if not defined.
* @param int $amount Fixed discount amount to apply in cents. Leave blank to pull from coupon.
* @return int Total discounted.
*/
protected function apply_coupon_fixed_product( $coupon, $items_to_apply, $discount_id = null, $amount = null ) {
protected function apply_coupon_fixed_product( $coupon, $items_to_apply, $amount = null ) {
$total_discount = 0;
$amount = $amount ? $amount: wc_add_number_precision( $coupon->get_amount() );
@ -481,7 +476,7 @@ class WC_Discounts {
$total_discount += $discount;
// Store code and discount amount per item.
$this->discounts[ $discount_id ][ $item->key ] += $discount;
$this->discounts[ $coupon->get_code() ][ $item->key ] += $discount;
}
return $total_discount;
}
@ -492,11 +487,10 @@ class WC_Discounts {
* @since 3.2.0
* @param WC_Coupon $coupon Coupon object. Passed through filters.
* @param array $items_to_apply Array of items to apply the coupon to.
* @param string $discount_id Optional ID for the discount. Generated from discount or coupon code if not defined.
* @param int $amount Fixed discount amount to apply in cents. Leave blank to pull from coupon.
* @return int Total discounted.
*/
protected function apply_coupon_fixed_cart( $coupon, $items_to_apply, $discount_id = null, $amount = null ) {
protected function apply_coupon_fixed_cart( $coupon, $items_to_apply, $amount = null ) {
$total_discount = 0;
$amount = $amount ? $amount : wc_add_number_precision( $coupon->get_amount() );
$items_to_apply = array_filter( $items_to_apply, array( $this, 'filter_products_with_price' ) );
@ -508,16 +502,16 @@ class WC_Discounts {
$per_item_discount = absint( $amount / $item_count ); // round it down to the nearest cent.
if ( $per_item_discount > 0 ) {
$total_discount = $this->apply_coupon_fixed_product( $coupon, $items_to_apply, $discount_id, $per_item_discount );
$total_discount = $this->apply_coupon_fixed_product( $coupon, $items_to_apply, $per_item_discount );
/**
* If there is still discount remaining, repeat the process.
*/
if ( $total_discount > 0 && $total_discount < $amount ) {
$total_discount += $this->apply_coupon_fixed_cart( $coupon, $items_to_apply, $discount_id, $amount - $total_discount );
$total_discount += $this->apply_coupon_fixed_cart( $coupon, $items_to_apply, $amount - $total_discount );
}
} elseif ( $amount > 0 ) {
$total_discount += $this->apply_coupon_remainder( $coupon, $items_to_apply, $discount_id, $amount );
$total_discount += $this->apply_coupon_remainder( $coupon, $items_to_apply, $amount );
}
return $total_discount;
}
@ -529,11 +523,10 @@ class WC_Discounts {
* @since 3.2.0
* @param WC_Coupon $coupon Coupon object if appliable. Passed through filters.
* @param array $items_to_apply Array of items to apply the coupon to.
* @param string $discount_id Optional ID for the discount. Generated from discount or coupon code if not defined.
* @param int $amount Fixed discount amount to apply.
* @return int Total discounted.
*/
protected function apply_coupon_remainder( $coupon, $items_to_apply, $discount_id = null, $amount ) {
protected function apply_coupon_remainder( $coupon, $items_to_apply, $amount ) {
$total_discount = 0;
foreach ( $items_to_apply as $item ) {
@ -551,7 +544,7 @@ class WC_Discounts {
$total_discount += $discount;
// Store code and discount amount per item.
$this->discounts[ $discount_id ][ $item->key ] += $discount;
$this->discounts[ $coupon->get_code() ][ $item->key ] += $discount;
if ( $total_discount >= $amount ) {
break 2;