Merge pull request #26850 from woocommerce/fix/26654
Make sure shipping tax are not rounded down when prices are inclusive of taxes.
This commit is contained in:
commit
dfe5493dd5
|
@ -462,7 +462,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
$tax_totals[ $code ]->is_compound = $tax->is_compound();
|
||||
$tax_totals[ $code ]->label = $tax->get_label();
|
||||
$tax_totals[ $code ]->amount += (float) $tax->get_tax_total() + (float) $tax->get_shipping_tax_total();
|
||||
$tax_totals[ $code ]->formatted_amount = wc_price( wc_round_tax_total( $tax_totals[ $code ]->amount ), array( 'currency' => $this->get_currency() ) );
|
||||
$tax_totals[ $code ]->formatted_amount = wc_price( $tax_totals[ $code ]->amount, array( 'currency' => $this->get_currency() ) );
|
||||
}
|
||||
|
||||
if ( apply_filters( 'woocommerce_order_hide_zero_taxes', true ) ) {
|
||||
|
@ -672,7 +672,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
*/
|
||||
protected function set_total_tax( $value ) {
|
||||
// We round here because this is a total entry, as opposed to line items in other setters.
|
||||
$this->set_prop( 'total_tax', wc_format_decimal( wc_round_tax_total( $value ) ) );
|
||||
$this->set_prop( 'total_tax', wc_format_decimal( round( $value, wc_get_price_decimals() ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*
|
||||
* @var object $item The item being displayed
|
||||
* @var int $item_id The id of the item being displayed
|
||||
*
|
||||
* @package WooCommerce/Admin/Views
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
@ -86,7 +88,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
<td class="line_tax" width="1%">
|
||||
<div class="view">
|
||||
<?php
|
||||
echo wp_kses_post( ( '' !== $tax_item_total ) ? wc_price( wc_round_tax_total( $tax_item_total ), array( 'currency' => $order->get_currency() ) ) : '–' );
|
||||
echo wp_kses_post( ( '' !== $tax_item_total ) ? wc_price( $tax_item_total, array( 'currency' => $order->get_currency() ) ) : '–' );
|
||||
$refunded = $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'shipping' );
|
||||
if ( $refunded ) {
|
||||
echo wp_kses_post( '<small class="refunded">-' . wc_price( $refunded, array( 'currency' => $order->get_currency() ) ) . '</small>' );
|
||||
|
|
|
@ -341,7 +341,8 @@ final class WC_Cart_Totals {
|
|||
$shipping_line->taxable = true;
|
||||
$shipping_line->total = wc_add_number_precision_deep( $shipping_object->cost );
|
||||
$shipping_line->taxes = wc_add_number_precision_deep( $shipping_object->taxes, false );
|
||||
$shipping_line->total_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $shipping_line->taxes ) );
|
||||
$shipping_line->taxes = array_map( array( $this, 'round_item_subtotal' ), $shipping_line->taxes );
|
||||
$shipping_line->total_tax = array_sum( $shipping_line->taxes );
|
||||
|
||||
$this->shipping[ $key ] = $shipping_line;
|
||||
}
|
||||
|
@ -858,7 +859,7 @@ final class WC_Cart_Totals {
|
|||
* @since 3.2.0
|
||||
*/
|
||||
protected function calculate_totals() {
|
||||
$this->set_total( 'total', round( $this->get_total( 'items_total', true ) + $this->get_total( 'fees_total', true ) + $this->get_total( 'shipping_total', true ) + wc_round_tax_total( array_sum( $this->get_merged_taxes( true ) ), 0 ), 0 ) );
|
||||
$this->set_total( 'total', round( $this->get_total( 'items_total', true ) + $this->get_total( 'fees_total', true ) + $this->get_total( 'shipping_total', true ) + array_sum( $this->get_merged_taxes( true ) ), 0 ) );
|
||||
$this->cart->set_total_tax( array_sum( $this->get_merged_taxes( false ) ) );
|
||||
|
||||
// Allow plugins to hook and alter totals before final total is calculated.
|
||||
|
|
|
@ -849,6 +849,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
|||
* @return array
|
||||
*/
|
||||
public function get_tax_totals() {
|
||||
$shipping_taxes = $this->get_shipping_taxes(); // Shipping taxes are rounded differently, so we will subtract from all taxes, then round and then add them back.
|
||||
$taxes = $this->get_taxes();
|
||||
$tax_totals = array();
|
||||
|
||||
|
@ -860,9 +861,17 @@ class WC_Cart extends WC_Legacy_Cart {
|
|||
$tax_totals[ $code ] = new stdClass();
|
||||
$tax_totals[ $code ]->amount = 0;
|
||||
}
|
||||
|
||||
$tax_totals[ $code ]->tax_rate_id = $key;
|
||||
$tax_totals[ $code ]->is_compound = WC_Tax::is_compound( $key );
|
||||
$tax_totals[ $code ]->label = WC_Tax::get_rate_label( $key );
|
||||
|
||||
if ( isset( $shipping_taxes[ $key ] ) ) {
|
||||
$tax -= $shipping_taxes[ $key ];
|
||||
$tax = wc_round_tax_total( $tax );
|
||||
$tax += round( $shipping_taxes[ $key ], wc_get_price_decimals() );
|
||||
unset( $shipping_taxes[ $key ] );
|
||||
}
|
||||
$tax_totals[ $code ]->amount += wc_round_tax_total( $tax );
|
||||
$tax_totals[ $code ]->formatted_amount = wc_price( $tax_totals[ $code ]->amount );
|
||||
}
|
||||
|
@ -1902,7 +1911,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
|||
if ( ! $compound && WC_Tax::is_compound( $key ) ) {
|
||||
continue;
|
||||
}
|
||||
$total += wc_round_tax_total( $tax );
|
||||
$total += $tax;
|
||||
}
|
||||
if ( $display ) {
|
||||
$total = wc_format_decimal( $total, wc_get_price_decimals() );
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
<?php
|
||||
/**
|
||||
* Helper class for shipping related unit tests.
|
||||
*
|
||||
* @package WooCommerce\Tests|Helper
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WC_Helper_Shipping.
|
||||
|
@ -11,15 +16,17 @@ class WC_Helper_Shipping {
|
|||
* Create a simple flat rate at the cost of 10.
|
||||
*
|
||||
* @since 2.3
|
||||
*
|
||||
* @param float $cost Optional. Cost of flat rate method.
|
||||
*/
|
||||
public static function create_simple_flat_rate() {
|
||||
public static function create_simple_flat_rate( $cost = 10 ) {
|
||||
$flat_rate_settings = array(
|
||||
'enabled' => 'yes',
|
||||
'title' => 'Flat rate',
|
||||
'availability' => 'all',
|
||||
'countries' => '',
|
||||
'tax_status' => 'taxable',
|
||||
'cost' => '10',
|
||||
'cost' => $cost,
|
||||
);
|
||||
|
||||
update_option( 'woocommerce_flat_rate_settings', $flat_rate_settings );
|
||||
|
@ -28,6 +35,48 @@ class WC_Helper_Shipping {
|
|||
WC()->shipping()->load_shipping_methods();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to set customer address so that shipping can be calculated.
|
||||
*/
|
||||
public static function force_customer_us_address() {
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( self::class, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( self::class, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( self::class, 'force_customer_us_postcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that can be hooked to a filter to force the customer's shipping state to be NY.
|
||||
*
|
||||
* @since 4.4.0
|
||||
* @param string $state State code.
|
||||
* @return string
|
||||
*/
|
||||
public static function force_customer_us_state( $state ) {
|
||||
return 'NY';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that can be hooked to a filter to force the customer's shipping country to be US.
|
||||
*
|
||||
* @since 4.4.0
|
||||
* @param string $country Country code.
|
||||
* @return string
|
||||
*/
|
||||
public static function force_customer_us_country( $country ) {
|
||||
return 'US';
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that can be hooked to a filter to force the customer's shipping postal code to be 12345.
|
||||
*
|
||||
* @since 4.4.0
|
||||
* @param string $postcode Postal code.
|
||||
* @return string
|
||||
*/
|
||||
public static function force_customer_us_postcode( $postcode ) {
|
||||
return '12345';
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the simple flat rate.
|
||||
*
|
||||
|
|
|
@ -62,10 +62,8 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
'cost' => '9.59',
|
||||
);
|
||||
update_option( 'woocommerce_flat_rate_settings', $flat_rate_settings );
|
||||
// Set an address so that shipping can be calculated.
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
|
||||
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
||||
WC()->cart->add_discount( $coupon->get_code() );
|
||||
|
@ -177,9 +175,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
update_option( 'woocommerce_tax_round_at_subtotal', 'yes' );
|
||||
|
||||
// Set an address so that shipping can be calculated.
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
|
||||
// Create tax classes first.
|
||||
WC_Tax::create_tax_class( '23percent' );
|
||||
|
@ -620,9 +616,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
WC()->cart->empty_cart();
|
||||
remove_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_country' ) );
|
||||
remove_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_gb_postcode' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
||||
|
||||
// Test out of store location with no coupon.
|
||||
|
@ -767,9 +761,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
WC()->cart->empty_cart();
|
||||
remove_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_gb_country' ) );
|
||||
remove_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_gb_postcode' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
||||
|
||||
// Test out of store location with no coupon.
|
||||
|
@ -872,9 +864,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
$full_coupon->set_amount( 100 );
|
||||
$full_coupon->save();
|
||||
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
||||
|
||||
// Test out of store location with no coupon.
|
||||
|
@ -941,7 +931,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
* @return string
|
||||
*/
|
||||
public function force_customer_us_country( $country ) {
|
||||
return 'US';
|
||||
return WC_Helper_Shipping::force_customer_us_country( $country );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -952,7 +942,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
* @return string
|
||||
*/
|
||||
public function force_customer_us_state( $state ) {
|
||||
return 'NY';
|
||||
return WC_Helper_Shipping::force_customer_us_state( $state );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -963,7 +953,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
* @return string
|
||||
*/
|
||||
public function force_customer_us_postcode( $postcode ) {
|
||||
return '12345';
|
||||
return WC_Helper_Shipping::force_customer_us_postcode( $postcode );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -989,9 +979,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
update_option( 'woocommerce_calc_taxes', 'yes' );
|
||||
|
||||
// Set an address so that shipping can be calculated.
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
|
||||
// 19% tax.
|
||||
$tax_rate = array(
|
||||
|
@ -1549,9 +1537,7 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
||||
|
||||
// Set an address so that shipping can be calculated.
|
||||
add_filter( 'woocommerce_customer_get_shipping_country', array( $this, 'force_customer_us_country' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_state', array( $this, 'force_customer_us_state' ) );
|
||||
add_filter( 'woocommerce_customer_get_shipping_postcode', array( $this, 'force_customer_us_postcode' ) );
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
|
||||
// Set the flat_rate shipping method.
|
||||
WC()->session->set( 'chosen_shipping_methods', array( 'flat_rate' ) );
|
||||
|
@ -1564,6 +1550,65 @@ class WC_Tests_Cart extends WC_Unit_Test_Case {
|
|||
$this->assertEquals( 20, WC()->cart->total );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that shipping tax rounding does not round down when price are inclusive of taxes.
|
||||
*/
|
||||
public function test_calculate_totals_shipping_tax_rounded_26654() {
|
||||
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' => '25.0000',
|
||||
'tax_rate_name' => 'Tax @ 25%',
|
||||
'tax_rate_priority' => '1',
|
||||
'tax_rate_compound' => '0',
|
||||
'tax_rate_shipping' => '1',
|
||||
'tax_rate_order' => '1',
|
||||
'tax_rate_class' => 'standard',
|
||||
);
|
||||
WC_Tax::_insert_tax_rate( $tax_rate );
|
||||
|
||||
$product = WC_Helper_Product::create_simple_product();
|
||||
$product->set_regular_price( 242 );
|
||||
$product->set_tax_class( 'product' );
|
||||
$product->save();
|
||||
|
||||
WC_Helper_Shipping::create_simple_flat_rate( 75.10 );
|
||||
WC_Helper_Shipping::force_customer_us_address();
|
||||
|
||||
WC()->cart->empty_cart();
|
||||
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
||||
WC()->session->set( 'chosen_shipping_methods', array( 'flat_rate' ) );
|
||||
WC()->cart->calculate_totals();
|
||||
|
||||
$this->assertEquals( 18.775, WC()->cart->get_shipping_tax() );
|
||||
$this->assertEquals( 335.88, WC()->cart->get_total( 'edit' ) );
|
||||
$this->assertEquals( 67.18, WC()->cart->get_taxes_total() );
|
||||
|
||||
$checkout = WC_Checkout::instance();
|
||||
$order = new WC_Order();
|
||||
$checkout->set_data_from_cart( $order );
|
||||
$this->assertEquals( 67.18, $order->get_total_tax() );
|
||||
$this->assertEquals( 335.88, $order->get_total() );
|
||||
$this->assertEquals( 18.775, $order->get_shipping_tax() );
|
||||
|
||||
update_option( 'woocommerce_tax_round_at_subtotal', 'no' );
|
||||
WC()->cart->calculate_totals();
|
||||
|
||||
$this->assertEquals( 18.78, WC()->cart->get_shipping_tax() );
|
||||
$this->assertEquals( 335.88, WC()->cart->get_total( 'edit' ) );
|
||||
$this->assertEquals( 67.18, WC()->cart->get_taxes_total() );
|
||||
|
||||
$order = new WC_Order();
|
||||
$checkout->set_data_from_cart( $order );
|
||||
$this->assertEquals( 67.18, $order->get_total_tax() );
|
||||
$this->assertEquals( 335.88, $order->get_total() );
|
||||
$this->assertEquals( 18.78, $order->get_shipping_tax() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test cart fee.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue