Store fee amount and prevent totals going negative
This commit is contained in:
parent
372723dae1
commit
804feb9333
|
@ -1324,11 +1324,6 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
$cart_total += $item->get_total();
|
||||
}
|
||||
|
||||
// Sum fee costs.
|
||||
foreach ( $this->get_fees() as $item ) {
|
||||
$fee_total += $item->get_total();
|
||||
}
|
||||
|
||||
// Sum shipping costs.
|
||||
foreach ( $this->get_shipping_methods() as $shipping ) {
|
||||
$shipping_total += $shipping->get_total();
|
||||
|
@ -1336,6 +1331,21 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
|||
|
||||
$this->set_shipping_total( $shipping_total );
|
||||
|
||||
// Sum fee costs.
|
||||
foreach ( $this->get_fees() as $item ) {
|
||||
$amount = $item->get_amount();
|
||||
|
||||
if ( 0 > $amount ) {
|
||||
$max_discount = round( $cart_total + $fee_total + $shipping_total, wc_get_price_decimals() ) * -1;
|
||||
|
||||
if ( $item->get_total() < $max_discount ) {
|
||||
$item->set_total( $max_discount );
|
||||
}
|
||||
}
|
||||
|
||||
$fee_total += $item->get_total();
|
||||
}
|
||||
|
||||
// Calculate taxes for items, shipping, discounts.
|
||||
if ( $and_taxes ) {
|
||||
$this->calculate_taxes();
|
||||
|
|
|
@ -228,6 +228,10 @@ function wc_save_order_items( $order_id, $items ) {
|
|||
),
|
||||
) );
|
||||
|
||||
if ( 'fee' === $item->get_type() ) {
|
||||
$item->set_amount( $item_data['line_total'] );
|
||||
}
|
||||
|
||||
if ( isset( $items['meta_key'][ $item_id ], $items['meta_value'][ $item_id ] ) ) {
|
||||
foreach ( $items['meta_key'][ $item_id ] as $meta_id => $meta_key ) {
|
||||
$meta_value = isset( $items['meta_value'][ $item_id ][ $meta_id ] ) ? wp_unslash( $items['meta_value'][ $item_id ][ $meta_id ] ) : '';
|
||||
|
|
|
@ -827,6 +827,7 @@ class WC_AJAX {
|
|||
}
|
||||
|
||||
$fee = new WC_Order_Item_Fee();
|
||||
$fee->set_amount( $amount );
|
||||
$fee->set_total( $amount );
|
||||
$fee->set_name( sprintf( __( '%s fee', 'woocommerce' ), $formatted_amount ) );
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ final class WC_Cart_Fees {
|
|||
'tax_class' => '',
|
||||
'taxable' => false,
|
||||
'amount' => 0,
|
||||
'total' => 0,
|
||||
);
|
||||
|
||||
/**
|
||||
|
|
|
@ -268,6 +268,8 @@ final class WC_Cart_Totals {
|
|||
$this->fees = array();
|
||||
$this->cart->calculate_fees();
|
||||
|
||||
$fee_running_total = 0;
|
||||
|
||||
foreach ( $this->cart->get_fees() as $fee_key => $fee_object ) {
|
||||
$fee = $this->get_default_fee_props();
|
||||
$fee->object = $fee_object;
|
||||
|
@ -275,6 +277,17 @@ final class WC_Cart_Totals {
|
|||
$fee->taxable = $fee->object->taxable;
|
||||
$fee->total = wc_add_number_precision_deep( $fee->object->amount );
|
||||
|
||||
// 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;
|
||||
|
||||
if ( $fee->total < $max_discount ) {
|
||||
$fee->total = $max_discount;
|
||||
}
|
||||
}
|
||||
|
||||
$fee_running_total += $fee->total;
|
||||
|
||||
if ( $this->calculate_tax ) {
|
||||
if ( 0 > $fee->total ) {
|
||||
// Negative fees should have the taxes split between all items so it works as a true discount.
|
||||
|
@ -304,8 +317,9 @@ final class WC_Cart_Totals {
|
|||
}
|
||||
|
||||
// Set totals within object.
|
||||
$fee->object->tax_data = wc_remove_number_precision_deep( $fee->taxes );
|
||||
$fee->object->tax = wc_remove_number_precision_deep( $fee->total_tax );
|
||||
$fee->object->total = wc_remove_number_precision_deep( $fee->total );
|
||||
$fee->object->tax_data = wc_remove_number_precision_deep( $fee->taxes );
|
||||
$fee->object->tax = wc_remove_number_precision_deep( $fee->total_tax );
|
||||
|
||||
$this->fees[ $fee_key ] = $fee;
|
||||
}
|
||||
|
@ -691,6 +705,9 @@ final class WC_Cart_Totals {
|
|||
$this->coupon_discount_totals = (array) $discounts->get_discounts_by_item( true );
|
||||
$this->coupon_discount_tax_totals = $coupon_discount_tax_amounts;
|
||||
|
||||
$this->set_total( 'discounts_total', array_sum( $this->coupon_discount_totals ) );
|
||||
$this->set_total( 'discounts_tax_total', array_sum( $this->coupon_discount_tax_totals ) );
|
||||
|
||||
$this->cart->set_coupon_discount_totals( wc_remove_number_precision_deep( $coupon_discount_amounts ) );
|
||||
$this->cart->set_coupon_discount_tax_totals( wc_remove_number_precision_deep( $coupon_discount_tax_amounts ) );
|
||||
}
|
||||
|
@ -735,8 +752,6 @@ final class WC_Cart_Totals {
|
|||
* @since 3.2.0
|
||||
*/
|
||||
protected function calculate_totals() {
|
||||
$this->set_total( 'discounts_total', array_sum( $this->coupon_discount_totals ) );
|
||||
$this->set_total( 'discounts_tax_total', array_sum( $this->coupon_discount_tax_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 ) ) ) );
|
||||
|
||||
// Add totals to cart object.
|
||||
|
|
|
@ -1701,6 +1701,8 @@ class WC_Cart extends WC_Legacy_Cart {
|
|||
*/
|
||||
public function calculate_fees() {
|
||||
do_action( 'woocommerce_cart_calculate_fees', $this );
|
||||
|
||||
$this->add_fee( 'Test', -100 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -401,8 +401,9 @@ class WC_Checkout {
|
|||
$item->legacy_fee_key = $fee_key; // @deprecated For legacy actions.
|
||||
$item->set_props( array(
|
||||
'name' => $fee->name,
|
||||
'tax_class' => $fee->taxable ? $fee->tax_class : 0,
|
||||
'total' => $fee->amount,
|
||||
'tax_class' => $fee->taxable ? $fee->tax_class: 0,
|
||||
'amount' => $fee->amount,
|
||||
'total' => $fee->total,
|
||||
'total_tax' => $fee->tax,
|
||||
'taxes' => array(
|
||||
'total' => $fee->tax_data,
|
||||
|
|
|
@ -18,12 +18,14 @@ class WC_Order_Item_Fee extends WC_Order_Item {
|
|||
|
||||
/**
|
||||
* Order Data array. This is the core order data exposed in APIs since 3.0.0.
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @var array
|
||||
*/
|
||||
protected $extra_data = array(
|
||||
'tax_class' => '',
|
||||
'tax_status' => 'taxable',
|
||||
'amount' => '',
|
||||
'total' => '',
|
||||
'total_tax' => '',
|
||||
'taxes' => array(
|
||||
|
@ -39,8 +41,9 @@ class WC_Order_Item_Fee extends WC_Order_Item {
|
|||
* @return array
|
||||
*/
|
||||
protected function get_tax_class_costs( $order ) {
|
||||
$costs = array_fill_keys( $order->get_items_tax_classes(), 0 );
|
||||
$costs['non-taxable'] = 0;
|
||||
$order_item_tax_classes = $order->get_items_tax_classes();
|
||||
$costs = array_fill_keys( $order_item_tax_classes, 0 );
|
||||
$costs['non-taxable'] = 0;
|
||||
|
||||
foreach ( $order->get_items( array( 'line_item', 'fee', 'shipping' ) ) as $item ) {
|
||||
if ( 0 > $item->get_total() ) {
|
||||
|
@ -49,7 +52,8 @@ class WC_Order_Item_Fee extends WC_Order_Item {
|
|||
if ( 'taxable' !== $item->get_tax_status() ) {
|
||||
$costs['non-taxable'] += $item->get_total();
|
||||
} elseif ( 'inherit' === $item->get_tax_class() ) {
|
||||
$costs[ reset( $order->get_items_tax_classes() ) ] += $item->get_total();
|
||||
$inherit_class = reset( $order_item_tax_classes );
|
||||
$costs[ $inherit_class ] += $item->get_total();
|
||||
} else {
|
||||
$costs[ $item->get_tax_class() ] += $item->get_total();
|
||||
}
|
||||
|
@ -70,7 +74,7 @@ class WC_Order_Item_Fee extends WC_Order_Item {
|
|||
}
|
||||
// Use regular calculation unless the fee is negative.
|
||||
if ( 0 <= $this->get_total() ) {
|
||||
return parent::calculate_taxes();
|
||||
return parent::calculate_taxes( $calculate_tax_for );
|
||||
}
|
||||
if ( wc_tax_enabled() && ( $order = $this->get_order() ) ) {
|
||||
// Apportion taxes to order items, shipping, and fees.
|
||||
|
@ -101,6 +105,16 @@ class WC_Order_Item_Fee extends WC_Order_Item {
|
|||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set fee amount.
|
||||
*
|
||||
* @param string $value
|
||||
* @throws WC_Data_Exception
|
||||
*/
|
||||
public function set_amount( $value ) {
|
||||
$this->set_prop( 'amount', wc_format_decimal( $value ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set tax class.
|
||||
*
|
||||
|
@ -173,6 +187,16 @@ class WC_Order_Item_Fee extends WC_Order_Item {
|
|||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get fee amount.
|
||||
*
|
||||
* @param string $context
|
||||
* @return string
|
||||
*/
|
||||
public function get_amount( $context = 'view' ) {
|
||||
return $this->get_prop( 'amount', $context );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get order item name.
|
||||
*
|
||||
|
|
|
@ -14,10 +14,11 @@ class WC_Order_Item_Fee_Data_Store extends Abstract_WC_Order_Item_Type_Data_Stor
|
|||
|
||||
/**
|
||||
* Data stored in meta keys.
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @var array
|
||||
*/
|
||||
protected $internal_meta_keys = array( '_tax_class', '_tax_status', '_line_subtotal', '_line_subtotal_tax', '_line_total', '_line_tax', '_line_tax_data' );
|
||||
protected $internal_meta_keys = array( '_fee_amount', '_tax_class', '_tax_status', '_line_subtotal', '_line_subtotal_tax', '_line_total', '_line_tax', '_line_tax_data' );
|
||||
|
||||
/**
|
||||
* Read/populate data properties specific to this order item.
|
||||
|
@ -29,6 +30,7 @@ class WC_Order_Item_Fee_Data_Store extends Abstract_WC_Order_Item_Type_Data_Stor
|
|||
parent::read( $item );
|
||||
$id = $item->get_id();
|
||||
$item->set_props( array(
|
||||
'amount' => get_metadata( 'order_item', $id, '_fee_amount', true ),
|
||||
'tax_class' => get_metadata( 'order_item', $id, '_tax_class', true ),
|
||||
'tax_status' => get_metadata( 'order_item', $id, '_tax_status', true ),
|
||||
'total' => get_metadata( 'order_item', $id, '_line_total', true ),
|
||||
|
@ -47,6 +49,7 @@ class WC_Order_Item_Fee_Data_Store extends Abstract_WC_Order_Item_Type_Data_Stor
|
|||
public function save_item_data( &$item ) {
|
||||
$id = $item->get_id();
|
||||
$save_values = array(
|
||||
'_fee_amount' => $item->get_amount( 'edit' ),
|
||||
'_tax_class' => $item->get_tax_class( 'edit' ),
|
||||
'_tax_status' => $item->get_tax_status( 'edit' ),
|
||||
'_line_total' => $item->get_total( 'edit' ),
|
||||
|
|
|
@ -328,7 +328,7 @@ function wc_cart_totals_order_total_html() {
|
|||
* @param object $fee
|
||||
*/
|
||||
function wc_cart_totals_fee_html( $fee ) {
|
||||
$cart_totals_fee_html = ( 'excl' == WC()->cart->tax_display_cart ) ? wc_price( $fee->amount ) : wc_price( $fee->amount + $fee->tax );
|
||||
$cart_totals_fee_html = ( 'excl' == WC()->cart->tax_display_cart ) ? wc_price( $fee->total ) : wc_price( $fee->total + $fee->tax );
|
||||
|
||||
echo apply_filters( 'woocommerce_cart_totals_fee_html', $cart_totals_fee_html, $fee );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue