Add a 'NumberUtil' class with a 'round' method.
There's a number of places in the WooCommerce codebase where the built-in function 'round' is executed passing a non-numeric value (not a number and not a string that can be parsed as a number), for example round(''). In PHP 7 this yields a value of 0, but in PHP 8 this throws an error. This commit adds a 'NumberUtil' class with a static 'round' method, this method checks if the passed value is numeric and if so it just executes the built-in function, otherwise it returns 0. And all the calls to 'round' in the codebase are replaced with 'NumberUtil::round'.
This commit is contained in:
parent
b1e81d02da
commit
52eed70f04
|
@ -10,6 +10,8 @@
|
|||
* @package WooCommerce\Classes
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
require_once WC_ABSPATH . 'includes/legacy/abstract-wc-legacy-order.php';
|
||||
|
@ -428,7 +430,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
} else {
|
||||
$total_discount = $this->get_discount_total() + $this->get_discount_tax();
|
||||
}
|
||||
return apply_filters( 'woocommerce_order_get_total_discount', round( $total_discount, WC_ROUNDING_PRECISION ), $this );
|
||||
return apply_filters( 'woocommerce_order_get_total_discount', NumberUtil::round( $total_discount, WC_ROUNDING_PRECISION ), $this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -437,7 +439,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
* @return float
|
||||
*/
|
||||
public function get_subtotal() {
|
||||
$subtotal = round( $this->get_cart_subtotal_for_order(), wc_get_price_decimals() );
|
||||
$subtotal = NumberUtil::round( $this->get_cart_subtotal_for_order(), wc_get_price_decimals() );
|
||||
return apply_filters( 'woocommerce_order_get_subtotal', (float) $subtotal, $this );
|
||||
}
|
||||
|
||||
|
@ -672,7 +674,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( round( $value, wc_get_price_decimals() ) ) );
|
||||
$this->set_prop( 'total_tax', wc_format_decimal( NumberUtil::round( $value, wc_get_price_decimals() ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1677,7 +1679,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
|
||||
// Sum shipping costs.
|
||||
foreach ( $this->get_shipping_methods() as $shipping ) {
|
||||
$shipping_total += round( $shipping->get_total(), wc_get_price_decimals() );
|
||||
$shipping_total += NumberUtil::round( $shipping->get_total(), wc_get_price_decimals() );
|
||||
}
|
||||
|
||||
$this->set_shipping_total( $shipping_total );
|
||||
|
@ -1687,7 +1689,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
$fee_total = $item->get_total();
|
||||
|
||||
if ( 0 > $fee_total ) {
|
||||
$max_discount = 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;
|
||||
|
||||
if ( $fee_total < $max_discount && 0 > $max_discount ) {
|
||||
$item->set_total( $max_discount );
|
||||
|
@ -1714,9 +1716,9 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
}
|
||||
}
|
||||
|
||||
$this->set_discount_total( 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_total( 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 + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() ) );
|
||||
|
||||
do_action( 'woocommerce_order_after_calculate_totals', $and_taxes, $this );
|
||||
|
||||
|
@ -1767,7 +1769,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
$subtotal = $item->get_subtotal();
|
||||
}
|
||||
|
||||
$subtotal = $round ? round( $subtotal, wc_get_price_decimals() ) : $subtotal;
|
||||
$subtotal = $round ? NumberUtil::round( $subtotal, wc_get_price_decimals() ) : $subtotal;
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_order_amount_line_subtotal', $subtotal, $this, $item, $inc_tax, $round );
|
||||
|
@ -1791,7 +1793,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
$total = floatval( $item->get_total() ) / $item->get_quantity();
|
||||
}
|
||||
|
||||
$total = $round ? round( $total, wc_get_price_decimals() ) : $total;
|
||||
$total = $round ? NumberUtil::round( $total, wc_get_price_decimals() ) : $total;
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_order_amount_item_total', $total, $this, $item, $inc_tax, $round );
|
||||
|
@ -1813,7 +1815,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
$total = $inc_tax ? $item->get_total() + $item->get_total_tax() : $item->get_total();
|
||||
|
||||
// Check if we need to round.
|
||||
$total = $round ? round( $total, wc_get_price_decimals() ) : $total;
|
||||
$total = $round ? NumberUtil::round( $total, wc_get_price_decimals() ) : $total;
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_order_amount_line_total', $total, $this, $item, $inc_tax, $round );
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
|
@ -956,7 +957,7 @@ class WC_Admin_Post_Types {
|
|||
$regular_price = $product->get_regular_price();
|
||||
if ( $is_percentage ) {
|
||||
$percent = $price / 100;
|
||||
$new_price = max( 0, $regular_price - ( round( $regular_price * $percent, wc_get_price_decimals() ) ) );
|
||||
$new_price = max( 0, $regular_price - ( NumberUtil::round( $regular_price * $percent, wc_get_price_decimals() ) ) );
|
||||
} else {
|
||||
$new_price = max( 0, $regular_price - $price );
|
||||
}
|
||||
|
@ -968,7 +969,7 @@ class WC_Admin_Post_Types {
|
|||
|
||||
if ( isset( $new_price ) && $new_price !== $old_price ) {
|
||||
$price_changed = true;
|
||||
$new_price = round( $new_price, wc_get_price_decimals() );
|
||||
$new_price = NumberUtil::round( $new_price, wc_get_price_decimals() );
|
||||
$product->{"set_{$price_type}_price"}( $new_price );
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
|
@ -2466,7 +2467,7 @@ class WC_AJAX {
|
|||
|
||||
if ( '%' === substr( $value, -1 ) ) {
|
||||
$percent = wc_format_decimal( substr( $value, 0, -1 ) );
|
||||
$field_value += round( ( $field_value / 100 ) * $percent, wc_get_price_decimals() ) * "{$operator}1";
|
||||
$field_value += NumberUtil::round( ( $field_value / 100 ) * $percent, wc_get_price_decimals() ) * "{$operator}1";
|
||||
} else {
|
||||
$field_value += $value * "{$operator}1";
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
* @version 3.2.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
@ -280,7 +282,7 @@ final class WC_Cart_Totals {
|
|||
|
||||
// Negative fees should not make the order total go negative.
|
||||
if ( 0 > $fee->total ) {
|
||||
$max_discount = round( $this->get_total( 'items_total', true ) + $fee_running_total + $this->get_total( 'shipping_total', true ) ) * -1;
|
||||
$max_discount = NumberUtil::round( $this->get_total( 'items_total', true ) + $fee_running_total + $this->get_total( 'shipping_total', true ) ) * -1;
|
||||
|
||||
if ( $fee->total < $max_discount ) {
|
||||
$fee->total = $max_discount;
|
||||
|
@ -429,7 +431,7 @@ final class WC_Cart_Totals {
|
|||
$taxes = WC_Tax::calc_tax( $item->price, $base_tax_rates, true );
|
||||
|
||||
// Now we have a new item price (excluding TAX).
|
||||
$item->price = round( $item->price - array_sum( $taxes ) );
|
||||
$item->price = NumberUtil::round( $item->price - array_sum( $taxes ) );
|
||||
$item->price_includes_tax = false;
|
||||
}
|
||||
return $item;
|
||||
|
@ -748,7 +750,7 @@ final class WC_Cart_Totals {
|
|||
|
||||
$items_subtotal = $this->get_rounded_items_total( $this->get_values_for_total( 'subtotal' ) );
|
||||
|
||||
$this->set_total( 'items_subtotal', round( $items_subtotal ) );
|
||||
$this->set_total( 'items_subtotal', NumberUtil::round( $items_subtotal ) );
|
||||
$this->set_total( 'items_subtotal_tax', wc_round_tax_total( array_sum( $merged_subtotal_taxes ), 0 ) );
|
||||
|
||||
$this->cart->set_subtotal( $this->get_total( 'items_subtotal' ) );
|
||||
|
@ -859,7 +861,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 ) + array_sum( $this->get_merged_taxes( true ) ), 0 ) );
|
||||
$this->set_total( 'total', NumberUtil::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.
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
require_once WC_ABSPATH . 'includes/legacy/class-wc-legacy-cart.php';
|
||||
|
@ -877,7 +879,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
|||
if ( isset( $shipping_taxes[ $key ] ) ) {
|
||||
$tax -= $shipping_taxes[ $key ];
|
||||
$tax = wc_round_tax_total( $tax );
|
||||
$tax += round( $shipping_taxes[ $key ], wc_get_price_decimals() );
|
||||
$tax += NumberUtil::round( $shipping_taxes[ $key ], wc_get_price_decimals() );
|
||||
unset( $shipping_taxes[ $key ] );
|
||||
}
|
||||
$tax_totals[ $code ]->amount += wc_round_tax_total( $tax );
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
* @version 3.0.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
require_once dirname( __FILE__ ) . '/legacy/class-wc-legacy-coupon.php';
|
||||
|
@ -446,7 +448,14 @@ class WC_Coupon extends WC_Legacy_Coupon {
|
|||
$discount = $single ? $discount : $discount * $cart_item_qty;
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_coupon_get_discount_amount', round( min( $discount, $discounting_amount ), wc_get_rounding_precision() ), $discounting_amount, $cart_item, $single, $this );
|
||||
return apply_filters(
|
||||
'woocommerce_coupon_get_discount_amount',
|
||||
NumberUtil::round( min( $discount, $discounting_amount ), wc_get_rounding_precision() ),
|
||||
$discounting_amount,
|
||||
$cart_item,
|
||||
$single,
|
||||
$this
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @since 3.2.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
|
@ -230,7 +232,7 @@ class WC_Discounts {
|
|||
* @return int
|
||||
*/
|
||||
public function get_discounted_price_in_cents( $item ) {
|
||||
return absint( round( $item->price - $this->get_discount( $item->key, true ) ) );
|
||||
return absint( NumberUtil::round( $item->price - $this->get_discount( $item->key, true ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -359,7 +361,7 @@ class WC_Discounts {
|
|||
$discounted_price = $this->get_discounted_price_in_cents( $item );
|
||||
|
||||
// Get the price we actually want to discount, based on settings.
|
||||
$price_to_discount = ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $discounted_price : round( $item->price );
|
||||
$price_to_discount = ( 'yes' === get_option( 'woocommerce_calc_discounts_sequentially', 'no' ) ) ? $discounted_price : NumberUtil::round( $item->price );
|
||||
|
||||
// See how many and what price to apply to.
|
||||
$apply_quantity = $limit_usage_qty && ( $limit_usage_qty - $applied_count ) < $item->quantity ? $limit_usage_qty - $applied_count : $item->quantity;
|
||||
|
@ -910,7 +912,7 @@ class WC_Discounts {
|
|||
|
||||
if ( $this->object->get_prices_include_tax() ) {
|
||||
// Add tax to tax-exclusive subtotal.
|
||||
$subtotal = $subtotal + wc_add_number_precision( round( $this->object->get_total_tax(), wc_get_price_decimals() ) );
|
||||
$subtotal = $subtotal + wc_add_number_precision( NumberUtil::round( $this->object->get_total_tax(), wc_get_price_decimals() ) );
|
||||
}
|
||||
|
||||
return $subtotal;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* @package WooCommerce\Classes
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
|
@ -98,7 +100,7 @@ class WC_Tax {
|
|||
* @return float
|
||||
*/
|
||||
public static function round( $in ) {
|
||||
return apply_filters( 'woocommerce_tax_round', round( $in, wc_get_rounding_precision() ), $in );
|
||||
return apply_filters( 'woocommerce_tax_round', NumberUtil::round( $in, wc_get_rounding_precision() ), $in );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
|
@ -346,7 +347,7 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
|||
// Webhook away!
|
||||
$response = wp_safe_remote_request( $this->get_delivery_url(), $http_args );
|
||||
|
||||
$duration = round( microtime( true ) - $start_time, 5 );
|
||||
$duration = NumberUtil::round( microtime( true ) - $start_time, 5 );
|
||||
|
||||
$this->log_delivery( $delivery_id, $http_args, $response, $duration );
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
|
@ -322,7 +323,7 @@ class WC_CLI_REST_Command {
|
|||
$i++;
|
||||
$bits = explode( ', ', $query[2] );
|
||||
$backtrace = implode( ', ', array_slice( $bits, 13 ) );
|
||||
$seconds = round( $query[1], 6 );
|
||||
$seconds = NumberUtil::round( $query[1], 6 );
|
||||
$slow_query_message .= <<<EOT
|
||||
{$i}:
|
||||
- {$seconds} seconds
|
||||
|
@ -334,7 +335,7 @@ EOT;
|
|||
} elseif ( 'wc' !== WP_CLI::get_config( 'debug' ) ) {
|
||||
$slow_query_message = '. Use --debug=wc to see all queries.';
|
||||
}
|
||||
$query_total_time = round( $query_total_time, 6 );
|
||||
$query_total_time = NumberUtil::round( $query_total_time, 6 );
|
||||
WP_CLI::debug( "wc command executed {$query_count} queries in {$query_total_time} seconds{$slow_query_message}", 'wc' );
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
|
@ -706,7 +707,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
$terms[] = 'outofstock';
|
||||
}
|
||||
|
||||
$rating = min( 5, round( $product->get_average_rating(), 0 ) );
|
||||
$rating = min( 5, NumberUtil::round( $product->get_average_rating(), 0 ) );
|
||||
|
||||
if ( $rating > 0 ) {
|
||||
$terms[] = 'rated-' . $rating;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* @package WooCommerce\Gateways
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
@ -557,7 +559,7 @@ class WC_Gateway_Paypal_Request {
|
|||
$precision = 0;
|
||||
}
|
||||
|
||||
return round( $price, $precision );
|
||||
return NumberUtil::round( $price, $precision );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @version 3.1.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
@ -158,7 +160,7 @@ abstract class WC_Product_Importer implements WC_Importer_Interface {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return absint( min( round( ( $this->file_position / $size ) * 100 ), 100 ) );
|
||||
return absint( min( NumberUtil::round( ( $this->file_position / $size ) * 100 ), 100 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* @package WooCommerce\Shipping
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
@ -159,7 +161,7 @@ class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
|
|||
$total = $total - WC()->cart->get_discount_total();
|
||||
}
|
||||
|
||||
$total = round( $total, wc_get_price_decimals() );
|
||||
$total = NumberUtil::round( $total, wc_get_price_decimals() );
|
||||
|
||||
if ( $total >= $this->min_amount ) {
|
||||
$has_met_min_amount = true;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
* @package WooCommerce\Shipping
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
@ -193,9 +195,9 @@ class WC_Shipping_Legacy_Free_Shipping extends WC_Shipping_Method {
|
|||
$total = WC()->cart->get_displayed_subtotal();
|
||||
|
||||
if ( WC()->cart->display_prices_including_tax() ) {
|
||||
$total = round( $total - ( WC()->cart->get_discount_total() + WC()->cart->get_discount_tax() ), wc_get_price_decimals() );
|
||||
$total = NumberUtil::round( $total - ( WC()->cart->get_discount_total() + WC()->cart->get_discount_tax() ), wc_get_price_decimals() );
|
||||
} else {
|
||||
$total = round( $total - WC()->cart->get_discount_total(), wc_get_price_decimals() );
|
||||
$total = NumberUtil::round( $total - WC()->cart->get_discount_total(), wc_get_price_decimals() );
|
||||
}
|
||||
|
||||
if ( $total >= $this->min_amount ) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
|
@ -129,7 +130,7 @@ class WC_Tracks_Client {
|
|||
* @return string A string representing a timestamp.
|
||||
*/
|
||||
public static function build_timestamp() {
|
||||
$ts = round( microtime( true ) * 1000 );
|
||||
$ts = NumberUtil::round( microtime( true ) * 1000 );
|
||||
|
||||
return number_format( $ts, 0, '', '' );
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @version 3.9.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
@ -56,7 +58,7 @@ trait WC_Item_Totals {
|
|||
*/
|
||||
public static function round_item_subtotal( $value ) {
|
||||
if ( ! self::round_at_subtotal() ) {
|
||||
$value = round( $value );
|
||||
$value = NumberUtil::round( $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
|
@ -961,13 +962,13 @@ function wc_get_image_size( $image_size ) {
|
|||
} elseif ( 'custom' === $cropping ) {
|
||||
$width = max( 1, get_option( 'woocommerce_thumbnail_cropping_custom_width', '4' ) );
|
||||
$height = max( 1, get_option( 'woocommerce_thumbnail_cropping_custom_height', '3' ) );
|
||||
$size['height'] = absint( round( ( $size['width'] / $width ) * $height ) );
|
||||
$size['height'] = absint( NumberUtil::round( ( $size['width'] / $width ) * $height ) );
|
||||
$size['crop'] = 1;
|
||||
} else {
|
||||
$cropping_split = explode( ':', $cropping );
|
||||
$width = max( 1, current( $cropping_split ) );
|
||||
$height = max( 1, end( $cropping_split ) );
|
||||
$size['height'] = absint( round( ( $size['width'] / $width ) * $height ) );
|
||||
$size['height'] = absint( NumberUtil::round( ( $size['width'] / $width ) * $height ) );
|
||||
$size['crop'] = 1;
|
||||
}
|
||||
}
|
||||
|
@ -1844,7 +1845,7 @@ function wc_get_rounding_precision() {
|
|||
function wc_add_number_precision( $value, $round = true ) {
|
||||
$cent_precision = pow( 10, wc_get_price_decimals() );
|
||||
$value = $value * $cent_precision;
|
||||
return $round ? round( $value, wc_get_rounding_precision() - wc_get_price_decimals() ) : $value;
|
||||
return $round ? NumberUtil::round( $value, wc_get_rounding_precision() - wc_get_price_decimals() ) : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2396,14 +2397,14 @@ function wc_decimal_to_fraction( $decimal ) {
|
|||
*/
|
||||
function wc_round_discount( $value, $precision ) {
|
||||
if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
|
||||
return round( $value, $precision, WC_DISCOUNT_ROUNDING_MODE ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
return NumberUtil::round( $value, $precision, WC_DISCOUNT_ROUNDING_MODE ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
}
|
||||
|
||||
if ( 2 === WC_DISCOUNT_ROUNDING_MODE ) {
|
||||
return wc_legacy_round_half_down( $value, $precision );
|
||||
}
|
||||
|
||||
return round( $value, $precision );
|
||||
return NumberUtil::round( $value, $precision );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
|
@ -228,11 +230,11 @@ function wc_round_tax_total( $value, $precision = null ) {
|
|||
$precision = is_null( $precision ) ? wc_get_price_decimals() : intval( $precision );
|
||||
|
||||
if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
|
||||
$rounded_tax = round( $value, $precision, wc_get_tax_rounding_mode() ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
$rounded_tax = NumberUtil::round( $value, $precision, wc_get_tax_rounding_mode() ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
} elseif ( 2 === wc_get_tax_rounding_mode() ) {
|
||||
$rounded_tax = wc_legacy_round_half_down( $value, $precision );
|
||||
} else {
|
||||
$rounded_tax = round( $value, $precision );
|
||||
$rounded_tax = NumberUtil::round( $value, $precision );
|
||||
}
|
||||
|
||||
return apply_filters( 'wc_round_tax_total', $rounded_tax, $value, $precision, WC_TAX_ROUNDING_MODE );
|
||||
|
@ -259,7 +261,7 @@ function wc_legacy_round_half_down( $value, $precision ) {
|
|||
$value = implode( '.', $value );
|
||||
}
|
||||
|
||||
return round( floatval( $value ), $precision );
|
||||
return NumberUtil::round( floatval( $value ), $precision );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -820,7 +822,7 @@ if ( ! function_exists( 'wc_hex_darker' ) ) {
|
|||
|
||||
foreach ( $base as $k => $v ) {
|
||||
$amount = $v / 100;
|
||||
$amount = round( $amount * $factor );
|
||||
$amount = NumberUtil::round( $amount * $factor );
|
||||
$new_decimal = $v - $amount;
|
||||
|
||||
$new_hex_component = dechex( $new_decimal );
|
||||
|
@ -851,7 +853,7 @@ if ( ! function_exists( 'wc_hex_lighter' ) ) {
|
|||
foreach ( $base as $k => $v ) {
|
||||
$amount = 255 - $v;
|
||||
$amount = $amount / 100;
|
||||
$amount = round( $amount * $factor );
|
||||
$amount = NumberUtil::round( $amount * $factor );
|
||||
$new_decimal = $v + $amount;
|
||||
|
||||
$new_hex_component = dechex( $new_decimal );
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
|
@ -982,7 +983,7 @@ function wc_get_price_including_tax( $product, $args = array() ) {
|
|||
$taxes_total = array_sum( array_map( 'wc_round_tax_total', $taxes ) );
|
||||
}
|
||||
|
||||
$return_price = round( $line_price + $taxes_total, wc_get_price_decimals() );
|
||||
$return_price = NumberUtil::round( $line_price + $taxes_total, wc_get_price_decimals() );
|
||||
} else {
|
||||
$tax_rates = WC_Tax::get_rates( $product->get_tax_class() );
|
||||
$base_tax_rates = WC_Tax::get_base_tax_rates( $product->get_tax_class( 'unfiltered' ) );
|
||||
|
@ -1000,7 +1001,7 @@ function wc_get_price_including_tax( $product, $args = array() ) {
|
|||
$remove_taxes_total = array_sum( array_map( 'wc_round_tax_total', $remove_taxes ) );
|
||||
}
|
||||
|
||||
$return_price = round( $line_price - $remove_taxes_total, wc_get_price_decimals() );
|
||||
$return_price = NumberUtil::round( $line_price - $remove_taxes_total, wc_get_price_decimals() );
|
||||
|
||||
/**
|
||||
* The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations.
|
||||
|
@ -1019,7 +1020,7 @@ function wc_get_price_including_tax( $product, $args = array() ) {
|
|||
$modded_taxes_total = array_sum( array_map( 'wc_round_tax_total', $modded_taxes ) );
|
||||
}
|
||||
|
||||
$return_price = round( $line_price - $base_taxes_total + $modded_taxes_total, wc_get_price_decimals() );
|
||||
$return_price = NumberUtil::round( $line_price - $base_taxes_total + $modded_taxes_total, wc_get_price_decimals() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
/**
|
||||
* A class of utilities for dealing with numbers.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Utilities;
|
||||
|
||||
/**
|
||||
* A class of utilities for dealing with numbers.
|
||||
*/
|
||||
final class NumberUtil {
|
||||
|
||||
/**
|
||||
* Round a number using the built-in `round` function if the value to round is numeric
|
||||
* (a number or a string that can be parsed as a number), or 0 otherwise.
|
||||
*
|
||||
* This is needed because in PHP 7 applying `round` to a non-numeric value returns 0,
|
||||
* but in PHP 8 it throws an error. Specifically, in WooCommerce we have a few places where
|
||||
* round('') is often executed.
|
||||
*
|
||||
* @param mixed $val The value to round.
|
||||
* @param int $precision The optional number of decimal digits to round to.
|
||||
* @param int $mode A constant to specify the mode in which rounding occurs.
|
||||
*
|
||||
* @return float The value rounded to the given precision as a float, or the supplied default value.
|
||||
*/
|
||||
public static function round( $val, int $precision = 0, int $mode = PHP_ROUND_HALF_UP ) : float {
|
||||
if ( is_numeric( $val ) ) {
|
||||
return round( $val, $precision, $mode );
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@
|
|||
* @package WooCommerce\Tests\Orders
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
/**
|
||||
* Order coupon tests.
|
||||
*/
|
||||
|
@ -194,7 +196,7 @@ class WC_Tests_Order_Coupons extends WC_Unit_Test_Case {
|
|||
* Coupon will therefore discount 200. Compare the total without tax so we can compare the ex tax price and avoid rounding mishaps.
|
||||
*/
|
||||
$order->apply_coupon( 'test-coupon-2' );
|
||||
$this->assertEquals( 401, round( $order->get_total_discount( false ), 2 ), $order->get_total_discount( false ) );
|
||||
$this->assertEquals( 401, NumberUtil::round( $order->get_total_discount( false ), 2 ), $order->get_total_discount( false ) );
|
||||
$this->assertEquals( 598.99, $order->get_total(), $order->get_total() );
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @since 3.4.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
/**
|
||||
* Class Tax.
|
||||
* @package WooCommerce\Tests\Tax
|
||||
|
@ -325,8 +327,8 @@ class WC_Tests_Tax extends WC_Unit_Test_Case {
|
|||
* Next tax would be calced on 100 - 7.8341 = 92.1659.
|
||||
* 92.1659 - ( 92.1659 / 1.05 ) = 4.38885.
|
||||
*/
|
||||
$this->assertEquals( round( $calced_tax[ $tax_rate_1_id ], 4 ), 4.3889 );
|
||||
$this->assertEquals( round( $calced_tax[ $tax_rate_2_id ], 4 ), 7.8341 );
|
||||
$this->assertEquals( NumberUtil::round( $calced_tax[ $tax_rate_1_id ], 4 ), 4.3889 );
|
||||
$this->assertEquals( NumberUtil::round( $calced_tax[ $tax_rate_2_id ], 4 ), 7.8341 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Tests\Utilities;
|
||||
|
||||
use Automattic\WooCommerce\Utilities\NumberUtil;
|
||||
|
||||
/**
|
||||
* A collection of tests for the string utility class.
|
||||
*/
|
||||
class NumberUtilTest extends \WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* @testdox `round` should work as the built-in function of the same name when passing a number.
|
||||
*/
|
||||
public function test_round_when_passing_a_number() {
|
||||
$actual = NumberUtil::round( 1234.5 );
|
||||
$expected = 1235;
|
||||
$this->assertEquals( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox `round` should work as the built-in function of the same name when passing a number and precision.
|
||||
*/
|
||||
public function test_round_when_passing_a_number_and_precision() {
|
||||
$actual = NumberUtil::round( 1234.5678, 2 );
|
||||
$expected = 1234.57;
|
||||
$this->assertEquals( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox `round` should work as the built-in function of the same name when passing a number and a mode flag.
|
||||
*/
|
||||
public function test_round_when_passing_a_number_and_mode_flag() {
|
||||
$actual = NumberUtil::round( 1234.5, 0, PHP_ROUND_HALF_DOWN );
|
||||
$expected = 1234;
|
||||
$this->assertEquals( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox `round` should work as the built-in function of the same name when passing a number-like string.
|
||||
*/
|
||||
public function test_round_when_passing_a_number_like_string() {
|
||||
$actual = NumberUtil::round( '1234.5678' );
|
||||
$expected = 1235;
|
||||
$this->assertEquals( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox `round` should work as the built-in function of the same name when passing a number-like string and precision.
|
||||
*/
|
||||
public function test_round_when_passing_a_number_like_string_and_precision() {
|
||||
$actual = NumberUtil::round( '1234.5678', 2 );
|
||||
$expected = 1234.57;
|
||||
$this->assertEquals( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox `round` should work as the built-in function of the same name when passing a number-like string and a mode flag.
|
||||
*/
|
||||
public function test_round_when_passing_a_number_like_string_and_mode_flag() {
|
||||
$actual = NumberUtil::round( '1234.5', 0, PHP_ROUND_HALF_DOWN );
|
||||
$expected = 1234;
|
||||
$this->assertEquals( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for the `round` tests for non-numeric values.
|
||||
*
|
||||
* @return array Values to test.
|
||||
*/
|
||||
public function data_provider_for_test_round_when_passing_a_non_number_like_string() {
|
||||
return array(
|
||||
array( null ),
|
||||
array( '' ),
|
||||
array( 'foobar' ),
|
||||
array( array() ),
|
||||
array( new \stdClass() ),
|
||||
array( true ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox `round` should return 0 when passing a non-numeric value.
|
||||
*
|
||||
* @dataProvider data_provider_for_test_round_when_passing_a_non_number_like_string
|
||||
*
|
||||
* @param mixed $value Value to test.
|
||||
*/
|
||||
public function test_round_when_passing_a_non_number_like_string( $value ) {
|
||||
$actual = NumberUtil::round( $value );
|
||||
$expected = 0;
|
||||
$this->assertEquals( $expected, $actual );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue