Refactor Order Class to use shared calculation logic.

We added a trait to move shared logic betweem Orders and Cart. This commit refactors Order class to use that shared logic.
Also adds a test for a failing case.
This commit is contained in:
vedanshujain 2019-10-15 00:23:16 +05:30
parent bee7ea4490
commit 60cd7b3651
5 changed files with 95 additions and 13 deletions

View File

@ -18,6 +18,7 @@ require_once WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-order.php';
* WC_Abstract_Order class.
*/
abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
use WC_Item_Totals;
/**
* Order Data array. This is the core order data exposed in APIs since 3.0.0.
@ -769,6 +770,23 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
return apply_filters( 'woocommerce_order_get_items', $items, $this, $types );
}
/**
* Return array of values for calculations.
*
* @param string $field Field name to return.
*
* @return array Array of values.
*/
protected function get_values_for_total( $field ) {
$items = array_map(
function ( $item ) use ( $field ) {
return wc_add_number_precision( $item[ $field ] );
},
array_values( $this->get_items() )
);
return $items;
}
/**
* Return an array of coupons within this order.
*
@ -1508,18 +1526,13 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
public function calculate_totals( $and_taxes = true ) {
do_action( 'woocommerce_order_before_calculate_totals', $and_taxes, $this );
$cart_subtotal = 0;
$cart_total = 0;
$fees_total = 0;
$shipping_total = 0;
$cart_subtotal_tax = 0;
$cart_total_tax = 0;
// Sum line item costs.
foreach ( $this->get_items() as $item ) {
$cart_subtotal += round( $item->get_subtotal(), wc_get_price_decimals() );
$cart_total += round( $item->get_total(), wc_get_price_decimals() );
}
$cart_subtotal = wc_remove_number_precision( $this->get_rounded_items_total( 'subtotal' ) );
$cart_total = wc_remove_number_precision( $this->get_rounded_items_total() );
// Sum shipping costs.
foreach ( $this->get_shipping_methods() as $shipping ) {

View File

@ -553,6 +553,16 @@ final class WC_Cart_Totals {
return $in_cents ? $this->totals : wc_remove_number_precision_deep( $this->totals );
}
/**
* Returns array of values for totals calculation.
*
* @param string $field Field name. Will probably be `total` or `subtotal`.
* @return array Items object
*/
protected function get_values_for_total( $field ) {
return array_values( wp_list_pluck( $this->items, $field ) );
}
/**
* Get taxes merged by type.
*

View File

@ -13,24 +13,28 @@ if ( ! defined( 'ABSPATH' ) ) {
/**
* Trait WC_Item_Totals.
*
* Right now this do not have much, but plan is to eventually move all shared calculation logic between Orders and Cart in this file.
*
* @since 3.9.0
*/
trait WC_Item_Totals {
/**
* Line items to calculate. Overwrite in child class.
* Line items to calculate. Define in child class.
*
* @since 3.9.0
* @var WC_Order_Item[]
* @param string $field Field name to calculate upon.
*
* @return array having `total`|`subtotal` property.
*/
protected $items = array();
abstract protected function get_values_for_total( $field );
/**
* Return rounded total based on settings. Will be used by Cart and Orders.
*
* @since 3.9.0
*
* @param string $field Field to round and sum based on setting. Will likely be `total` or `subtotal`.
* @param string $field Field to round and sum based on setting. Will likely be `total` or `subtotal`. Values must be without precision.
*
* @return float|int Appropriately rounded value.
*/
@ -38,7 +42,7 @@ trait WC_Item_Totals {
return array_sum(
array_map(
array( $this, 'round_item_subtotal' ),
array_values( wp_list_pluck( $this->items, $field ) )
$this->get_values_for_total( $field )
)
);
}

View File

@ -0,0 +1,55 @@
<?php
/**
* Class WC_Tests_Order file.
*
* @package WooCommerce|Tests|Order
*/
/**
* Class WC_Tests_Order.
*/
class WC_Tests_Order extends WC_Unit_Test_Case {
/**
* Test for total when round at subtotal is enabled.
*
* @link https://github.com/woocommerce/woocommerce/issues/24695
*/
public function test_order_calculate_total_rounding_24695() {
update_option( 'woocommerce_prices_include_tax', 'yes' );
update_option( 'woocommerce_calc_taxes', 'yes' );
update_option( 'woocommerce_tax_round_at_subtotal', 'yes' );
$tax_rate = array(
'tax_rate_country' => '',
'tax_rate_state' => '',
'tax_rate' => '7.0000',
'tax_rate_name' => 'CGST',
'tax_rate_priority' => '1',
'tax_rate_compound' => '0',
'tax_rate_shipping' => '0',
'tax_rate_order' => '1',
'tax_rate_class' => 'tax_1',
);
WC_Tax::_insert_tax_rate( $tax_rate );
$product1 = WC_Helper_Product::create_simple_product();
$product1->set_regular_price( 2 );
$product1->save();
$product2 = WC_Helper_Product::create_simple_product();
$product2->set_regular_price( 2.5 );
$product2->save();
$order = new WC_Order();
$order->add_product( $product1, 1 );
$order->add_product( $product2, 4 );
$order->save();
$order->calculate_totals( true );
$this->assertEquals( 12, $order->get_total() );
$this->assertEquals( 0.79, $order->get_total_tax() );
}
}

View File

@ -62,7 +62,7 @@ class WC_Tests_Order_Coupons extends WC_Unit_Test_Case {
array(
'product' => $product,
'quantity' => 1,
'subtotal' => 909.09, // Ex tax.
'subtotal' => 909.09, // Ex tax 10%.
'total' => 726.36,
)
);