From 06c1a2ad8daa5062e53267ab249ef292b6e2b744 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Thu, 20 Jul 2017 14:33:38 +0100 Subject: [PATCH 01/21] apply discount --- includes/class-wc-discounts.php | 13 +++++ tests/unit-tests/discounts/discounts.php | 60 ++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index 26b9b56b6d1..3593d45d59b 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -155,6 +155,19 @@ class WC_Discounts { } } + /** + * Allows a discount to be applied to the items programmatically without a coupon. + * @return [type] [description] + */ + public function apply_discount( $discount ) { + if ( strstr( $discount, '%' ) ) { + $discount = absint( rtrim( $discount, '%' ) ); + $discounted = $this->apply_percentage_discount( $this->items, $discount ); + + return $this->remove_precision( $discounted ); + } + } + /** * Apply a discount to all items using a coupon. * diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index 247f5257441..3d591bb7b76 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -48,6 +48,66 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $order->delete( true ); } + public function test_apply_discount() { + $tax_rate = array( + 'tax_rate_country' => '', + 'tax_rate_state' => '', + 'tax_rate' => '20.0000', + 'tax_rate_name' => 'VAT', + 'tax_rate_priority' => '1', + 'tax_rate_compound' => '0', + 'tax_rate_shipping' => '1', + 'tax_rate_order' => '1', + 'tax_rate_class' => '', + ); + $tax_rate2 = array( + 'tax_rate_country' => '', + 'tax_rate_state' => '', + 'tax_rate' => '20.0000', + 'tax_rate_name' => 'VAT', + 'tax_rate_priority' => '1', + 'tax_rate_compound' => '0', + 'tax_rate_shipping' => '1', + 'tax_rate_order' => '1', + 'tax_rate_class' => 'reduced-rate', + ); + $tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate ); + $tax_rate_id2 = WC_Tax::_insert_tax_rate( $tax_rate2 ); + update_option( 'woocommerce_calc_taxes', 'yes' ); + + $product = WC_Helper_Product::create_simple_product(); + $product2 = WC_Helper_Product::create_simple_product(); + + $product->set_tax_class( '' ); + $product2->set_tax_class( 'reduced-rate' ); + + $product->save(); + $product2->save(); + + // Add product to the cart. + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_to_cart( $product2->get_id(), 1 ); + + // Test. + $discounts = new WC_Discounts(); + $discounts->set_items( WC()->cart->get_cart() ); + $result = $discounts->apply_discount( '50%' ); + + echo "\n\n\n"; + print_r( $result ); + echo "\n\n\n"; + + $this->assertEquals( array( 'test' => 2 ), $result ); + + // Cleanup. + WC()->cart->empty_cart(); + $product->delete( true ); + $product2->delete( true ); + WC_Tax::_delete_tax_rate( $tax_rate_id ); + WC_Tax::_delete_tax_rate( $tax_rate_id2 ); + update_option( 'woocommerce_calc_taxes', 'no' ); + } + /** * test get_applied_coupons */ From 0e96bd8a93e9f79f63f6d99592d5610203ee3fad Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Thu, 20 Jul 2017 17:34:30 +0100 Subject: [PATCH 02/21] Discount rows --- includes/class-wc-discounts.php | 44 ++++++++++++++++++++---- tests/unit-tests/discounts/discounts.php | 12 ++++--- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index 3593d45d59b..f9990d94c07 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -157,15 +157,47 @@ class WC_Discounts { /** * Allows a discount to be applied to the items programmatically without a coupon. - * @return [type] [description] + * + * @param string $raw_discount Discount amount either fixed or percentage. + * @return int discounted amount in cents. */ - public function apply_discount( $discount ) { - if ( strstr( $discount, '%' ) ) { - $discount = absint( rtrim( $discount, '%' ) ); - $discounted = $this->apply_percentage_discount( $this->items, $discount ); + public function apply_discount( $raw_discount ) { + if ( strstr( $raw_discount, '%' ) ) { + $discount = absint( rtrim( $raw_discount, '%' ) ); + $total_to_discount = 0; - return $this->remove_precision( $discounted ); + // Get total item cost right now. + foreach ( $this->items as $item ) { + $total_to_discount += $this->get_discounted_price_in_cents( $item ); + } + + // @todo sum other manual discounts too + foreach ( $this->discounts as $key => $value ) { + if ( strstr( $key, 'discount-' ) ) { + $total_to_discount = $total_to_discount - $value; + } + } + + $discount_total = $discount * ( $total_to_discount / 100 ); + $discount_id = ''; + $index = 1; + + while ( ! $discount_id ) { + $discount_id = 'discount-' . $raw_discount; + + if ( 1 < $index ) { + $discount_id .= '-' . $index; + } + + if ( isset( $this->discounts[ $discount_id ] ) ) { + $index ++; + $discount_id = ''; + } + } + + return $this->discounts[ $discount_id ] = $discount_total; } + // @todo fixed discounts } /** diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index 3d591bb7b76..f5d185e4ab5 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -91,13 +91,15 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { // Test. $discounts = new WC_Discounts(); $discounts->set_items( WC()->cart->get_cart() ); - $result = $discounts->apply_discount( '50%' ); - echo "\n\n\n"; - print_r( $result ); - echo "\n\n\n"; + $discounts->apply_discount( '50%' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-50%'], 10 ); - $this->assertEquals( array( 'test' => 2 ), $result ); + $discounts->apply_discount( '50%' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-50%'], 10, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-50%-2'], 5, print_r( $all_discounts, true ) ); // Cleanup. WC()->cart->empty_cart(); From e5ec0e66e309931b31892c833824ae3f10273807 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Thu, 20 Jul 2017 20:33:27 +0100 Subject: [PATCH 03/21] fixed discount --- includes/class-wc-discounts.php | 69 ++++++++++++------------ tests/unit-tests/discounts/discounts.php | 19 +++++++ 2 files changed, 54 insertions(+), 34 deletions(-) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index f9990d94c07..ff6e934ba63 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -162,42 +162,43 @@ class WC_Discounts { * @return int discounted amount in cents. */ public function apply_discount( $raw_discount ) { - if ( strstr( $raw_discount, '%' ) ) { - $discount = absint( rtrim( $raw_discount, '%' ) ); - $total_to_discount = 0; + // Get total item cost after any extra discounts. + $total_to_discount = 0; - // Get total item cost right now. - foreach ( $this->items as $item ) { - $total_to_discount += $this->get_discounted_price_in_cents( $item ); - } - - // @todo sum other manual discounts too - foreach ( $this->discounts as $key => $value ) { - if ( strstr( $key, 'discount-' ) ) { - $total_to_discount = $total_to_discount - $value; - } - } - - $discount_total = $discount * ( $total_to_discount / 100 ); - $discount_id = ''; - $index = 1; - - while ( ! $discount_id ) { - $discount_id = 'discount-' . $raw_discount; - - if ( 1 < $index ) { - $discount_id .= '-' . $index; - } - - if ( isset( $this->discounts[ $discount_id ] ) ) { - $index ++; - $discount_id = ''; - } - } - - return $this->discounts[ $discount_id ] = $discount_total; + foreach ( $this->items as $item ) { + $total_to_discount += $this->get_discounted_price_in_cents( $item ); } - // @todo fixed discounts + + foreach ( $this->discounts as $key => $value ) { + if ( strstr( $key, 'discount-' ) ) { + $total_to_discount = $total_to_discount - $value; + } + } + + if ( strstr( $raw_discount, '%' ) ) { + $discount = absint( rtrim( $raw_discount, '%' ) ); + $discount_total = $discount * ( $total_to_discount / 100 ); + } else { + $discount_total = min( absint( $raw_discount * $this->precision ), $total_to_discount ); + } + + $discount_id = ''; + $index = 1; + + while ( ! $discount_id ) { + $discount_id = 'discount-' . $raw_discount; + + if ( 1 < $index ) { + $discount_id .= '-' . $index; + } + + if ( isset( $this->discounts[ $discount_id ] ) ) { + $index ++; + $discount_id = ''; + } + } + + return $this->discounts[ $discount_id ] = $discount_total; } /** diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index f5d185e4ab5..5941aa91ad4 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -101,6 +101,25 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $this->assertEquals( $all_discounts['discount-50%'], 10, print_r( $all_discounts, true ) ); $this->assertEquals( $all_discounts['discount-50%-2'], 5, print_r( $all_discounts, true ) ); + // Test fixed discounts. + $discounts = new WC_Discounts(); + $discounts->set_items( WC()->cart->get_cart() ); + + $discounts->apply_discount( '5' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-5'], 5 ); + + $discounts->apply_discount( '5' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); + + $discounts->apply_discount( '15' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-15'], 10, print_r( $all_discounts, true ) ); + // Cleanup. WC()->cart->empty_cart(); $product->delete( true ); From 499519eaac50af9ef0b2fe6aa9b1af073791fdc8 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Thu, 20 Jul 2017 20:50:09 +0100 Subject: [PATCH 04/21] WC_Discount class --- includes/class-wc-discount.php | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 includes/class-wc-discount.php diff --git a/includes/class-wc-discount.php b/includes/class-wc-discount.php new file mode 100644 index 00000000000..49b238af53e --- /dev/null +++ b/includes/class-wc-discount.php @@ -0,0 +1,77 @@ + '', + 'discount' => 0, + ); + + /** + * Coupon ID. + * + * @param string $id + */ + public function set_id( $id ) { + + } + + /** + * Discount amount - either fixed or percentage. + * + * @param string $amount + */ + public function set_amount( $amount ) { + + } + + /** + * Amount of discount this has given in total. + */ + public function set_discount_total() { + + } + + /** + * Array of negative taxes. + */ + public function set_taxes() { + + } + + /** + * Calculates the amount of negative tax to apply for this discount, since + * discounts are applied before tax. + * + * For percent discounts this is simply a percent of each cart item's tax. + * + * For fixed discounts, the taxes are calculated proportionally so the + * discount is fairly split between items. + * + * @return [type] [description] + */ + public function calculate_negative_taxes() { + + } + +} From 83b60573fa0e5643d858eff6891c69262b0a619a Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 21 Jul 2017 14:22:40 +0100 Subject: [PATCH 05/21] Framework for discount class --- includes/class-wc-discount.php | 103 +++++++++++++++++++----- tests/unit-tests/discounts/discount.php | 43 ++++++++++ 2 files changed, 125 insertions(+), 21 deletions(-) create mode 100644 tests/unit-tests/discounts/discount.php diff --git a/includes/class-wc-discount.php b/includes/class-wc-discount.php index 49b238af53e..2c5248163a7 100644 --- a/includes/class-wc-discount.php +++ b/includes/class-wc-discount.php @@ -1,4 +1,8 @@ '', - 'discount' => 0, + 'amount' => 0, + 'discount' => 0, + 'discount_type' => 'fixed_cart', ); /** - * Coupon ID. + * Checks the coupon type. + * @param string $type Array or string of types + * @return bool + */ + public function is_type( $type ) { + return ( $this->get_discount_type() === $type || ( is_array( $type ) && in_array( $this->get_discount_type(), $type ) ) ); + } + + /** + * Prefix for action and filter hooks on data. + * + * @return string + */ + protected function get_hook_prefix() { + return 'woocommerce_discount_get_'; + } + + /** + * Returns the ID of this dicount. + * + * @return string + */ + public function get_id() { + return $this->id; + } + + /** + * Discount ID. * * @param string $id */ public function set_id( $id ) { + $this->id = $id; + } + /** + * Get discount amount. + * + * @param string $context + * @return float + */ + public function get_amount( $context = 'view' ) { + return $this->get_prop( 'amount', $context ); } /** * Discount amount - either fixed or percentage. * - * @param string $amount + * @param string $raw_amount */ - public function set_amount( $amount ) { - + public function set_amount( $raw_amount ) { + if ( strstr( $raw_amount, '%' ) ) { + $amount = absint( rtrim( $raw_amount, '%' ) ); + $this->set_prop( 'amount', $amount ); + $this->set_discount_type( 'percent' ); + } else { + $this->set_prop( 'amount', wc_format_decimal( $amount ) ); + } } /** - * Amount of discount this has given in total. + * Get discount type. + * + * @param string $context + * @return string */ - public function set_discount_total() { - + public function get_discount_type( $context = 'view' ) { + return $this->get_prop( 'discount_type', $context ); } /** - * Array of negative taxes. + * Set discount type. + * + * @param string $discount_type + * @throws WC_Data_Exception */ - public function set_taxes() { - + public function set_discount_type( $discount_type ) { + if ( ! in_array( $discount_type, array( 'percent', 'fixed_cart' ) ) { + $this->error( 'coupon_invalid_discount_type', __( 'Invalid discount type', 'woocommerce' ) ); + } + $this->set_prop( 'discount_type', $discount_type ); } + /** + * Amount of discount this has given in total. @todo should this be here? + */ + public function set_discount_total() {} + + /** + * Array of negative taxes. @todo should this be here? + */ + public function set_taxes() {} + /** * Calculates the amount of negative tax to apply for this discount, since * discounts are applied before tax. @@ -68,10 +131,8 @@ class WC_Discount { * For fixed discounts, the taxes are calculated proportionally so the * discount is fairly split between items. * - * @return [type] [description] + * @todo Should this bere here? */ - public function calculate_negative_taxes() { - - } + public function calculate_negative_taxes() {} } diff --git a/tests/unit-tests/discounts/discount.php b/tests/unit-tests/discounts/discount.php new file mode 100644 index 00000000000..6ce0f5140b4 --- /dev/null +++ b/tests/unit-tests/discounts/discount.php @@ -0,0 +1,43 @@ + Date: Thu, 27 Jul 2017 10:37:20 -0700 Subject: [PATCH 06/21] Get everything working again --- includes/class-wc-discounts.php | 2 +- tests/unit-tests/discounts/discounts.php | 164 ++++++++++++----------- 2 files changed, 84 insertions(+), 82 deletions(-) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index 2c82cf860d9..48eab63043b 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -159,7 +159,7 @@ class WC_Discounts { $discount = absint( rtrim( $raw_discount, '%' ) ); $discount_total = $discount * ( $total_to_discount / 100 ); } else { - $discount_total = min( absint( $raw_discount * $this->precision ), $total_to_discount ); + $discount_total = min( absint( wc_add_number_precision( $raw_discount ) ), $total_to_discount ); } $discount_id = ''; diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index 30cde832a0a..f5ed0b16b21 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -76,87 +76,6 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $order->delete( true ); } - public function test_apply_discount() { - $tax_rate = array( - 'tax_rate_country' => '', - 'tax_rate_state' => '', - 'tax_rate' => '20.0000', - 'tax_rate_name' => 'VAT', - 'tax_rate_priority' => '1', - 'tax_rate_compound' => '0', - 'tax_rate_shipping' => '1', - 'tax_rate_order' => '1', - 'tax_rate_class' => '', - ); - $tax_rate2 = array( - 'tax_rate_country' => '', - 'tax_rate_state' => '', - 'tax_rate' => '20.0000', - 'tax_rate_name' => 'VAT', - 'tax_rate_priority' => '1', - 'tax_rate_compound' => '0', - 'tax_rate_shipping' => '1', - 'tax_rate_order' => '1', - 'tax_rate_class' => 'reduced-rate', - ); - $tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate ); - $tax_rate_id2 = WC_Tax::_insert_tax_rate( $tax_rate2 ); - update_option( 'woocommerce_calc_taxes', 'yes' ); - - $product = WC_Helper_Product::create_simple_product(); - $product2 = WC_Helper_Product::create_simple_product(); - - $product->set_tax_class( '' ); - $product2->set_tax_class( 'reduced-rate' ); - - $product->save(); - $product2->save(); - - // Add product to the cart. - WC()->cart->add_to_cart( $product->get_id(), 1 ); - WC()->cart->add_to_cart( $product2->get_id(), 1 ); - - // Test. - $discounts = new WC_Discounts(); - $discounts->set_items( WC()->cart->get_cart() ); - - $discounts->apply_discount( '50%' ); - $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-50%'], 10 ); - - $discounts->apply_discount( '50%' ); - $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-50%'], 10, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-50%-2'], 5, print_r( $all_discounts, true ) ); - - // Test fixed discounts. - $discounts = new WC_Discounts(); - $discounts->set_items( WC()->cart->get_cart() ); - - $discounts->apply_discount( '5' ); - $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-5'], 5 ); - - $discounts->apply_discount( '5' ); - $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); - - $discounts->apply_discount( '15' ); - $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-15'], 10, print_r( $all_discounts, true ) ); - - // Cleanup. - WC()->cart->empty_cart(); - $product->delete( true ); - $product2->delete( true ); - WC_Tax::_delete_tax_rate( $tax_rate_id ); - WC_Tax::_delete_tax_rate( $tax_rate_id2 ); - update_option( 'woocommerce_calc_taxes', 'no' ); - } - /** * test get_applied_coupons */ @@ -533,4 +452,87 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { update_option( 'woocommerce_calc_taxes', 'no' ); $coupon->delete( true ); } + + /** + * Test apply_discount method. + */ + public function test_apply_discount() { + $tax_rate = array( + 'tax_rate_country' => '', + 'tax_rate_state' => '', + 'tax_rate' => '20.0000', + 'tax_rate_name' => 'VAT', + 'tax_rate_priority' => '1', + 'tax_rate_compound' => '0', + 'tax_rate_shipping' => '1', + 'tax_rate_order' => '1', + 'tax_rate_class' => '', + ); + $tax_rate2 = array( + 'tax_rate_country' => '', + 'tax_rate_state' => '', + 'tax_rate' => '20.0000', + 'tax_rate_name' => 'VAT', + 'tax_rate_priority' => '1', + 'tax_rate_compound' => '0', + 'tax_rate_shipping' => '1', + 'tax_rate_order' => '1', + 'tax_rate_class' => 'reduced-rate', + ); + $tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate ); + $tax_rate_id2 = WC_Tax::_insert_tax_rate( $tax_rate2 ); + update_option( 'woocommerce_calc_taxes', 'yes' ); + + $product = WC_Helper_Product::create_simple_product(); + $product2 = WC_Helper_Product::create_simple_product(); + + $product->set_tax_class( '' ); + $product2->set_tax_class( 'reduced-rate' ); + + $product->save(); + $product2->save(); + + // Add product to the cart. + WC()->cart->add_to_cart( $product->get_id(), 1 ); + WC()->cart->add_to_cart( $product2->get_id(), 1 ); + + $discounts = new WC_Discounts(); + $discounts->set_items( $this->get_items_for_discounts_class() ); + + $discounts->apply_discount( '50%' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-50%'], 10 ); + + $discounts->apply_discount( '50%' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-50%'], 10, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-50%-2'], 5, print_r( $all_discounts, true ) ); + + // Test fixed discounts. + $discounts = new WC_Discounts(); + $discounts->set_items( $this->get_items_for_discounts_class() ); + + $discounts->apply_discount( '5' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-5'], 5 ); + + $discounts->apply_discount( '5' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); + + $discounts->apply_discount( '15' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( $all_discounts['discount-15'], 10, print_r( $all_discounts, true ) ); + + // Cleanup. + WC()->cart->empty_cart(); + $product->delete( true ); + $product2->delete( true ); + WC_Tax::_delete_tax_rate( $tax_rate_id ); + WC_Tax::_delete_tax_rate( $tax_rate_id2 ); + update_option( 'woocommerce_calc_taxes', 'no' ); + } } From 3a11e345a6837e01ce8b4378ab97c1c47b81ad82 Mon Sep 17 00:00:00 2001 From: claudiulodro Date: Thu, 27 Jul 2017 11:08:22 -0700 Subject: [PATCH 07/21] Fix some things and hook up discount class --- includes/class-wc-discount.php | 12 ++++++++++-- includes/class-wc-discounts.php | 10 ++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/includes/class-wc-discount.php b/includes/class-wc-discount.php index 2c5248163a7..760a64ffe03 100644 --- a/includes/class-wc-discount.php +++ b/includes/class-wc-discount.php @@ -85,7 +85,7 @@ class WC_Discount extends WC_Data { $this->set_prop( 'amount', $amount ); $this->set_discount_type( 'percent' ); } else { - $this->set_prop( 'amount', wc_format_decimal( $amount ) ); + $this->set_prop( 'amount', wc_format_decimal( $raw_amount ) ); } } @@ -99,6 +99,14 @@ class WC_Discount extends WC_Data { return $this->get_prop( 'discount_type', $context ); } + public function get_discount_amount( $total ) { + if ( 'percent' === $this->get_discount_type() ) { + return $this->get_amount() * ( $total / 100 ); + } else { + return min( absint( wc_add_number_precision( $this->get_amount() ) ), $total ); + } + } + /** * Set discount type. * @@ -106,7 +114,7 @@ class WC_Discount extends WC_Data { * @throws WC_Data_Exception */ public function set_discount_type( $discount_type ) { - if ( ! in_array( $discount_type, array( 'percent', 'fixed_cart' ) ) { + if ( ! in_array( $discount_type, array( 'percent', 'fixed_cart' ) ) ) { $this->error( 'coupon_invalid_discount_type', __( 'Invalid discount type', 'woocommerce' ) ); } $this->set_prop( 'discount_type', $discount_type ); diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index 48eab63043b..bc6344ab4aa 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -155,13 +155,15 @@ class WC_Discounts { } } - if ( strstr( $raw_discount, '%' ) ) { - $discount = absint( rtrim( $raw_discount, '%' ) ); - $discount_total = $discount * ( $total_to_discount / 100 ); + if ( is_a( $raw_discount, 'WC_Discount' ) ) { + $discount = $raw_discount; } else { - $discount_total = min( absint( wc_add_number_precision( $raw_discount ) ), $total_to_discount ); + $discount = new WC_Discount; + $discount->set_amount( $raw_discount ); } + $discount_total = $discount->get_discount_amount( $total_to_discount ); + $discount_id = ''; $index = 1; From b56b87c97b1157322bfd41041b714caf5cdaab90 Mon Sep 17 00:00:00 2001 From: claudiulodro Date: Thu, 27 Jul 2017 14:08:38 -0700 Subject: [PATCH 08/21] Good progress on wc_discount and manual discount handling --- includes/class-wc-discount.php | 25 +++++++------ includes/class-wc-discounts.php | 46 ++++++++++++++++++------ tests/unit-tests/discounts/discount.php | 16 +++++++-- tests/unit-tests/discounts/discounts.php | 18 +++++----- 4 files changed, 74 insertions(+), 31 deletions(-) diff --git a/includes/class-wc-discount.php b/includes/class-wc-discount.php index 760a64ffe03..af4b1c6e42e 100644 --- a/includes/class-wc-discount.php +++ b/includes/class-wc-discount.php @@ -99,14 +99,6 @@ class WC_Discount extends WC_Data { return $this->get_prop( 'discount_type', $context ); } - public function get_discount_amount( $total ) { - if ( 'percent' === $this->get_discount_type() ) { - return $this->get_amount() * ( $total / 100 ); - } else { - return min( absint( wc_add_number_precision( $this->get_amount() ) ), $total ); - } - } - /** * Set discount type. * @@ -121,9 +113,22 @@ class WC_Discount extends WC_Data { } /** - * Amount of discount this has given in total. @todo should this be here? + * Amount of discount this has given in total cents. + * + * @param int $total */ - public function set_discount_total() {} + public function set_discount_total( $total ) { + $this->set_prop( 'discount', absint( $total ) ); + } + + /** + * Get amount of discount this has in cents. + * + * @return int + */ + public function get_discount_total( $context = 'view' ) { + return $this->get_prop( 'discount', $context ); + } /** * Array of negative taxes. @todo should this be here? diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index bc6344ab4aa..d2cd2e8f1ef 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -38,6 +38,13 @@ class WC_Discounts { */ protected $applied_coupons = array(); + /** + * An array of applied WC_Discount objects. + * + * @var array + */ + protected $manual_discounts = array(); + /** * Constructor. * @@ -76,7 +83,19 @@ class WC_Discounts { * @return array */ public function get_discounts( $in_cents = false ) { - return $in_cents ? $this->discounts : wc_remove_number_precision_deep ( $this->discounts ); + + $discounts = $in_cents ? $this->discounts : wc_remove_number_precision_deep ( $this->discounts ); + + $manual = array(); + foreach ( $this->manual_discounts as $manual_discount ) { + $manual[ $manual_discount->get_id() ] = $in_cents ? $manual_discount->get_discount_total() : wc_remove_number_precision_deep( $manual_discount->get_discount_total() ); + } + + return array_merge( $discounts, $manual ); + } + + public function get_manual_discounts() { + return $this->manual_discounts; } /** @@ -149,10 +168,8 @@ class WC_Discounts { $total_to_discount += $this->get_discounted_price_in_cents( $item ); } - foreach ( $this->discounts as $key => $value ) { - if ( strstr( $key, 'discount-' ) ) { - $total_to_discount = $total_to_discount - $value; - } + foreach ( $this->manual_discounts as $key => $value ) { + $total_to_discount = $total_to_discount - $value->get_discount_total(); } if ( is_a( $raw_discount, 'WC_Discount' ) ) { @@ -162,25 +179,32 @@ class WC_Discounts { $discount->set_amount( $raw_discount ); } - $discount_total = $discount->get_discount_amount( $total_to_discount ); + if ( 'percent' === $discount->get_discount_type() ) { + $discount_total = $discount->get_amount() * ( $total_to_discount / 100 ); + } else { + $discount_total = min( absint( wc_add_number_precision( $discount->get_amount() ) ), $total_to_discount ); + } + $discount->set_discount_total( $discount_total ); $discount_id = ''; $index = 1; - while ( ! $discount_id ) { - $discount_id = 'discount-' . $raw_discount; + $discount_id = 'discount-' . $discount->get_amount() . ( 'percent' === $discount->get_discount_type() ? '%' : '' ); if ( 1 < $index ) { $discount_id .= '-' . $index; } - if ( isset( $this->discounts[ $discount_id ] ) ) { + if ( isset( $this->manual_discounts[ $discount_id ] ) ) { $index ++; $discount_id = ''; } } - return $this->discounts[ $discount_id ] = $discount_total; + $discount->set_id( $discount_id ); + $this->manual_discounts[ $discount_id ] = $discount; + + return $discount->get_discount_total(); } /** @@ -244,6 +268,8 @@ class WC_Discounts { } break; } + + return true; } /** diff --git a/tests/unit-tests/discounts/discount.php b/tests/unit-tests/discounts/discount.php index 6ce0f5140b4..86543d0e854 100644 --- a/tests/unit-tests/discounts/discount.php +++ b/tests/unit-tests/discounts/discount.php @@ -10,21 +10,33 @@ class WC_Tests_Discount extends WC_Unit_Test_Case { * Test get and set ID. */ public function test_get_set_id() { - + $discount = new WC_Discount; + $discount->set_id( 'discount-5' ); + $this->assertEquals( 'discount-5', $discount->get_id() ); } /** * Test get and set ID. */ public function test_get_set_amount() { + $discount = new WC_Discount; + $discount->set_amount( '10' ); + $this->assertEquals( '10', $discount->get_amount() ); + $this->assertEquals( 'fixed_cart', $discount->get_discount_type() ); + $discount = new WC_Discount; + $discount->set_amount( '10%' ); + $this->assertEquals( '10', $discount->get_amount() ); + $this->assertEquals( 'percent', $discount->get_discount_type() ); } /** * Test get and set discount total. */ public function test_get_set_discount_total() { - + $discount = new WC_Discount; + $discount->set_discount_total( 1000 ); + $this->assertEquals( 1000, $discount->get_discount_total() ); } /** diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index f5ed0b16b21..95ffee1cdac 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -501,12 +501,12 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $discounts->apply_discount( '50%' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-50%'], 10 ); + $this->assertEquals( 10, $all_discounts['discount-50%'] ); $discounts->apply_discount( '50%' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-50%'], 10, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-50%-2'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( 10, $all_discounts['discount-50%'], print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-50%-2'], print_r( $all_discounts, true ) ); // Test fixed discounts. $discounts = new WC_Discounts(); @@ -514,18 +514,18 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $discounts->apply_discount( '5' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-5'], 5 ); + $this->assertEquals( 5, $all_discounts['discount-5'] ); $discounts->apply_discount( '5' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-5'], print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-5-2'], print_r( $all_discounts, true ) ); $discounts->apply_discount( '15' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( $all_discounts['discount-5'], 5, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-5-2'], 5, print_r( $all_discounts, true ) ); - $this->assertEquals( $all_discounts['discount-15'], 10, print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-5'], print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-5-2'], print_r( $all_discounts, true ) ); + $this->assertEquals( 10, $all_discounts['discount-15'], print_r( $all_discounts, true ) ); // Cleanup. WC()->cart->empty_cart(); From f57c6dc2eeb85aeba2c208583c2438684ebdb0dc Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 11:42:54 +0100 Subject: [PATCH 09/21] Speed up tests --- phpunit.xml | 10 +++++++--- phpunit.xml.dist | 10 +++++++--- tests/bootstrap.php | 14 ++++++++++---- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/phpunit.xml b/phpunit.xml index 0a829bc9242..fc3f8769d94 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -18,8 +18,10 @@ . - ./apigen/ - ./i18n/ + ./apigen/ + ./assets/ + ./dummy-data/ + ./i18n/ ./includes/api/legacy/ ./includes/gateways/simplify-commerce-deprecated/ ./includes/gateways/simplify-commerce/includes/ @@ -33,7 +35,9 @@ ./includes/widgets/ ./templates/ ./tests/ - ./tmp/ + ./vendor/ + ./.*/ + ./tmp/ diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0ae53994749..16455121568 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,8 +18,10 @@ . - ./apigen/ - ./i18n/ + ./apigen/ + ./assets/ + ./dummy-data/ + ./i18n/ ./includes/api/legacy/ ./includes/gateways/simplify-commerce-deprecated/ ./includes/gateways/simplify-commerce/includes/ @@ -33,7 +35,9 @@ ./includes/widgets/ ./templates/ ./tests/ - ./tmp/ + ./vendor/ + ./.*/ + ./tmp/ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 7973a117ed6..a9c59730dc4 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -24,7 +24,6 @@ class WC_Unit_Tests_Bootstrap { * @since 2.2 */ public function __construct() { - ini_set( 'display_errors','on' ); error_reporting( E_ALL ); @@ -33,6 +32,10 @@ class WC_Unit_Tests_Bootstrap { $_SERVER['SERVER_NAME'] = 'localhost'; } + $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; + $_SERVER['SERVER_NAME'] = ''; + $PHP_SELF = $GLOBALS['PHP_SELF'] = $_SERVER['PHP_SELF'] = '/index.php'; + $this->tests_dir = dirname( __FILE__ ); $this->plugin_dir = dirname( $this->tests_dir ); $this->wp_tests_dir = getenv( 'WP_TESTS_DIR' ) ? getenv( 'WP_TESTS_DIR' ) : '/tmp/wordpress-tests-lib'; @@ -43,12 +46,16 @@ class WC_Unit_Tests_Bootstrap { // load WC tests_add_filter( 'muplugins_loaded', array( $this, 'load_wc' ) ); - // install WC - tests_add_filter( 'setup_theme', array( $this, 'install_wc' ) ); + echo 'Loading WordPress bootstrap...' . PHP_EOL; // load the WP testing environment require_once( $this->wp_tests_dir . '/includes/bootstrap.php' ); + // Activate + install + activate_plugin( 'woocommerce/woocommerce.php' ); + + $this->install_wc(); + // load WC testing framework $this->includes(); } @@ -68,7 +75,6 @@ class WC_Unit_Tests_Bootstrap { * @since 2.2 */ public function install_wc() { - // Clean existing install first. define( 'WP_UNINSTALL_PLUGIN', true ); define( 'WC_REMOVE_ALL_DATA', true ); From 5ed2f147a7fae8623b73bbe4cf786064095a53ae Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 11:51:57 +0100 Subject: [PATCH 10/21] woocommerce_coupon_is_valid --- includes/class-wc-discounts.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index d2cd2e8f1ef..eccf714061a 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -859,7 +859,7 @@ class WC_Discounts { $this->validate_coupon_excluded_items( $coupon ); $this->validate_coupon_eligible_items( $coupon ); - if ( ! apply_filters( 'woocommerce_discount_is_coupon_valid', true, $coupon, $this ) ) { + if ( ! apply_filters( 'woocommerce_coupon_is_valid', true, $coupon, $this ) ) { throw new Exception( __( 'Coupon is not valid.', 'woocommerce' ), 100 ); } } catch ( Exception $e ) { From 9b458f9368cae52c1325072a5734f3038a65b21a Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 12:20:49 +0100 Subject: [PATCH 11/21] Remove private validation methods from coupon and use discounts class --- includes/class-wc-coupon.php | 269 +---------------------------------- 1 file changed, 5 insertions(+), 264 deletions(-) diff --git a/includes/class-wc-coupon.php b/includes/class-wc-coupon.php index df1420eb2a9..f1746d1d48b 100644 --- a/includes/class-wc-coupon.php +++ b/includes/class-wc-coupon.php @@ -739,279 +739,20 @@ class WC_Coupon extends WC_Legacy_Coupon { } /** - * Ensure coupon exists or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_exists. - * @throws Exception - */ - private function validate_exists() { - if ( ! $this->get_id() ) { - throw new Exception( self::E_WC_COUPON_NOT_EXIST ); - } - } - - /** - * Ensure coupon usage limit is valid or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_usage_limit. - * @throws Exception - */ - private function validate_usage_limit() { - if ( $this->get_usage_limit() > 0 && $this->get_usage_count() >= $this->get_usage_limit() ) { - throw new Exception( self::E_WC_COUPON_USAGE_LIMIT_REACHED ); - } - } - - /** - * Ensure coupon user usage limit is valid or throw exception. - * - * Per user usage limit - check here if user is logged in (against user IDs). - * Checked again for emails later on in WC_Cart::check_customer_coupons(). - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_user_usage_limit. - * @param int $user_id - * @throws Exception - */ - private function validate_user_usage_limit( $user_id = 0 ) { - if ( empty( $user_id ) ) { - $user_id = get_current_user_id(); - } - if ( $this->get_usage_limit_per_user() > 0 && is_user_logged_in() && $this->get_id() && $this->data_store ) { - $usage_count = $this->data_store->get_usage_by_user_id( $this, $user_id ); - if ( $usage_count >= $this->get_usage_limit_per_user() ) { - throw new Exception( self::E_WC_COUPON_USAGE_LIMIT_REACHED ); - } - } - } - - /** - * Ensure coupon date is valid or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_expiry_date. - * @throws Exception - */ - private function validate_expiry_date() { - if ( $this->get_date_expires() && current_time( 'timestamp', true ) > $this->get_date_expires()->getTimestamp() ) { - throw new Exception( $error_code = self::E_WC_COUPON_EXPIRED ); - } - } - - /** - * Ensure coupon amount is valid or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_minimum_amount. - * @throws Exception - */ - private function validate_minimum_amount() { - if ( $this->get_minimum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_minimum_amount', $this->get_minimum_amount() > WC()->cart->get_displayed_subtotal(), $this ) ) { - throw new Exception( self::E_WC_COUPON_MIN_SPEND_LIMIT_NOT_MET ); - } - } - - /** - * Ensure coupon amount is valid or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_maximum_amount. - * @throws Exception - */ - private function validate_maximum_amount() { - if ( $this->get_maximum_amount() > 0 && apply_filters( 'woocommerce_coupon_validate_maximum_amount', $this->get_maximum_amount() < WC()->cart->get_displayed_subtotal(), $this ) ) { - throw new Exception( self::E_WC_COUPON_MAX_SPEND_LIMIT_MET ); - } - } - - /** - * Ensure coupon is valid for products in the cart is valid or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_product_ids. - * @throws Exception - */ - private function validate_product_ids() { - if ( sizeof( $this->get_product_ids() ) > 0 ) { - $valid_for_cart = false; - if ( ! WC()->cart->is_empty() ) { - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( in_array( $cart_item['product_id'], $this->get_product_ids() ) || in_array( $cart_item['variation_id'], $this->get_product_ids() ) || in_array( $cart_item['data']->get_parent_id(), $this->get_product_ids() ) ) { - $valid_for_cart = true; - } - } - } - if ( ! $valid_for_cart ) { - throw new Exception( self::E_WC_COUPON_NOT_APPLICABLE ); - } - } - } - - /** - * Ensure coupon is valid for product categories in the cart is valid or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_product_categories. - * @throws Exception - */ - private function validate_product_categories() { - if ( sizeof( $this->get_product_categories() ) > 0 ) { - $valid_for_cart = false; - if ( ! WC()->cart->is_empty() ) { - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( $this->get_exclude_sale_items() && $cart_item['data'] && $cart_item['data']->is_on_sale() ) { - continue; - } - $product_cats = wc_get_product_cat_ids( $cart_item['product_id'] ); - - // If we find an item with a cat in our allowed cat list, the coupon is valid - if ( sizeof( array_intersect( $product_cats, $this->get_product_categories() ) ) > 0 ) { - $valid_for_cart = true; - } - } - } - if ( ! $valid_for_cart ) { - throw new Exception( self::E_WC_COUPON_NOT_APPLICABLE ); - } - } - } - - /** - * Ensure coupon is valid for sale items in the cart is valid or throw exception. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_sale_items. - * @throws Exception - */ - private function validate_sale_items() { - if ( $this->get_exclude_sale_items() ) { - $valid_for_cart = false; - - if ( ! WC()->cart->is_empty() ) { - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - $product = $cart_item['data']; - - if ( ! $product->is_on_sale() ) { - $valid_for_cart = true; - } - } - } - if ( ! $valid_for_cart ) { - throw new Exception( self::E_WC_COUPON_NOT_VALID_SALE_ITEMS ); - } - } - } - - /** - * All exclusion rules must pass at the same time for a product coupon to be valid. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_excluded_items. - * @throws Exception - */ - private function validate_excluded_items() { - if ( ! WC()->cart->is_empty() && $this->is_type( wc_get_product_coupon_types() ) ) { - $valid = false; - - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( $this->is_valid_for_product( $cart_item['data'], $cart_item ) ) { - $valid = true; - break; - } - } - - if ( ! $valid ) { - throw new Exception( self::E_WC_COUPON_NOT_APPLICABLE ); - } - } - } - - /** - * Cart discounts cannot be added if non-eligible product is found in cart. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_eligible_items. - */ - private function validate_cart_excluded_items() { - if ( ! $this->is_type( wc_get_product_coupon_types() ) ) { - $this->validate_cart_excluded_product_ids(); - $this->validate_cart_excluded_product_categories(); - } - } - - /** - * Exclude products from cart. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_excluded_product_ids. - * @throws Exception - */ - private function validate_cart_excluded_product_ids() { - // Exclude Products. - if ( sizeof( $this->get_excluded_product_ids() ) > 0 ) { - $valid_for_cart = true; - if ( ! WC()->cart->is_empty() ) { - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( in_array( $cart_item['product_id'], $this->get_excluded_product_ids() ) || in_array( $cart_item['variation_id'], $this->get_excluded_product_ids() ) || in_array( $cart_item['data']->get_parent_id(), $this->get_excluded_product_ids() ) ) { - $valid_for_cart = false; - } - } - } - if ( ! $valid_for_cart ) { - throw new Exception( self::E_WC_COUPON_EXCLUDED_PRODUCTS ); - } - } - } - - /** - * Exclude categories from cart. - * - * @deprecated 3.2.0 In favor of WC_Discounts->validate_coupon_excluded_product_categories. - * @throws Exception - */ - private function validate_cart_excluded_product_categories() { - if ( sizeof( $this->get_excluded_product_categories() ) > 0 ) { - $valid_for_cart = true; - if ( ! WC()->cart->is_empty() ) { - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - if ( $this->get_exclude_sale_items() && $cart_item['data'] && $cart_item['data']->is_on_sale() ) { - continue; - } - $product_cats = wc_get_product_cat_ids( $cart_item['product_id'] ); - - if ( sizeof( array_intersect( $product_cats, $this->get_excluded_product_categories() ) ) > 0 ) { - $valid_for_cart = false; - } - } - } - if ( ! $valid_for_cart ) { - throw new Exception( self::E_WC_COUPON_EXCLUDED_CATEGORIES ); - } - } - } - - /** - * Check if a coupon is valid. + * Check if a coupon is valid for the cart. * * @deprecated 3.2.0 In favor of WC_Discounts->is_coupon_valid. * @throws Exception * @return bool Validity. */ public function is_valid() { - wc_deprecated_function( 'is_valid', '3.2', 'WC_Discounts->is_coupon_valid' ); + $discounts = new WC_Discounts( WC()->cart ); + $valid = $discounts->is_coupon_valid( $this ); - try { - $this->validate_exists(); - $this->validate_usage_limit(); - $this->validate_user_usage_limit(); - $this->validate_expiry_date(); - $this->validate_minimum_amount(); - $this->validate_maximum_amount(); - $this->validate_product_ids(); - $this->validate_product_categories(); - $this->validate_sale_items(); - $this->validate_excluded_items(); - $this->validate_cart_excluded_items(); - - if ( ! apply_filters( 'woocommerce_coupon_is_valid', true, $this ) ) { - throw new Exception( self::E_WC_COUPON_INVALID_FILTERED ); - } - } catch ( Exception $e ) { - $this->error_message = $this->get_coupon_error( $e->getMessage() ); + if ( is_wp_error( $valid ) ) { + $this->error_message = $valid->get_error_message(); return false; } - - return true; } /** From 51fbb1aec309acc388c47fe3fa51f5e9ba643749 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 13:02:39 +0100 Subject: [PATCH 12/21] set_items_from_cart --- includes/class-wc-cart-totals.php | 25 ++++-- includes/class-wc-cart.php | 30 ++++--- includes/class-wc-coupon.php | 2 + includes/class-wc-discount.php | 36 ++++---- includes/class-wc-discounts.php | 108 +++++++++++++++-------- tests/unit-tests/discounts/discounts.php | 74 +++++----------- 6 files changed, 155 insertions(+), 120 deletions(-) diff --git a/includes/class-wc-cart-totals.php b/includes/class-wc-cart-totals.php index a12fa3ffd45..f0933c69471 100644 --- a/includes/class-wc-cart-totals.php +++ b/includes/class-wc-cart-totals.php @@ -110,11 +110,10 @@ final class WC_Cart_Totals { * * @since 3.2.0 * @param object $cart Cart object to calculate totals for. - * @param object $customer Customer who owns this cart. */ - public function __construct( &$cart = null, &$customer = null ) { + public function __construct( &$cart = null ) { $this->object = $cart; - $this->calculate_tax = wc_tax_enabled() && ! $customer->get_is_vat_exempt(); + $this->calculate_tax = wc_tax_enabled() && ! $cart->get_customer()->get_is_vat_exempt(); if ( is_a( $cart, 'WC_Cart' ) ) { $this->calculate(); @@ -233,7 +232,7 @@ final class WC_Cart_Totals { $fee->total = wc_add_number_precision_deep( $fee->object->amount ); if ( $this->calculate_tax && $fee->object->taxable ) { - $fee->taxes = WC_Tax::calc_tax( $fee->total, WC_Tax::get_rates( $fee->object->tax_class, $this->customer ), false ); + $fee->taxes = WC_Tax::calc_tax( $fee->total, WC_Tax::get_rates( $fee->object->tax_class, $this->object->get_customer() ), false ); $fee->total_tax = array_sum( $fee->taxes ); if ( ! $this->round_at_subtotal() ) { @@ -321,7 +320,7 @@ final class WC_Cart_Totals { */ protected function get_item_tax_rates( $item ) { $tax_class = $item->product->get_tax_class(); - return isset( $this->item_tax_rates[ $tax_class ] ) ? $this->item_tax_rates[ $tax_class ] : $this->item_tax_rates[ $tax_class ] = WC_Tax::get_rates( $item->product->get_tax_class(), $this->customer ); + return isset( $this->item_tax_rates[ $tax_class ] ) ? $this->item_tax_rates[ $tax_class ] : $this->item_tax_rates[ $tax_class ] = WC_Tax::get_rates( $item->product->get_tax_class(), $this->object->get_customer() ); } /** @@ -492,10 +491,10 @@ final class WC_Cart_Totals { protected function calculate_discounts() { $this->set_coupons(); - $discounts = new WC_Discounts( $this->items ); + $discounts = new WC_Discounts( $this->object ); foreach ( $this->coupons as $coupon ) { - $discounts->apply_coupon( $coupon ); + $discounts->apply_discount( $coupon ); } $this->discount_totals = $discounts->get_discounts( true ); @@ -514,6 +513,18 @@ final class WC_Cart_Totals { $applied_coupons = $discounts->get_applied_coupons(); $this->object->coupon_discount_amounts = wp_list_pluck( $applied_coupons, 'discount' ); + + + + + + + + + + + + $this->object->coupon_discount_tax_amounts = wp_list_pluck( $applied_coupons, 'discount_tax' ); } diff --git a/includes/class-wc-cart.php b/includes/class-wc-cart.php index 3db24df3ed9..31bdcd1dd3a 100644 --- a/includes/class-wc-cart.php +++ b/includes/class-wc-cart.php @@ -1098,6 +1098,16 @@ class WC_Cart { return ( $first_item_subtotal < $second_item_subtotal ) ? 1 : -1; } + /** + * Get cart's owner. + * + * @since 3.2.0 + * @return WC_Customer + */ + public function get_customer() { + return WC()->customer; + } + /** * Calculate totals for the items in the cart. */ @@ -1396,7 +1406,7 @@ class WC_Cart { } // VAT exemption done at this point - so all totals are correct before exemption - if ( WC()->customer->get_is_vat_exempt() ) { + if ( $this->get_customer()->get_is_vat_exempt() ) { $this->remove_taxes(); } @@ -1412,7 +1422,7 @@ class WC_Cart { $this->tax_total = WC_Tax::get_tax_total( $this->taxes ); // VAT exemption done at this point - so all totals are correct before exemption - if ( WC()->customer->get_is_vat_exempt() ) { + if ( $this->get_customer()->get_is_vat_exempt() ) { $this->remove_taxes(); } } @@ -1533,12 +1543,12 @@ class WC_Cart { 'ID' => get_current_user_id(), ), 'destination' => array( - 'country' => WC()->customer->get_shipping_country(), - 'state' => WC()->customer->get_shipping_state(), - 'postcode' => WC()->customer->get_shipping_postcode(), - 'city' => WC()->customer->get_shipping_city(), - 'address' => WC()->customer->get_shipping_address(), - 'address_2' => WC()->customer->get_shipping_address_2(), + 'country' => $this->get_customer()->get_shipping_country(), + 'state' => $this->get_customer()->get_shipping_state(), + 'postcode' => $this->get_customer()->get_shipping_postcode(), + 'city' => $this->get_customer()->get_shipping_city(), + 'address' => $this->get_customer()->get_shipping_address(), + 'address_2' => $this->get_customer()->get_shipping_address_2(), ), 'cart_subtotal' => $this->get_displayed_subtotal(), ), @@ -1596,8 +1606,8 @@ class WC_Cart { } if ( 'yes' === get_option( 'woocommerce_shipping_cost_requires_address' ) ) { - if ( ! WC()->customer->has_calculated_shipping() ) { - if ( ! WC()->customer->get_shipping_country() || ( ! WC()->customer->get_shipping_state() && ! WC()->customer->get_shipping_postcode() ) ) { + if ( ! $this->get_customer()->has_calculated_shipping() ) { + if ( ! $this->get_customer()->get_shipping_country() || ( ! $this->get_customer()->get_shipping_state() && ! $this->get_customer()->get_shipping_postcode() ) ) { return false; } } diff --git a/includes/class-wc-coupon.php b/includes/class-wc-coupon.php index f1746d1d48b..0fda8c44e2e 100644 --- a/includes/class-wc-coupon.php +++ b/includes/class-wc-coupon.php @@ -753,6 +753,8 @@ class WC_Coupon extends WC_Legacy_Coupon { $this->error_message = $valid->get_error_message(); return false; } + + return $valid; } /** diff --git a/includes/class-wc-discount.php b/includes/class-wc-discount.php index af4b1c6e42e..3db04cd7712 100644 --- a/includes/class-wc-discount.php +++ b/includes/class-wc-discount.php @@ -4,11 +4,9 @@ if ( ! defined( 'ABSPATH' ) ) { } /** - * A single discount. + * A discount. * - * Represents a fixed or percent based discount at cart level. Extended by cart - * and order discounts since they share the same logic for things like tax - * calculation. + * Represents a fixed, percent or coupon based discount calculated by WC_Discounts class. * * @author Automattic * @package WooCommerce/Classes @@ -23,9 +21,11 @@ class WC_Discount extends WC_Data { * @var array */ protected $data = array( + 'coupon_code' => '', + 'discounts' => array(), // Array of discounts. Keys for item ids, values for the discount amount. 'amount' => 0, 'discount' => 0, - 'discount_type' => 'fixed_cart', + 'type' => 'fixed', ); /** @@ -37,6 +37,15 @@ class WC_Discount extends WC_Data { return ( $this->get_discount_type() === $type || ( is_array( $type ) && in_array( $this->get_discount_type(), $type ) ) ); } + /** + * Valid discount types. + * + * @return array + */ + protected function get_valid_discount_types() { + return array( 'fixed', 'percent', 'coupon' ); + } + /** * Prefix for action and filter hooks on data. * @@ -95,8 +104,8 @@ class WC_Discount extends WC_Data { * @param string $context * @return string */ - public function get_discount_type( $context = 'view' ) { - return $this->get_prop( 'discount_type', $context ); + public function get_type( $context = 'view' ) { + return $this->get_prop( 'type', $context ); } /** @@ -105,11 +114,11 @@ class WC_Discount extends WC_Data { * @param string $discount_type * @throws WC_Data_Exception */ - public function set_discount_type( $discount_type ) { - if ( ! in_array( $discount_type, array( 'percent', 'fixed_cart' ) ) ) { - $this->error( 'coupon_invalid_discount_type', __( 'Invalid discount type', 'woocommerce' ) ); + public function set_type( $discount_type ) { + if ( ! in_array( $discount_type, $this->get_valid_discount_types() ) ) { + $this->error( 'invalid_discount_type', __( 'Invalid discount type', 'woocommerce' ) ); } - $this->set_prop( 'discount_type', $discount_type ); + $this->set_prop( 'type', $discount_type ); } /** @@ -130,11 +139,6 @@ class WC_Discount extends WC_Data { return $this->get_prop( 'discount', $context ); } - /** - * Array of negative taxes. @todo should this be here? - */ - public function set_taxes() {} - /** * Calculates the amount of negative tax to apply for this discount, since * discounts are applied before tax. diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index eccf714061a..ee3fba3ca8e 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -27,7 +27,7 @@ class WC_Discounts { /** * An array of discounts which have been applied to items. * - * @var array + * @var WC_Discount[] */ protected $discounts = array(); @@ -48,10 +48,40 @@ class WC_Discounts { /** * Constructor. * - * @param array $items Items to discount. + * @param array $object Cart or order object. */ - public function __construct( $items = array() ) { - $this->set_items( $items ); + public function __construct( $object = array() ) { + if ( is_a( $object, 'WC_Cart' ) ) { + $this->set_items_from_cart( $object ); + } else { + // @todo accept order objects. + } + } + + /** + * Normalise cart/order items which will be discounted. + * + * @since 3.2.0 + * @param array $cart Cart object. + */ + public function set_items_from_cart( $cart ) { + $this->items = array(); + + foreach ( $cart->get_cart() as $key => $cart_item ) { + $item = new stdClass(); + $item->key = $key; + $item->object = $cart_item; + $item->product = $cart_item['data']; + $item->quantity = $cart_item['quantity']; + $item->price = wc_add_number_precision_deep( $item->product->get_price() ) * $item->quantity; + $item->tax_class = $item->product->get_tax_class(); + $item->tax_rates = WC_Tax::get_rates( $item->tax_class, $cart->get_customer() ); + $this->items[ $key ] = $item; + } + + uasort( $this->items, array( $this, 'sort_by_price' ) ); + + $this->discounts = array_merge( array_fill_keys( array_keys( $this->items ), 0 ), $this->discounts ); } /** @@ -84,7 +114,7 @@ class WC_Discounts { */ public function get_discounts( $in_cents = false ) { - $discounts = $in_cents ? $this->discounts : wc_remove_number_precision_deep ( $this->discounts ); + $discounts = $in_cents ? $this->discounts : wc_remove_number_precision_deep( $this->discounts ); $manual = array(); foreach ( $this->manual_discounts as $manual_discount ) { @@ -132,35 +162,45 @@ class WC_Discounts { } /** - * Set cart/order items which will be discounted. + * Apply a discount to all items. * - * @since 3.2.0 - * @param array $items List items. - */ - public function set_items( $items ) { - $this->items = array(); - $this->discounts = array(); - $this->applied_coupons = array(); - - if ( ! empty( $items ) && is_array( $items ) ) { - foreach ( $items as $key => $item ) { - $this->items[ $key ] = $item; - $this->items[ $key ]->key = $key; - $this->items[ $key ]->price = $item->subtotal; - } - $this->discounts = array_fill_keys( array_keys( $items ), 0 ); - } - - uasort( $this->items, array( $this, 'sort_by_price' ) ); - } - - /** - * Allows a discount to be applied to the items programmatically without a coupon. - * - * @param string $raw_discount Discount amount either fixed or percentage. - * @return int discounted amount in cents. + * @param string|object $raw_discount Accepts a string (fixed or percent discounts), WC_Discount object, or WC_Coupon object. + * @return bool|WP_Error True if applied or WP_Error instance in failure. */ public function apply_discount( $raw_discount ) { + if ( is_a( $raw_discount, 'WC_Coupon' ) ) { + return $this->apply_coupon( $raw_discount ); + } + + $discount = false; + + if ( is_a( $raw_discount, 'WC_Discount' ) ) { + $discount = $raw_discount; + } elseif ( strstr( $raw_discount, '%' ) ) { + $discount = new WC_Discount; + $discount->set_type( 'percent' ); + $discount->set_amount( trim( $raw_discount, '%' ) ); + } elseif ( 0 < absint( $raw_discount ) ) { + $discount = new WC_Discount; + $discount->set_type( 'fixed' ); + $discount->set_amount( absint( $raw_discount ) ); + } + + if ( ! $discount ) { + return new WP_Error( 'invalid_coupon', __( 'Invalid discount', 'woocommerce' ) ); + } + + + + + + + + + + + + // Get total item cost after any extra discounts. $total_to_discount = 0; @@ -214,11 +254,7 @@ class WC_Discounts { * @param WC_Coupon $coupon Coupon object being applied to the items. * @return bool|WP_Error True if applied or WP_Error instance in failure. */ - public function apply_coupon( $coupon ) { - if ( ! is_a( $coupon, 'WC_Coupon' ) ) { - return false; - } - + protected function apply_coupon( $coupon ) { $is_coupon_valid = $this->is_coupon_valid( $coupon ); if ( is_wp_error( $is_coupon_valid ) ) { diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index 95ffee1cdac..e8e4b2a7389 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -6,38 +6,10 @@ */ class WC_Tests_Discounts extends WC_Unit_Test_Case { - protected function get_items_for_discounts_class() { - $items = array(); - $precision = pow( 10, wc_get_price_decimals() ); - foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { - $item = (object) array( - 'key' => '', - 'quantity' => 0, - 'price' => 0, - 'product' => false, - 'price_includes_tax' => wc_prices_include_tax(), - 'subtotal' => 0, - 'subtotal_tax' => 0, - 'subtotal_taxes' => array(), - 'total' => 0, - 'total_tax' => 0, - 'taxes' => array(), - 'discounted_price' => 0, - ); - $item->object = $cart_item; - $item->quantity = $cart_item['quantity']; - $item->subtotal = $cart_item['data']->get_price() * $precision * $cart_item['quantity']; - $item->product = $cart_item['data']; - $item->tax_rates = WC_Tax::get_rates( $item->product->get_tax_class() ); - $items[ $cart_item_key ] = $item; - } - return $items; - } - /** * Test get and set items. */ - public function test_get_set_items() { + public function test_get_set_items_from_cart() { // Create dummy product - price will be 10 $product = WC_Helper_Product::create_simple_product(); @@ -52,22 +24,22 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { // Test setting items to the cart. $discounts = new WC_Discounts(); - $discounts->set_items( $this->get_items_for_discounts_class() ); + $discounts->set_items_from_cart( WC()->cart ); $this->assertEquals( 1, count( $discounts->get_items() ) ); // Test setting items to an order. $discounts = new WC_Discounts(); - $discounts->set_items( $this->get_items_for_discounts_class() ); + $discounts->set_items_from_cart( WC()->cart ); $this->assertEquals( 1, count( $discounts->get_items() ) ); // Empty array of items. $discounts = new WC_Discounts(); - $discounts->set_items( array() ); + $discounts->set_items_from_cart( array() ); $this->assertEquals( array(), $discounts->get_items() ); // Invalid items. $discounts = new WC_Discounts(); - $discounts->set_items( false ); + $discounts->set_items_from_cart( false ); $this->assertEquals( array(), $discounts->get_items() ); // Cleanup. @@ -83,14 +55,14 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $discounts = new WC_Discounts(); $product = WC_Helper_Product::create_simple_product(); WC()->cart->add_to_cart( $product->get_id(), 1 ); - $discounts->set_items( $this->get_items_for_discounts_class() ); + $discounts->set_items_from_cart( WC()->cart ); // Test applying multiple coupons and getting totals. $coupon = WC_Helper_Coupon::create_coupon( 'test' ); $coupon->set_amount( 50 ); $coupon->set_discount_type( 'percent' ); $coupon->save(); - $discounts->apply_coupon( $coupon ); + $discounts->apply_discount( $coupon ); $this->assertEquals( array( 'test' => array( 'discount' => 5, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); @@ -99,11 +71,11 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $coupon2->set_amount( 50 ); $coupon2->set_discount_type( 'percent' ); $coupon->save(); - $discounts->apply_coupon( $coupon2 ); + $discounts->apply_discount( $coupon2 ); $this->assertEquals( array( 'test' => array( 'discount' => 5, 'discount_tax' => 0 ), 'test2' => array( 'discount' => 2.50, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); - $discounts->apply_coupon( $coupon ); + $discounts->apply_discount( $coupon ); $this->assertEquals( array( 'test' => array( 'discount' => 6.25, 'discount_tax' => 0 ), 'test2' => array( 'discount' => 2.50, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); // Test different coupon types. @@ -112,14 +84,14 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $coupon->set_discount_type( 'fixed_product' ); $coupon->set_amount( 2 ); $coupon->save(); - $discounts->set_items( $this->get_items_for_discounts_class() ); - $discounts->apply_coupon( $coupon ); + $discounts->set_items_from_cart( WC()->cart ); + $discounts->apply_discount( $coupon ); $this->assertEquals( array( 'test' => array( 'discount' => 4, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); $coupon->set_discount_type( 'fixed_cart' ); $coupon->save(); - $discounts->set_items( $this->get_items_for_discounts_class() ); - $discounts->apply_coupon( $coupon ); + $discounts->set_items_from_cart( WC()->cart ); + $discounts->apply_discount( $coupon ); $this->assertEquals( array( 'test' => array( 'discount' => 2, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); // Cleanup. @@ -146,20 +118,20 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { // Apply a percent discount. $coupon->set_discount_type( 'percent' ); - $discounts->set_items( $this->get_items_for_discounts_class() ); - $discounts->apply_coupon( $coupon ); + $discounts->set_items_from_cart( WC()->cart ); + $discounts->apply_discount( $coupon ); $this->assertEquals( 9, $discounts->get_discounted_price( current( $discounts->get_items() ) ) ); // Apply a fixed cart coupon. $coupon->set_discount_type( 'fixed_cart' ); - $discounts->set_items( $this->get_items_for_discounts_class() ); - $discounts->apply_coupon( $coupon ); + $discounts->set_items_from_cart( WC()->cart ); + $discounts->apply_discount( $coupon ); $this->assertEquals( 0, $discounts->get_discounted_price( current( $discounts->get_items() ) ) ); // Apply a fixed product coupon. $coupon->set_discount_type( 'fixed_product' ); - $discounts->set_items( $this->get_items_for_discounts_class() ); - $discounts->apply_coupon( $coupon ); + $discounts->set_items_from_cart( WC()->cart ); + $discounts->apply_discount( $coupon ); $this->assertEquals( 0, $discounts->get_discounted_price( current( $discounts->get_items() ) ) ); // Cleanup. @@ -431,11 +403,11 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $products[] = $product; } - $discounts->set_items( $this->get_items_for_discounts_class() ); + $discounts->set_items_from_cart( WC()->cart ); foreach ( $test['coupons'] as $coupon_props ) { $coupon->set_props( $coupon_props ); - $discounts->apply_coupon( $coupon ); + $discounts->apply_discount( $coupon ); } $this->assertEquals( $test['expected_total_discount'], array_sum( $discounts->get_discounts() ), 'Test case ' . $test_index . ' failed (' . print_r( $test, true ) . ' - ' . print_r( $discounts->get_discounts(), true ) . ')' ); @@ -497,7 +469,7 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { WC()->cart->add_to_cart( $product2->get_id(), 1 ); $discounts = new WC_Discounts(); - $discounts->set_items( $this->get_items_for_discounts_class() ); + $discounts->set_items_from_cart( WC()->cart ); $discounts->apply_discount( '50%' ); $all_discounts = $discounts->get_discounts(); @@ -510,7 +482,7 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { // Test fixed discounts. $discounts = new WC_Discounts(); - $discounts->set_items( $this->get_items_for_discounts_class() ); + $discounts->set_items_from_cart( WC()->cart ); $discounts->apply_discount( '5' ); $all_discounts = $discounts->get_discounts(); From e23e55bb273f6d604f717ce58f9bf7779ddaf7aa Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 15:35:41 +0100 Subject: [PATCH 13/21] Methods for getting specific totals and discounts whilst keeping storage in a single array --- includes/class-wc-cart-totals.php | 58 ++-- includes/class-wc-discount.php | 117 ++------ includes/class-wc-discounts.php | 326 ++++++++++------------- tests/unit-tests/discounts/discounts.php | 53 ---- 4 files changed, 205 insertions(+), 349 deletions(-) diff --git a/includes/class-wc-cart-totals.php b/includes/class-wc-cart-totals.php index f0933c69471..38ba6e218ed 100644 --- a/includes/class-wc-cart-totals.php +++ b/includes/class-wc-cart-totals.php @@ -497,35 +497,47 @@ final class WC_Cart_Totals { $discounts->apply_discount( $coupon ); } - $this->discount_totals = $discounts->get_discounts( true ); - $this->totals['discounts_total'] = array_sum( $this->discount_totals ); + $this->discount_totals = $discounts->get_discounts_by_item( true ); + $this->totals['discounts_total'] = array_sum( $this->discount_totals ); + $this->object->coupon_discount_amounts = $discounts->get_discounts_by_coupon(); - // See how much tax was 'discounted'. + // See how much tax was 'discounted' per item and per coupon. if ( $this->calculate_tax ) { - foreach ( $this->discount_totals as $cart_item_key => $discount ) { - $item = $this->items[ $cart_item_key ]; - if ( $item->product->is_taxable() ) { - $taxes = WC_Tax::calc_tax( $discount, $item->tax_rates, false ); - $this->totals['discounts_tax_total'] += $this->round_at_subtotal() ? array_sum( $taxes ) : wc_round_tax_total( array_sum( $taxes ), 0 ); + $coupon_discount_tax_amounts = array(); + $item_taxes = 0; + + foreach ( $discounts->get_discounts( true ) as $coupon_code => $coupon_discounts ) { + $coupon_discount_tax_amounts[ $coupon_code ] = 0; + + foreach ( $coupon_discounts as $item_key => $item_discount ) { + $item = $this->items[ $item_key ]; + + if ( $item->product->is_taxable() ) { + $item_tax = array_sum( WC_Tax::calc_tax( $discount, $item->tax_rates, false ) ); + $item_taxes += $item_tax; + $coupon_discount_tax_amounts[ $coupon_code ] += $item_tax; + } } } + + $this->totals['discounts_tax_total'] = $item_taxes; + $this->object->coupon_discount_tax_amounts = $coupon_discount_tax_amounts; } + } - $applied_coupons = $discounts->get_applied_coupons(); - $this->object->coupon_discount_amounts = wp_list_pluck( $applied_coupons, 'discount' ); - - - - - - - - - - - - - $this->object->coupon_discount_tax_amounts = wp_list_pluck( $applied_coupons, 'discount_tax' ); + /** + * Return discounted tax amount for an item. + * + * @param object $item + * @param int $discount_amount + * @return int + */ + protected function get_item_discount_tax( $item, $discount_amount ) { + if ( $item->product->is_taxable() ) { + $taxes = WC_Tax::calc_tax( $discount_amount, $item->tax_rates, false ); + return array_sum( $taxes ); + } + return 0; } /** diff --git a/includes/class-wc-discount.php b/includes/class-wc-discount.php index 3db04cd7712..41b27d394b5 100644 --- a/includes/class-wc-discount.php +++ b/includes/class-wc-discount.php @@ -13,7 +13,7 @@ if ( ! defined( 'ABSPATH' ) ) { * @version 3.2.0 * @since 3.2.0 */ -class WC_Discount extends WC_Data { +class WC_Discount { /** * Data array, with defaults. @@ -21,135 +21,62 @@ class WC_Discount extends WC_Data { * @var array */ protected $data = array( - 'coupon_code' => '', - 'discounts' => array(), // Array of discounts. Keys for item ids, values for the discount amount. - 'amount' => 0, - 'discount' => 0, - 'type' => 'fixed', + 'amount' => 0, // Discount amount. + 'discount_type' => 'fixed', // Fixed, percent, or coupon. + 'discount_total' => 0, ); - /** - * Checks the coupon type. - * @param string $type Array or string of types - * @return bool - */ - public function is_type( $type ) { - return ( $this->get_discount_type() === $type || ( is_array( $type ) && in_array( $this->get_discount_type(), $type ) ) ); - } - - /** - * Valid discount types. - * - * @return array - */ - protected function get_valid_discount_types() { - return array( 'fixed', 'percent', 'coupon' ); - } - - /** - * Prefix for action and filter hooks on data. - * - * @return string - */ - protected function get_hook_prefix() { - return 'woocommerce_discount_get_'; - } - - /** - * Returns the ID of this dicount. - * - * @return string - */ - public function get_id() { - return $this->id; - } - - /** - * Discount ID. - * - * @param string $id - */ - public function set_id( $id ) { - $this->id = $id; - } - /** * Get discount amount. * - * @param string $context - * @return float + * @return int */ - public function get_amount( $context = 'view' ) { - return $this->get_prop( 'amount', $context ); + public function get_amount() { + return $this->data['amount']; } /** * Discount amount - either fixed or percentage. * - * @param string $raw_amount + * @param string $raw_amount Amount discount gives. */ public function set_amount( $raw_amount ) { - if ( strstr( $raw_amount, '%' ) ) { - $amount = absint( rtrim( $raw_amount, '%' ) ); - $this->set_prop( 'amount', $amount ); - $this->set_discount_type( 'percent' ); - } else { - $this->set_prop( 'amount', wc_format_decimal( $raw_amount ) ); - } + $this->data['amount'] = wc_format_decimal( $raw_amount ); } /** * Get discount type. * - * @param string $context * @return string */ - public function get_type( $context = 'view' ) { - return $this->get_prop( 'type', $context ); + public function get_discount_type() { + return $this->data['discount_type']; } /** * Set discount type. * - * @param string $discount_type - * @throws WC_Data_Exception + * @param string $discount_type Type of discount. */ - public function set_type( $discount_type ) { - if ( ! in_array( $discount_type, $this->get_valid_discount_types() ) ) { - $this->error( 'invalid_discount_type', __( 'Invalid discount type', 'woocommerce' ) ); - } - $this->set_prop( 'type', $discount_type ); + public function set_discount_type( $discount_type ) { + $this->data['discount_type'] = $discount_type; } /** - * Amount of discount this has given in total cents. - * - * @param int $total - */ - public function set_discount_total( $total ) { - $this->set_prop( 'discount', absint( $total ) ); - } - - /** - * Get amount of discount this has in cents. + * Get discount total. * * @return int */ - public function get_discount_total( $context = 'view' ) { - return $this->get_prop( 'discount', $context ); + public function get_discount_total() { + return $this->data['discount_total']; } /** - * Calculates the amount of negative tax to apply for this discount, since - * discounts are applied before tax. + * Discount total. * - * For percent discounts this is simply a percent of each cart item's tax. - * - * For fixed discounts, the taxes are calculated proportionally so the - * discount is fairly split between items. - * - * @todo Should this bere here? + * @param string $total Total discount applied. */ - public function calculate_negative_taxes() {} - + public function set_discount_total( $total ) { + $this->data['discount_total'] = wc_format_decimal( $total ); + } } diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index ee3fba3ca8e..c0317bfddc4 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -27,17 +27,10 @@ class WC_Discounts { /** * An array of discounts which have been applied to items. * - * @var WC_Discount[] + * @var array[] Code => Item Key => Value */ protected $discounts = array(); - /** - * An array of applied coupons codes and total discount. - * - * @var array - */ - protected $applied_coupons = array(); - /** * An array of applied WC_Discount objects. * @@ -65,7 +58,11 @@ class WC_Discounts { * @param array $cart Cart object. */ public function set_items_from_cart( $cart ) { - $this->items = array(); + $this->items = $this->discounts = $this->manual_discounts = array(); + + if ( ! is_a( $cart, 'WC_Cart' ) ) { + return; + } foreach ( $cart->get_cart() as $key => $cart_item ) { $item = new stdClass(); @@ -74,14 +71,10 @@ class WC_Discounts { $item->product = $cart_item['data']; $item->quantity = $cart_item['quantity']; $item->price = wc_add_number_precision_deep( $item->product->get_price() ) * $item->quantity; - $item->tax_class = $item->product->get_tax_class(); - $item->tax_rates = WC_Tax::get_rates( $item->tax_class, $cart->get_customer() ); $this->items[ $key ] = $item; } uasort( $this->items, array( $this, 'sort_by_price' ) ); - - $this->discounts = array_merge( array_fill_keys( array_keys( $this->items ), 0 ), $this->discounts ); } /** @@ -95,35 +88,69 @@ class WC_Discounts { } /** - * Get discount by key without precision. + * Get discount by key with or without precision. * * @since 3.2.0 * @param string $key name of discount row to return. + * @param bool $in_cents Should the totals be returned in cents, or without precision. * @return array */ - public function get_discount( $key ) { - return isset( $this->discounts[ $key ] ) ? wc_remove_number_precision_deep( $this->discounts[ $key ] ) : 0; + public function get_discount( $key, $in_cents = false ) { + $item_discount_totals = $this->get_discounts_by_item( $in_cents ); + return isset( $item_discount_totals[ $key ] ) ? ( $in_cents ? $item_discount_totals[ $key ] : wc_remove_number_precision( $item_discount_totals[ $key ] ) ) : 0; } /** - * Get all discount totals with precision. + * Get all discount totals. @todo manual - should they just be stored in same array? * * @since 3.2.0 * @param bool $in_cents Should the totals be returned in cents, or without precision. * @return array */ public function get_discounts( $in_cents = false ) { + $discounts = $this->discounts; - $discounts = $in_cents ? $this->discounts : wc_remove_number_precision_deep( $this->discounts ); - - $manual = array(); - foreach ( $this->manual_discounts as $manual_discount ) { - $manual[ $manual_discount->get_id() ] = $in_cents ? $manual_discount->get_discount_total() : wc_remove_number_precision_deep( $manual_discount->get_discount_total() ); + foreach ( $this->get_manual_discounts() as $manual_discount_key => $manual_discount ) { + $discounts[ $manual_discount_key ] = $manual_discount->get_discount_total(); } - return array_merge( $discounts, $manual ); + return $in_cents ? $discounts : wc_remove_number_precision_deep( $discounts ); } + /** + * Get all discount totals per item. + * + * @since 3.2.0 + * @param bool $in_cents Should the totals be returned in cents, or without precision. + * @return array + */ + public function get_discounts_by_item( $in_cents = false ) { + $discounts = $this->discounts; + $item_discount_totals = array_shift( $discounts ); + + foreach ( $this->discounts as $item_discounts ) { + foreach ( $item_discounts as $item_key => $item_discount ) { + $item_discount_totals[ $item_key ] += $item_discount; + } + } + + return $in_cents ? wc_remove_number_precision_deep( $item_discount_totals ) : $item_discount_totals; + } + + /** + * Get all discount totals per coupon. + * + * @since 3.2.0 + * @param bool $in_cents Should the totals be returned in cents, or without precision. + * @return array + */ + public function get_discounts_by_coupon( $in_cents = false ) { + $coupon_discount_totals = array_map( 'array_sum', $this->discounts ); + + return $in_cents ? wc_remove_number_precision_deep( $coupon_discount_totals ) : $coupon_discount_totals; + } + + // @todo. public function get_manual_discounts() { return $this->manual_discounts; } @@ -147,61 +174,16 @@ class WC_Discounts { * @return float */ public function get_discounted_price_in_cents( $item ) { - return $item->price - $this->discounts[ $item->key ]; + return $item->price - $this->get_discount( $item->key, true ); } /** - * Returns a list of applied coupons with name value pairs - name being - * the coupon code, and value being the total amount disounted. + * Get total remaining after discounts. * * @since 3.2.0 - * @return array + * @return int */ - public function get_applied_coupons() { - return wc_remove_number_precision_deep( $this->applied_coupons ); - } - - /** - * Apply a discount to all items. - * - * @param string|object $raw_discount Accepts a string (fixed or percent discounts), WC_Discount object, or WC_Coupon object. - * @return bool|WP_Error True if applied or WP_Error instance in failure. - */ - public function apply_discount( $raw_discount ) { - if ( is_a( $raw_discount, 'WC_Coupon' ) ) { - return $this->apply_coupon( $raw_discount ); - } - - $discount = false; - - if ( is_a( $raw_discount, 'WC_Discount' ) ) { - $discount = $raw_discount; - } elseif ( strstr( $raw_discount, '%' ) ) { - $discount = new WC_Discount; - $discount->set_type( 'percent' ); - $discount->set_amount( trim( $raw_discount, '%' ) ); - } elseif ( 0 < absint( $raw_discount ) ) { - $discount = new WC_Discount; - $discount->set_type( 'fixed' ); - $discount->set_amount( absint( $raw_discount ) ); - } - - if ( ! $discount ) { - return new WP_Error( 'invalid_coupon', __( 'Invalid discount', 'woocommerce' ) ); - } - - - - - - - - - - - - - // Get total item cost after any extra discounts. + protected function get_total_after_discounts() { $total_to_discount = 0; foreach ( $this->items as $item ) { @@ -212,20 +194,15 @@ class WC_Discounts { $total_to_discount = $total_to_discount - $value->get_discount_total(); } - if ( is_a( $raw_discount, 'WC_Discount' ) ) { - $discount = $raw_discount; - } else { - $discount = new WC_Discount; - $discount->set_amount( $raw_discount ); - } - - if ( 'percent' === $discount->get_discount_type() ) { - $discount_total = $discount->get_amount() * ( $total_to_discount / 100 ); - } else { - $discount_total = min( absint( wc_add_number_precision( $discount->get_amount() ) ), $total_to_discount ); - } - $discount->set_discount_total( $discount_total ); + return $total_to_discount; + } + /** + * Generate a unique ID for a discount. + * + * @return void + */ + protected function generate_discount_id( $discount ) { $discount_id = ''; $index = 1; while ( ! $discount_id ) { @@ -240,11 +217,45 @@ class WC_Discounts { $discount_id = ''; } } + return $discount_id; + } - $discount->set_id( $discount_id ); - $this->manual_discounts[ $discount_id ] = $discount; + /** + * Apply a discount to all items. + * + * @param string|object $raw_discount Accepts a string (fixed or percent discounts), or WC_Coupon object. + * @return bool|WP_Error True if applied or WP_Error instance in failure. + */ + public function apply_discount( $raw_discount ) { + if ( is_a( $raw_discount, 'WC_Coupon' ) ) { + return $this->apply_coupon( $raw_discount ); + } - return $discount->get_discount_total(); + $discount = new WC_Discount; + + if ( strstr( $raw_discount, '%' ) ) { + $discount->set_discount_type( 'percent' ); + $discount->set_amount( trim( $raw_discount, '%' ) ); + } elseif ( 0 < absint( $raw_discount ) ) { + $discount->set_discount_type( 'fixed' ); + $discount->set_amount( wc_add_number_precision( absint( $raw_discount ) ) ); + } + + if ( ! $discount->get_amount() ) { + return new WP_Error( 'invalid_coupon', __( 'Invalid discount', 'woocommerce' ) ); + } + + $total_to_discount = $this->get_total_after_discounts(); + + if ( 'percent' === $discount->get_discount_type() ) { + $discount->set_discount_total( $discount->get_amount() * ( $total_to_discount / 100 ) ); + } else { + $discount->set_discount_total( min( $discount->get_amount(), $total_to_discount ) ); + } + + $this->manual_discounts[ $this->generate_discount_id( $discount ) ] = $discount; + + return true; } /** @@ -261,11 +272,8 @@ class WC_Discounts { return $is_coupon_valid; } - if ( ! isset( $this->applied_coupons[ $coupon->get_code() ] ) ) { - $this->applied_coupons[ $coupon->get_code() ] = array( - 'discount' => 0, - 'discount_tax' => 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 ); @@ -274,33 +282,22 @@ class WC_Discounts { // Core discounts are handled here as of 3.2. switch ( $coupon->get_discount_type() ) { case 'percent' : - $this->apply_percentage_discount( $items_to_apply, $coupon->get_amount(), $coupon ); + $this->apply_coupon_percent( $coupon, $items_to_apply ); break; case 'fixed_product' : - $this->apply_fixed_product_discount( $items_to_apply, wc_add_number_precision( $coupon->get_amount() ), $coupon ); + $this->apply_coupon_fixed_product( $coupon, $items_to_apply ); break; case 'fixed_cart' : - $this->apply_fixed_cart_discount( $items_to_apply, wc_add_number_precision( $coupon->get_amount() ), $coupon ); + $this->apply_coupon_fixed_cart( $coupon, $items_to_apply ); break; default : - if ( has_action( 'woocommerce_discounts_apply_coupon_' . $coupon_type ) ) { - // Allow custom coupon types to control this in their class per item, unless the new action is used. - do_action( 'woocommerce_discounts_apply_coupon_' . $coupon_type, $coupon, $items_to_apply, $this ); - } else { - // Fallback to old coupon-logic. - foreach ( $items_to_apply as $item ) { - $discounted_price = $this->get_discounted_price_in_cents( $item ); - $price_to_discount = ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $item->price : $discounted_price; - $discount = min( $discounted_price, $coupon->get_discount_amount( $price_to_discount, $item->object ) ); - $discount_tax = $this->get_item_discount_tax( $item, $discount ); + foreach ( $items_to_apply as $item ) { + $discounted_price = $this->get_discounted_price_in_cents( $item ); + $price_to_discount = wc_remove_number_precision( ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $item->price : $discounted_price ); + $discount = min( $discounted_price, wc_add_number_precision( $coupon->get_discount_amount( $price_to_discount ), $item->object ) ); - // Store totals. - $this->discounts[ $item->key ] += $discount; - if ( $coupon ) { - $this->applied_coupons[ $coupon->get_code() ]['discount'] += $discount; - $this->applied_coupons[ $coupon->get_code() ]['discount_tax'] += $discount_tax; - } - } + // Store code and discount amount per item. + $this->discounts[ $coupon->get_code() ][ $item->key ] += $discount; } break; } @@ -381,12 +378,11 @@ class WC_Discounts { * Apply percent discount to items and return an array of discounts granted. * * @since 3.2.0 - * @param array $items_to_apply Array of items to apply the coupon to. + * @param WC_Coupon $coupon Coupon object. Passed through filters. * @param int $amount Amount of discount. - * @param WC_Coupon $coupon Coupon object if appliable. Passed through filters. * @return int Total discounted. */ - protected function apply_percentage_discount( $items_to_apply, $amount, $coupon = null ) { + protected function apply_coupon_percent( $coupon, $items_to_apply ) { $total_discount = 0; foreach ( $items_to_apply as $item ) { @@ -397,17 +393,12 @@ class WC_Discounts { $price_to_discount = ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $item->price: $discounted_price; // Run coupon calculations. - $discount = $amount * ( $price_to_discount / 100 ); - $discount = min( $discounted_price, apply_filters( 'woocommerce_coupon_get_discount_amount', $discount, $price_to_discount, $item->object, false, $coupon ) ); - $discount_tax = $this->get_item_discount_tax( $item, $discount ); + $discount = $coupon->get_amount() * ( $price_to_discount / 100 ); + $discount = min( $discounted_price, apply_filters( 'woocommerce_coupon_get_discount_amount', $discount, $price_to_discount, $item->object, false, $coupon ) ); + $total_discount += $discount; - // Store totals. - $total_discount += $discount; - $this->discounts[ $item->key ] += $discount; - if ( $coupon ) { - $this->applied_coupons[ $coupon->get_code() ]['discount'] += $discount; - $this->applied_coupons[ $coupon->get_code() ]['discount_tax'] += $discount_tax; - } + // Store code and discount amount per item. + $this->discounts[ $coupon->get_code() ][ $item->key ] += $discount; } return $total_discount; } @@ -416,13 +407,14 @@ class WC_Discounts { * Apply fixed product discount to items. * * @since 3.2.0 - * @param array $items_to_apply Array of items to apply the coupon to. - * @param int $amount Amount of discount. - * @param WC_Coupon $coupon Coupon object if appliable. Passed through filters. + * @param WC_Coupon $coupon Coupon object. Passed through filters. + * @param array $items_to_apply Array of items to apply the coupon to. + * @param int $amount Fixed discount amount to apply in cents. Leave blank to pull from coupon. * @return int Total discounted. */ - protected function apply_fixed_product_discount( $items_to_apply, $amount, $coupon = 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() ); foreach ( $items_to_apply as $item ) { // Find out how much price is available to discount for the item. @@ -432,17 +424,12 @@ class WC_Discounts { $price_to_discount = ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $item->price: $discounted_price; // Run coupon calculations. - $discount = $amount * $item->quantity; - $discount = min( $discounted_price, apply_filters( 'woocommerce_coupon_get_discount_amount', $discount, $price_to_discount, $item->object, false, $coupon ) ); - $discount_tax = $this->get_item_discount_tax( $item, $discount ); + $discount = $amount * $item->quantity; + $discount = min( $discounted_price, apply_filters( 'woocommerce_coupon_get_discount_amount', $discount, $price_to_discount, $item->object, false, $coupon ) ); + $total_discount += $discount; - // Store totals. - $total_discount += $discount; - $this->discounts[ $item->key ] += $discount; - if ( $coupon ) { - $this->applied_coupons[ $coupon->get_code() ]['discount'] += $discount; - $this->applied_coupons[ $coupon->get_code() ]['discount_tax'] += $discount_tax; - } + // Store code and discount amount per item. + $this->discounts[ $coupon->get_code() ][ $item->key ] += $discount; } return $total_discount; } @@ -451,33 +438,34 @@ class WC_Discounts { * Apply fixed cart discount to items. * * @since 3.2.0 - * @param array $items_to_apply Array of items to apply the coupon to. - * @param int $cart_discount Fixed discount amount to apply. - * @param WC_Coupon $coupon Coupon object if appliable. Passed through filters. + * @param WC_Coupon $coupon Coupon object. Passed through filters. + * @param array $items_to_apply Array of items to apply the coupon to. + * @param int $amount Fixed discount amount to apply in cents. Leave blank to pull from coupon. * @return int Total discounted. */ - protected function apply_fixed_cart_discount( $items_to_apply, $cart_discount, $coupon = 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' ) ); if ( ! $item_count = array_sum( wp_list_pluck( $items_to_apply, 'quantity' ) ) ) { return $total_discount; } - $per_item_discount = floor( $cart_discount / $item_count ); // round it down to the nearest cent. + $per_item_discount = floor( $amount / $item_count ); // round it down to the nearest cent. if ( $per_item_discount > 0 ) { - $total_discounted = $this->apply_fixed_product_discount( $items_to_apply, $per_item_discount, $coupon ); + $total_discounted = $this->apply_coupon_fixed_product( $coupon, $items_to_apply, $per_item_discount ); /** * If there is still discount remaining, repeat the process. */ - if ( $total_discounted > 0 && $total_discounted < $cart_discount ) { - $total_discounted = $total_discounted + $this->apply_fixed_cart_discount( $items_to_apply, $cart_discount - $total_discounted ); + if ( $total_discounted > 0 && $total_discounted < $amount ) { + $total_discounted = $total_discounted + $this->apply_coupon_fixed_cart( $coupon, $items_to_apply, $amount - $total_discounted ); } - } elseif ( $cart_discount > 0 ) { - $total_discounted = $this->apply_fixed_cart_discount_remainder( $items_to_apply, $cart_discount, $coupon ); + } elseif ( $amount > 0 ) { + $total_discounted = $this->apply_fixed_cart_discount_remainder( $coupon, $items_to_apply, $amount ); } return $total_discount; } @@ -487,12 +475,12 @@ class WC_Discounts { * until the amount is expired, discounting 1 cent at a time. * * @since 3.2.0 - * @param array $items_to_apply Array of items to apply the coupon to. - * @param int $cart_discount Fixed discount amount to apply. * @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 int $amount Fixed discount amount to apply. * @return int Total discounted. */ - protected function apply_fixed_cart_discount_remainder( $items_to_apply, $remaining_discount, $coupon = null ) { + protected function apply_coupon_fixed_cart_remainder( $coupon, $items_to_apply, $amount ) { $total_discount = 0; foreach ( $items_to_apply as $item ) { @@ -504,43 +492,25 @@ class WC_Discounts { $price_to_discount = ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $item->price: $discounted_price; // Run coupon calculations. - $discount = min( $discounted_price, 1 ); - $discount_tax = $this->get_item_discount_tax( $item, $discount ); + $discount = min( $discounted_price, 1 ); // Store totals. - $total_discount += $discount; - $this->discounts[ $item->key ] += $discount; - if ( $coupon ) { - $this->applied_coupons[ $coupon->get_code() ]['discount'] += $discount; - $this->applied_coupons[ $coupon->get_code() ]['discount_tax'] += $discount_tax; - } + $total_discount += $discount; - if ( $total_discount >= $remaining_discount ) { + // Store code and discount amount per item. + $this->discounts[ $coupon->get_code() ][ $item->key ] += $discount; + + if ( $total_discount >= $amount ) { break 2; } } - if ( $total_discount >= $remaining_discount ) { + if ( $total_discount >= $amount ) { break; } } return $total_discount; } - /** - * Return discounted tax amount for an item. - * - * @param object $item - * @param int $discount_amount - * @return int - */ - protected function get_item_discount_tax( $item, $discount_amount ) { - if ( $item->product->is_taxable() ) { - $taxes = WC_Tax::calc_tax( $discount_amount, $item->tax_rates, false ); - return array_sum( $taxes ); - } - return 0; - } - /* |-------------------------------------------------------------------------- | Validation & Error Handling diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index e8e4b2a7389..4ba0957989c 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -48,59 +48,6 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $order->delete( true ); } - /** - * test get_applied_coupons - */ - public function test_get_applied_coupons() { - $discounts = new WC_Discounts(); - $product = WC_Helper_Product::create_simple_product(); - WC()->cart->add_to_cart( $product->get_id(), 1 ); - $discounts->set_items_from_cart( WC()->cart ); - - // Test applying multiple coupons and getting totals. - $coupon = WC_Helper_Coupon::create_coupon( 'test' ); - $coupon->set_amount( 50 ); - $coupon->set_discount_type( 'percent' ); - $coupon->save(); - $discounts->apply_discount( $coupon ); - - $this->assertEquals( array( 'test' => array( 'discount' => 5, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); - - $coupon2 = WC_Helper_Coupon::create_coupon( 'test2' ); - $coupon2->set_code( 'test2' ); - $coupon2->set_amount( 50 ); - $coupon2->set_discount_type( 'percent' ); - $coupon->save(); - $discounts->apply_discount( $coupon2 ); - - $this->assertEquals( array( 'test' => array( 'discount' => 5, 'discount_tax' => 0 ), 'test2' => array( 'discount' => 2.50, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); - - $discounts->apply_discount( $coupon ); - $this->assertEquals( array( 'test' => array( 'discount' => 6.25, 'discount_tax' => 0 ), 'test2' => array( 'discount' => 2.50, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); - - // Test different coupon types. - WC()->cart->empty_cart(); - WC()->cart->add_to_cart( $product->get_id(), 2 ); - $coupon->set_discount_type( 'fixed_product' ); - $coupon->set_amount( 2 ); - $coupon->save(); - $discounts->set_items_from_cart( WC()->cart ); - $discounts->apply_discount( $coupon ); - $this->assertEquals( array( 'test' => array( 'discount' => 4, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); - - $coupon->set_discount_type( 'fixed_cart' ); - $coupon->save(); - $discounts->set_items_from_cart( WC()->cart ); - $discounts->apply_discount( $coupon ); - $this->assertEquals( array( 'test' => array( 'discount' => 2, 'discount_tax' => 0 ) ), $discounts->get_applied_coupons() ); - - // Cleanup. - WC()->cart->empty_cart(); - $product->delete( true ); - $coupon->delete( true ); - $coupon2->delete( true ); - } - /** * Test applying a coupon (make sure it changes prices). */ From 9170b61a1ce8a74da4a70baa199919bea0b7f282 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 16:17:57 +0100 Subject: [PATCH 14/21] fix in cents logic direction. --- includes/class-wc-discount.php | 2 +- includes/class-wc-discounts.php | 4 ++-- tests/unit-tests/discounts/discounts.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/class-wc-discount.php b/includes/class-wc-discount.php index 41b27d394b5..6e9d12591c7 100644 --- a/includes/class-wc-discount.php +++ b/includes/class-wc-discount.php @@ -22,7 +22,7 @@ class WC_Discount { */ protected $data = array( 'amount' => 0, // Discount amount. - 'discount_type' => 'fixed', // Fixed, percent, or coupon. + 'discount_type' => 'fixed', // Fixed, percent, or coupon. 'discount_total' => 0, ); diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index c0317bfddc4..da33d40fa1e 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -134,7 +134,7 @@ class WC_Discounts { } } - return $in_cents ? wc_remove_number_precision_deep( $item_discount_totals ) : $item_discount_totals; + return $in_cents ? $item_discount_totals : wc_remove_number_precision_deep( $item_discount_totals ); } /** @@ -147,7 +147,7 @@ class WC_Discounts { public function get_discounts_by_coupon( $in_cents = false ) { $coupon_discount_totals = array_map( 'array_sum', $this->discounts ); - return $in_cents ? wc_remove_number_precision_deep( $coupon_discount_totals ) : $coupon_discount_totals; + return $in_cents ? $coupon_discount_totals : wc_remove_number_precision_deep( $coupon_discount_totals ); } // @todo. diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index 4ba0957989c..d6d2a371eb9 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -420,7 +420,7 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $discounts->apply_discount( '50%' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( 10, $all_discounts['discount-50%'] ); + $this->assertEquals( 10, $all_discounts['discount-50%'], print_r( $all_discounts, true ) ); $discounts->apply_discount( '50%' ); $all_discounts = $discounts->get_discounts(); From c7cb46a524c9d9c7e9a5e29397090a2bf005f3ea Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 16:31:11 +0100 Subject: [PATCH 15/21] Fix array shift usage --- includes/class-wc-discounts.php | 2 +- tests/unit-tests/discounts/discounts.php | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index da33d40fa1e..99032283080 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -128,7 +128,7 @@ class WC_Discounts { $discounts = $this->discounts; $item_discount_totals = array_shift( $discounts ); - foreach ( $this->discounts as $item_discounts ) { + foreach ( $discounts as $item_discounts ) { foreach ( $item_discounts as $item_key => $item_discount ) { $item_discount_totals[ $item_key ] += $item_discount; } diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index d6d2a371eb9..36476c7bd74 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -67,19 +67,19 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $coupon->set_discount_type( 'percent' ); $discounts->set_items_from_cart( WC()->cart ); $discounts->apply_discount( $coupon ); - $this->assertEquals( 9, $discounts->get_discounted_price( current( $discounts->get_items() ) ) ); + $this->assertEquals( 9, $discounts->get_discounted_price( current( $discounts->get_items() ) ), print_r( $discounts->get_discounts(), true ) ); // Apply a fixed cart coupon. $coupon->set_discount_type( 'fixed_cart' ); $discounts->set_items_from_cart( WC()->cart ); $discounts->apply_discount( $coupon ); - $this->assertEquals( 0, $discounts->get_discounted_price( current( $discounts->get_items() ) ) ); + $this->assertEquals( 0, $discounts->get_discounted_price( current( $discounts->get_items() ) ), print_r( $discounts->get_discounts(), true ) ); // Apply a fixed product coupon. $coupon->set_discount_type( 'fixed_product' ); $discounts->set_items_from_cart( WC()->cart ); $discounts->apply_discount( $coupon ); - $this->assertEquals( 0, $discounts->get_discounted_price( current( $discounts->get_items() ) ) ); + $this->assertEquals( 0, $discounts->get_discounted_price( current( $discounts->get_items() ) ), print_r( $discounts->get_discounts(), true ) ); // Cleanup. WC()->cart->empty_cart(); @@ -412,6 +412,7 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $product2->save(); // Add product to the cart. + WC()->cart->empty_cart(); WC()->cart->add_to_cart( $product->get_id(), 1 ); WC()->cart->add_to_cart( $product2->get_id(), 1 ); From 14717d4ebb44aa6c370998be966dc97a93f497a6 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 16:33:02 +0100 Subject: [PATCH 16/21] fix call to apply_coupon_fixed_cart_remainder --- includes/class-wc-discounts.php | 2 +- tests/unit-tests/discounts/discounts.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index 99032283080..68676125f7c 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -465,7 +465,7 @@ class WC_Discounts { } } elseif ( $amount > 0 ) { - $total_discounted = $this->apply_fixed_cart_discount_remainder( $coupon, $items_to_apply, $amount ); + $total_discounted = $this->apply_coupon_fixed_cart_remainder( $coupon, $items_to_apply, $amount ); } return $total_discount; } diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index 36476c7bd74..e13d92630c2 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -357,7 +357,7 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $discounts->apply_discount( $coupon ); } - $this->assertEquals( $test['expected_total_discount'], array_sum( $discounts->get_discounts() ), 'Test case ' . $test_index . ' failed (' . print_r( $test, true ) . ' - ' . print_r( $discounts->get_discounts(), true ) . ')' ); + $this->assertEquals( $test['expected_total_discount'], array_sum( $discounts->get_discounts_by_item() ), 'Test case ' . $test_index . ' failed (' . print_r( $test, true ) . ' - ' . print_r( $discounts->get_discounts(), true ) . ')' ); // Clean. WC()->cart->empty_cart(); From 64e04c614acb9845f6ba00952da736e7b06d8ad6 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 16:43:51 +0100 Subject: [PATCH 17/21] fix variable in calculate_discounts --- includes/class-wc-cart-totals.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/class-wc-cart-totals.php b/includes/class-wc-cart-totals.php index 38ba6e218ed..847cb228d1a 100644 --- a/includes/class-wc-cart-totals.php +++ b/includes/class-wc-cart-totals.php @@ -513,7 +513,7 @@ final class WC_Cart_Totals { $item = $this->items[ $item_key ]; if ( $item->product->is_taxable() ) { - $item_tax = array_sum( WC_Tax::calc_tax( $discount, $item->tax_rates, false ) ); + $item_tax = array_sum( WC_Tax::calc_tax( $item_discount, $item->tax_rates, false ) ); $item_taxes += $item_tax; $coupon_discount_tax_amounts[ $coupon_code ] += $item_tax; } From e67ae147399b9bfc89eb98b87544362de60be6c8 Mon Sep 17 00:00:00 2001 From: claudiulodro Date: Fri, 28 Jul 2017 08:53:23 -0700 Subject: [PATCH 18/21] Tests are working again! --- tests/unit-tests/discounts/discounts.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/unit-tests/discounts/discounts.php b/tests/unit-tests/discounts/discounts.php index e13d92630c2..01bb91e14e2 100644 --- a/tests/unit-tests/discounts/discounts.php +++ b/tests/unit-tests/discounts/discounts.php @@ -357,7 +357,8 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $discounts->apply_discount( $coupon ); } - $this->assertEquals( $test['expected_total_discount'], array_sum( $discounts->get_discounts_by_item() ), 'Test case ' . $test_index . ' failed (' . print_r( $test, true ) . ' - ' . print_r( $discounts->get_discounts(), true ) . ')' ); + $all_discounts = $discounts->get_discounts(); + $this->assertEquals( $test['expected_total_discount'], array_sum( $all_discounts['test'] ), 'Test case ' . $test_index . ' failed (' . print_r( $test, true ) . ' - ' . print_r( $discounts->get_discounts(), true ) . ')' ); // Clean. WC()->cart->empty_cart(); @@ -434,18 +435,18 @@ class WC_Tests_Discounts extends WC_Unit_Test_Case { $discounts->apply_discount( '5' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( 5, $all_discounts['discount-5'] ); + $this->assertEquals( 5, $all_discounts['discount-500'] ); $discounts->apply_discount( '5' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( 5, $all_discounts['discount-5'], print_r( $all_discounts, true ) ); - $this->assertEquals( 5, $all_discounts['discount-5-2'], print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-500'], print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-500-2'], print_r( $all_discounts, true ) ); $discounts->apply_discount( '15' ); $all_discounts = $discounts->get_discounts(); - $this->assertEquals( 5, $all_discounts['discount-5'], print_r( $all_discounts, true ) ); - $this->assertEquals( 5, $all_discounts['discount-5-2'], print_r( $all_discounts, true ) ); - $this->assertEquals( 10, $all_discounts['discount-15'], print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-500'], print_r( $all_discounts, true ) ); + $this->assertEquals( 5, $all_discounts['discount-500-2'], print_r( $all_discounts, true ) ); + $this->assertEquals( 10, $all_discounts['discount-1500'], print_r( $all_discounts, true ) ); // Cleanup. WC()->cart->empty_cart(); From c16df62b540e2c1ac5b4a86c8a7678cddcc06183 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 17:43:05 +0100 Subject: [PATCH 19/21] Fix tests and bootstrap --- includes/class-wc-cart-totals.php | 5 ++--- tests/bootstrap.php | 14 ++++---------- .../framework/helpers/class-wc-helper-shipping.php | 2 +- tests/unit-tests/totals/totals.php | 11 ++++++++++- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/includes/class-wc-cart-totals.php b/includes/class-wc-cart-totals.php index 847cb228d1a..6bb186ed65c 100644 --- a/includes/class-wc-cart-totals.php +++ b/includes/class-wc-cart-totals.php @@ -112,10 +112,9 @@ final class WC_Cart_Totals { * @param object $cart Cart object to calculate totals for. */ public function __construct( &$cart = null ) { - $this->object = $cart; - $this->calculate_tax = wc_tax_enabled() && ! $cart->get_customer()->get_is_vat_exempt(); - if ( is_a( $cart, 'WC_Cart' ) ) { + $this->object = $cart; + $this->calculate_tax = wc_tax_enabled() && ! $cart->get_customer()->get_is_vat_exempt(); $this->calculate(); } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index a9c59730dc4..7973a117ed6 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -24,6 +24,7 @@ class WC_Unit_Tests_Bootstrap { * @since 2.2 */ public function __construct() { + ini_set( 'display_errors','on' ); error_reporting( E_ALL ); @@ -32,10 +33,6 @@ class WC_Unit_Tests_Bootstrap { $_SERVER['SERVER_NAME'] = 'localhost'; } - $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1'; - $_SERVER['SERVER_NAME'] = ''; - $PHP_SELF = $GLOBALS['PHP_SELF'] = $_SERVER['PHP_SELF'] = '/index.php'; - $this->tests_dir = dirname( __FILE__ ); $this->plugin_dir = dirname( $this->tests_dir ); $this->wp_tests_dir = getenv( 'WP_TESTS_DIR' ) ? getenv( 'WP_TESTS_DIR' ) : '/tmp/wordpress-tests-lib'; @@ -46,16 +43,12 @@ class WC_Unit_Tests_Bootstrap { // load WC tests_add_filter( 'muplugins_loaded', array( $this, 'load_wc' ) ); - echo 'Loading WordPress bootstrap...' . PHP_EOL; + // install WC + tests_add_filter( 'setup_theme', array( $this, 'install_wc' ) ); // load the WP testing environment require_once( $this->wp_tests_dir . '/includes/bootstrap.php' ); - // Activate + install - activate_plugin( 'woocommerce/woocommerce.php' ); - - $this->install_wc(); - // load WC testing framework $this->includes(); } @@ -75,6 +68,7 @@ class WC_Unit_Tests_Bootstrap { * @since 2.2 */ public function install_wc() { + // Clean existing install first. define( 'WP_UNINSTALL_PLUGIN', true ); define( 'WC_REMOVE_ALL_DATA', true ); diff --git a/tests/framework/helpers/class-wc-helper-shipping.php b/tests/framework/helpers/class-wc-helper-shipping.php index 510ad2d3786..d78aef4a715 100644 --- a/tests/framework/helpers/class-wc-helper-shipping.php +++ b/tests/framework/helpers/class-wc-helper-shipping.php @@ -25,7 +25,7 @@ class WC_Helper_Shipping { update_option( 'woocommerce_flat_rate_settings', $flat_rate_settings ); update_option( 'woocommerce_flat_rate', array() ); WC_Cache_Helper::get_transient_version( 'shipping', true ); - WC()->shipping->unregister_shipping_methods(); + WC()->shipping->load_shipping_methods(); } /** diff --git a/tests/unit-tests/totals/totals.php b/tests/unit-tests/totals/totals.php index b3b197807cf..fde95f81510 100644 --- a/tests/unit-tests/totals/totals.php +++ b/tests/unit-tests/totals/totals.php @@ -30,6 +30,10 @@ class WC_Tests_Totals extends WC_Unit_Test_Case { public function setUp() { $this->ids = array(); + if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) { + define( 'WOOCOMMERCE_CHECKOUT', 1 ); + } + $tax_rate = array( 'tax_rate_country' => '', 'tax_rate_state' => '', @@ -42,7 +46,10 @@ class WC_Tests_Totals extends WC_Unit_Test_Case { 'tax_rate_class' => '', ); $tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate ); + update_option( 'woocommerce_calc_taxes', 'yes' ); + update_option( 'woocommerce_default_customer_address', 'base' ); + update_option( 'woocommerce_tax_based_on', 'base' ); $product = WC_Helper_Product::create_simple_product(); $product2 = WC_Helper_Product::create_simple_product(); @@ -67,7 +74,7 @@ class WC_Tests_Totals extends WC_Unit_Test_Case { add_action( 'woocommerce_cart_calculate_fees', array( $this, 'add_cart_fees_callback' ) ); - $this->totals = new WC_Cart_Totals( WC()->cart, WC()->customer ); + $this->totals = new WC_Cart_Totals( WC()->cart ); } /** @@ -101,6 +108,8 @@ class WC_Tests_Totals extends WC_Unit_Test_Case { foreach ( $this->ids['tax_rate_ids'] as $tax_rate_id ) { WC_Tax::_delete_tax_rate( $tax_rate_id ); } + + $this->ids = array(); } /** From 0839f5716be336685748c0c945a41e5bdb7ce86a Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Fri, 28 Jul 2017 17:49:39 +0100 Subject: [PATCH 20/21] phpcs --- includes/class-wc-discounts.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/includes/class-wc-discounts.php b/includes/class-wc-discounts.php index 68676125f7c..14d7517c9d1 100644 --- a/includes/class-wc-discounts.php +++ b/includes/class-wc-discounts.php @@ -39,15 +39,13 @@ class WC_Discounts { protected $manual_discounts = array(); /** - * Constructor. + * Constructor. @todo accept order objects. * * @param array $object Cart or order object. */ public function __construct( $object = array() ) { if ( is_a( $object, 'WC_Cart' ) ) { $this->set_items_from_cart( $object ); - } else { - // @todo accept order objects. } } @@ -101,7 +99,7 @@ class WC_Discounts { } /** - * Get all discount totals. @todo manual - should they just be stored in same array? + * Get all discount totals. * * @since 3.2.0 * @param bool $in_cents Should the totals be returned in cents, or without precision. @@ -150,7 +148,12 @@ class WC_Discounts { return $in_cents ? $coupon_discount_totals : wc_remove_number_precision_deep( $coupon_discount_totals ); } - // @todo. + /** + * Get an array of manual discounts which have been applied. + * + * @since 3.2.0 + * @return WC_Discount[] + */ public function get_manual_discounts() { return $this->manual_discounts; } @@ -200,7 +203,8 @@ class WC_Discounts { /** * Generate a unique ID for a discount. * - * @return void + * @param WC_Discount $discount Discount object. + * @return string */ protected function generate_discount_id( $discount ) { $discount_id = ''; @@ -379,7 +383,7 @@ class WC_Discounts { * * @since 3.2.0 * @param WC_Coupon $coupon Coupon object. Passed through filters. - * @param int $amount Amount of discount. + * @param array $items_to_apply Array of items to apply the coupon to. * @return int Total discounted. */ protected function apply_coupon_percent( $coupon, $items_to_apply ) { @@ -463,7 +467,6 @@ class WC_Discounts { if ( $total_discounted > 0 && $total_discounted < $amount ) { $total_discounted = $total_discounted + $this->apply_coupon_fixed_cart( $coupon, $items_to_apply, $amount - $total_discounted ); } - } elseif ( $amount > 0 ) { $total_discounted = $this->apply_coupon_fixed_cart_remainder( $coupon, $items_to_apply, $amount ); } From a721ab064e79cfdcdb03e245fb05ba82e53040c3 Mon Sep 17 00:00:00 2001 From: claudiulodro Date: Fri, 28 Jul 2017 09:59:24 -0700 Subject: [PATCH 21/21] Update WC_Discount tests --- tests/unit-tests/discounts/discount.php | 33 ++++++------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/tests/unit-tests/discounts/discount.php b/tests/unit-tests/discounts/discount.php index 86543d0e854..b1a900cc7fa 100644 --- a/tests/unit-tests/discounts/discount.php +++ b/tests/unit-tests/discounts/discount.php @@ -6,15 +6,6 @@ */ class WC_Tests_Discount extends WC_Unit_Test_Case { - /** - * Test get and set ID. - */ - public function test_get_set_id() { - $discount = new WC_Discount; - $discount->set_id( 'discount-5' ); - $this->assertEquals( 'discount-5', $discount->get_id() ); - } - /** * Test get and set ID. */ @@ -22,11 +13,15 @@ class WC_Tests_Discount extends WC_Unit_Test_Case { $discount = new WC_Discount; $discount->set_amount( '10' ); $this->assertEquals( '10', $discount->get_amount() ); - $this->assertEquals( 'fixed_cart', $discount->get_discount_type() ); + } + public function test_get_set_type() { $discount = new WC_Discount; - $discount->set_amount( '10%' ); - $this->assertEquals( '10', $discount->get_amount() ); + + $discount->set_discount_type( 'fixed' ); + $this->assertEquals( 'fixed', $discount->get_discount_type() ); + + $discount->set_discount_type( 'percent' ); $this->assertEquals( 'percent', $discount->get_discount_type() ); } @@ -38,18 +33,4 @@ class WC_Tests_Discount extends WC_Unit_Test_Case { $discount->set_discount_total( 1000 ); $this->assertEquals( 1000, $discount->get_discount_total() ); } - - /** - * Test get and set taxes. - */ - public function test_get_set_taxes() { - - } - - /** - * Test calculate negative taxes. - */ - public function test_calculate_negative_taxes() { - - } }