Fix legacy order data PHP 8 compatibility issue (#41094)

* add a failing test for setting shipping total to empty string (fails on PHP 8.x)

* make the WC_Tests_Order_Item_Product::test_get_item_shipping_total test pass

* add changelog file

* add some more explicit conversions to float where we add values and can't be sure it's not a string

* appease the linter

* set array_reduce's initial value to 0.0
This commit is contained in:
Leif Singer 2023-10-31 00:07:44 +01:00 committed by GitHub
parent ae259024e9
commit 7e55cbd1d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 22 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
fix legacy order data PHP 8 compatibility issue

View File

@ -1375,7 +1375,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
// If the order originally had prices including tax, remove the discount + discount tax. // If the order originally had prices including tax, remove the discount + discount tax.
if ( $this->get_prices_include_tax() ) { if ( $this->get_prices_include_tax() ) {
$coupon_object->set_amount( $coupon_item->get_discount() + $coupon_item->get_discount_tax() ); $coupon_object->set_amount( (float) $coupon_item->get_discount() + (float) $coupon_item->get_discount_tax() );
} else { } else {
$coupon_object->set_amount( $coupon_item->get_discount() ); $coupon_object->set_amount( $coupon_item->get_discount() );
} }
@ -1620,7 +1620,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$shipping_total = 0; $shipping_total = 0;
foreach ( $this->get_shipping_methods() as $shipping ) { foreach ( $this->get_shipping_methods() as $shipping ) {
$shipping_total += $shipping->get_total(); $shipping_total += (float) $shipping->get_total();
} }
$this->set_shipping_total( $shipping_total ); $this->set_shipping_total( $shipping_total );
@ -1783,8 +1783,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
return array_reduce( return array_reduce(
$this->get_fees(), $this->get_fees(),
function( $carry, $item ) { function( $carry, $item ) {
return $carry + $item->get_total(); return $carry + (float) $item->get_total();
} },
0.0
); );
} }
@ -1815,7 +1816,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$tax_amount = wc_round_tax_total( $tax_amount ); $tax_amount = wc_round_tax_total( $tax_amount );
} }
$shipping_taxes[ $tax_rate_id ] = isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] + $tax_amount : $tax_amount; $shipping_taxes[ $tax_rate_id ] = isset( $shipping_taxes[ $tax_rate_id ] ) ? (float) $shipping_taxes[ $tax_rate_id ] + $tax_amount : $tax_amount;
} }
} }
@ -1893,7 +1894,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$cart_total_tax = 0; $cart_total_tax = 0;
$cart_subtotal = $this->get_cart_subtotal_for_order(); $cart_subtotal = $this->get_cart_subtotal_for_order();
$cart_total = $this->get_cart_total_for_order(); $cart_total = (float) $this->get_cart_total_for_order();
// Sum shipping costs. // Sum shipping costs.
foreach ( $this->get_shipping_methods() as $shipping ) { foreach ( $this->get_shipping_methods() as $shipping ) {
@ -1904,7 +1905,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
// Sum fee costs. // Sum fee costs.
foreach ( $this->get_fees() as $item ) { foreach ( $this->get_fees() as $item ) {
$fee_total = $item->get_total(); $fee_total = (float) $item->get_total();
if ( 0 > $fee_total ) { if ( 0 > $fee_total ) {
$max_discount = NumberUtil::round( $cart_total + $fees_total + $shipping_total, wc_get_price_decimals() ) * -1; $max_discount = NumberUtil::round( $cart_total + $fees_total + $shipping_total, wc_get_price_decimals() ) * -1;
@ -1913,7 +1914,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$item->set_total( $max_discount ); $item->set_total( $max_discount );
} }
} }
$fees_total += $item->get_total(); $fees_total += (float) $item->get_total();
} }
// Calculate taxes for items, shipping, discounts. Note; this also triggers save(). // Calculate taxes for items, shipping, discounts. Note; this also triggers save().
@ -1936,7 +1937,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
$this->set_discount_total( NumberUtil::round( $cart_subtotal - $cart_total, wc_get_price_decimals() ) ); $this->set_discount_total( NumberUtil::round( $cart_subtotal - $cart_total, wc_get_price_decimals() ) );
$this->set_discount_tax( wc_round_tax_total( $cart_subtotal_tax - $cart_total_tax ) ); $this->set_discount_tax( wc_round_tax_total( $cart_subtotal_tax - $cart_total_tax ) );
$this->set_total( NumberUtil::round( $cart_total + $fees_total + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() ) ); $this->set_total( NumberUtil::round( $cart_total + $fees_total + (float) $this->get_shipping_total() + (float) $this->get_cart_tax() + (float) $this->get_shipping_tax(), wc_get_price_decimals() ) );
do_action( 'woocommerce_order_after_calculate_totals', $and_taxes, $this ); do_action( 'woocommerce_order_after_calculate_totals', $and_taxes, $this );
@ -1958,9 +1959,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( is_callable( array( $item, 'get_subtotal' ) ) && $item->get_quantity() ) { if ( is_callable( array( $item, 'get_subtotal' ) ) && $item->get_quantity() ) {
if ( $inc_tax ) { if ( $inc_tax ) {
$subtotal = ( $item->get_subtotal() + $item->get_subtotal_tax() ) / $item->get_quantity(); $subtotal = ( (float) $item->get_subtotal() + (float) $item->get_subtotal_tax() ) / $item->get_quantity();
} else { } else {
$subtotal = floatval( $item->get_subtotal() ) / $item->get_quantity(); $subtotal = ( (float) $item->get_subtotal() ) / $item->get_quantity();
} }
$subtotal = $round ? NumberUtil::round( $subtotal, wc_get_price_decimals() ) : $subtotal; $subtotal = $round ? NumberUtil::round( $subtotal, wc_get_price_decimals() ) : $subtotal;
@ -1982,9 +1983,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( is_callable( array( $item, 'get_subtotal' ) ) ) { if ( is_callable( array( $item, 'get_subtotal' ) ) ) {
if ( $inc_tax ) { if ( $inc_tax ) {
$subtotal = $item->get_subtotal() + $item->get_subtotal_tax(); $subtotal = (float) $item->get_subtotal() + (float) $item->get_subtotal_tax();
} else { } else {
$subtotal = $item->get_subtotal(); $subtotal = (float) $item->get_subtotal();
} }
$subtotal = $round ? NumberUtil::round( $subtotal, wc_get_price_decimals() ) : $subtotal; $subtotal = $round ? NumberUtil::round( $subtotal, wc_get_price_decimals() ) : $subtotal;
@ -2006,9 +2007,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( is_callable( array( $item, 'get_total' ) ) && $item->get_quantity() ) { if ( is_callable( array( $item, 'get_total' ) ) && $item->get_quantity() ) {
if ( $inc_tax ) { if ( $inc_tax ) {
$total = ( $item->get_total() + $item->get_total_tax() ) / $item->get_quantity(); $total = ( (float) $item->get_total() + (float) $item->get_total_tax() ) / $item->get_quantity();
} else { } else {
$total = floatval( $item->get_total() ) / $item->get_quantity(); $total = ( (float) $item->get_total() ) / $item->get_quantity();
} }
$total = $round ? NumberUtil::round( $total, wc_get_price_decimals() ) : $total; $total = $round ? NumberUtil::round( $total, wc_get_price_decimals() ) : $total;
@ -2030,7 +2031,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( is_callable( array( $item, 'get_total' ) ) ) { if ( is_callable( array( $item, 'get_total' ) ) ) {
// Check if we need to add line tax to the line total. // Check if we need to add line tax to the line total.
$total = $inc_tax ? $item->get_total() + $item->get_total_tax() : $item->get_total(); $total = $inc_tax ? (float) $item->get_total() + (float) $item->get_total_tax() : (float) $item->get_total();
// Check if we need to round. // Check if we need to round.
$total = $round ? NumberUtil::round( $total, wc_get_price_decimals() ) : $total; $total = $round ? NumberUtil::round( $total, wc_get_price_decimals() ) : $total;
@ -2113,14 +2114,14 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
*/ */
public function get_subtotal_to_display( $compound = false, $tax_display = '' ) { public function get_subtotal_to_display( $compound = false, $tax_display = '' ) {
$tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' ); $tax_display = $tax_display ? $tax_display : get_option( 'woocommerce_tax_display_cart' );
$subtotal = $this->get_cart_subtotal_for_order(); $subtotal = (float) $this->get_cart_subtotal_for_order();
if ( ! $compound ) { if ( ! $compound ) {
if ( 'incl' === $tax_display ) { if ( 'incl' === $tax_display ) {
$subtotal_taxes = 0; $subtotal_taxes = 0;
foreach ( $this->get_items() as $item ) { foreach ( $this->get_items() as $item ) {
$subtotal_taxes += self::round_line_tax( $item->get_subtotal_tax(), false ); $subtotal_taxes += self::round_line_tax( (float) $item->get_subtotal_tax(), false );
} }
$subtotal += wc_round_tax_total( $subtotal_taxes ); $subtotal += wc_round_tax_total( $subtotal_taxes );
} }
@ -2136,18 +2137,18 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
} }
// Add Shipping Costs. // Add Shipping Costs.
$subtotal += $this->get_shipping_total(); $subtotal += (float) $this->get_shipping_total();
// Remove non-compound taxes. // Remove non-compound taxes.
foreach ( $this->get_taxes() as $tax ) { foreach ( $this->get_taxes() as $tax ) {
if ( $tax->is_compound() ) { if ( $tax->is_compound() ) {
continue; continue;
} }
$subtotal = $subtotal + $tax->get_tax_total() + $tax->get_shipping_tax_total(); $subtotal = $subtotal + (float) $tax->get_tax_total() + (float) $tax->get_shipping_tax_total();
} }
// Remove discounts. // Remove discounts.
$subtotal = $subtotal - $this->get_total_discount(); $subtotal = $subtotal - (float) $this->get_total_discount();
$subtotal = wc_price( $subtotal, array( 'currency' => $this->get_currency() ) ); $subtotal = wc_price( $subtotal, array( 'currency' => $this->get_currency() ) );
} }
@ -2276,7 +2277,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
} }
$total_rows[ 'fee_' . $fee->get_id() ] = array( $total_rows[ 'fee_' . $fee->get_id() ] = array(
'label' => $fee->get_name() . ':', 'label' => $fee->get_name() . ':',
'value' => wc_price( 'excl' === $tax_display ? $fee->get_total() : $fee->get_total() + $fee->get_total_tax(), array( 'currency' => $this->get_currency() ) ), 'value' => wc_price( 'excl' === $tax_display ? (float) $fee->get_total() : (float) $fee->get_total() + (float) $fee->get_total_tax(), array( 'currency' => $this->get_currency() ) ),
); );
} }
} }

View File

@ -43,6 +43,9 @@ class WC_Tests_Order_Item_Product extends WC_Unit_Test_Case {
$product_item->set_total( '10.00' ); $product_item->set_total( '10.00' );
$this->assertEquals( '10.00', $product_item->get_total() ); $this->assertEquals( '10.00', $product_item->get_total() );
$product_item->set_total( '' );
$this->assertEquals( '0.00', $product_item->get_total() );
$product_item->set_subtotal_tax( '0.50' ); $product_item->set_subtotal_tax( '0.50' );
$this->assertEquals( '0.50', $product_item->get_subtotal_tax() ); $this->assertEquals( '0.50', $product_item->get_subtotal_tax() );
@ -50,6 +53,26 @@ class WC_Tests_Order_Item_Product extends WC_Unit_Test_Case {
$this->assertEquals( '0.30', $product_item->get_total_tax() ); $this->assertEquals( '0.30', $product_item->get_total_tax() );
} }
/**
* Test get item shipping total
*/
public function test_get_item_shipping_total() {
$order = WC_Helper_Order::create_order_with_fees_and_shipping();
$order_id = $order->get_id();
array_values( $order->get_items( 'shipping' ) )[0]->set_total( '10.17' );
$order->save();
$order = wc_get_order( $order_id );
$this->assertEquals( '10.17', $order->get_line_total( array_values( $order->get_items( 'shipping' ) )[0], true ) );
array_values( $order->get_items( 'shipping' ) )[0]->set_total( '' );
$order->save();
$order = wc_get_order( $order_id );
$this->assertEquals( '0.00', $order->get_line_total( array_values( $order->get_items( 'shipping' ) )[0], true ) );
}
/** /**
* Test set_taxes and get_taxes for WC_Order_Item_Product. * Test set_taxes and get_taxes for WC_Order_Item_Product.
* *