Manual discounts and negative taxes
This commit is contained in:
parent
1328e17069
commit
f71dc64d35
|
@ -874,64 +874,51 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function add_discount( $discount ) {
|
public function add_discount( $discount ) {
|
||||||
$discounts = new WC_Discounts( $this );
|
|
||||||
|
|
||||||
// See if we have a coupon code.
|
// See if we have a coupon code.
|
||||||
$coupon_code = wc_format_coupon_code( $discount );
|
$coupon_code = wc_format_coupon_code( $discount );
|
||||||
$coupon = new WC_Coupon( $coupon_code );
|
$coupon = new WC_Coupon( $coupon_code );
|
||||||
|
|
||||||
if ( $coupon->get_code() === $coupon_code && $coupon->is_valid() ) {
|
if ( $coupon->get_code() === $coupon_code && $coupon->is_valid() ) {
|
||||||
$applied = $discounts->apply_discount( $coupon );
|
$discounts = new WC_Discounts( $this );
|
||||||
|
$applied = $discounts->apply_discount( $coupon );
|
||||||
|
|
||||||
|
if ( $applied && ! is_wp_error( $applied ) ) {
|
||||||
|
$item_discounts = $discounts->get_discounts_by_item();
|
||||||
|
$coupon_discounts = $discounts->get_discounts_by_coupon();
|
||||||
|
|
||||||
|
// Add discounts to line items.
|
||||||
|
if ( $item_discounts ) {
|
||||||
|
foreach ( $item_discounts as $item_id => $amount ) {
|
||||||
|
$item = $this->get_item( $item_id );
|
||||||
|
$item->set_total( $amount );
|
||||||
|
$item->save();
|
||||||
|
}
|
||||||
|
unset( $this->items['line_items'] ); // Remove read line items variable so new totals are loaded from DB.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add WC_Order_Item_Coupon objects for applied coupons.
|
||||||
|
if ( $coupon_discounts ) {
|
||||||
|
foreach ( $coupon_discounts as $coupon_code => $amount ) {
|
||||||
|
$item = new WC_Order_Item_Coupon();
|
||||||
|
$item->set_props( array(
|
||||||
|
'code' => $coupon_code,
|
||||||
|
'discount' => $amount,
|
||||||
|
'discount_tax' => '', // @todo This needs to be calculated somehow like the cart class does. Maybe we need an order calculation class?
|
||||||
|
) );
|
||||||
|
$item->save();
|
||||||
|
$this->add_item( $item );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$applied = $discounts->apply_discount( $discount );
|
// Add WC_Order_Item_Discount object.
|
||||||
|
$item = new WC_Order_Item_Discount();
|
||||||
|
$item->set_amount( $discount );
|
||||||
|
$item->save();
|
||||||
|
$this->add_item( $item );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $applied && ! is_wp_error( $applied ) ) {
|
$this->calculate_totals( true );
|
||||||
$item_discounts = $discounts->get_discounts_by_item();
|
|
||||||
$coupon_discounts = $discounts->get_discounts_by_coupon();
|
|
||||||
$manual_discounts = $discounts->get_manual_discounts();
|
|
||||||
|
|
||||||
// Add discounts to line items.
|
|
||||||
if ( $item_discounts ) {
|
|
||||||
foreach ( $item_discounts as $item_id => $amount ) {
|
|
||||||
$item = $this->get_item( $item_id );
|
|
||||||
$item->set_total( $amount );
|
|
||||||
$item->save();
|
|
||||||
}
|
|
||||||
unset( $this->items['line_items'] ); // Remove read line items variable so new totals are loaded from DB.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add WC_Order_Item_Coupon objects for applied coupons.
|
|
||||||
if ( $coupon_discounts ) {
|
|
||||||
foreach ( $coupon_discounts as $coupon_code => $amount ) {
|
|
||||||
$item = new WC_Order_Item_Coupon();
|
|
||||||
$item->set_props( array(
|
|
||||||
'code' => $coupon_code,
|
|
||||||
'discount' => $amount,
|
|
||||||
'discount_tax' => '', // @todo This needs to be calculated somehow like the cart class does. Maybe we need an order calculation class?
|
|
||||||
) );
|
|
||||||
$this->add_item( $item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add WC_Order_Item_Discount objects for applied discounts.
|
|
||||||
if ( $manual_discounts ) {
|
|
||||||
foreach ( $manual_discounts as $manual_discount_key => $manual_discount ) {
|
|
||||||
$item = new WC_Order_Item_Discount();
|
|
||||||
$item->set_props( array(
|
|
||||||
'amount' => wc_remove_number_precision( $manual_discount->get_amount() ),
|
|
||||||
'discount_type' => $manual_discount->get_discount_type(),
|
|
||||||
'discount_total' => wc_remove_number_precision( $manual_discount->get_discount_total() ),
|
|
||||||
) );
|
|
||||||
$this->add_item( $item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo we need to work out if manual discounts get calculated here, during calculate_totals, or inside a dedicated class.
|
|
||||||
|
|
||||||
// Total recalc.
|
|
||||||
$this->calculate_totals( true );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1069,7 +1056,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return array_unique( $found_tax_classes );
|
return $found_tax_classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1120,11 +1107,11 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
||||||
$shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' );
|
$shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' );
|
||||||
|
|
||||||
if ( 'inherit' === $shipping_tax_class ) {
|
if ( 'inherit' === $shipping_tax_class ) {
|
||||||
$shipping_tax_class = current( array_intersect( array_merge( array( '' ), WC_Tax::get_tax_class_slugs() ), $this->get_items_tax_classes() ) );
|
$shipping_tax_class = current( array_intersect( array_merge( array( '' ), WC_Tax::get_tax_class_slugs() ), array_unique( $this->get_items_tax_classes() ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger tax recalculation for all items.
|
// Trigger tax recalculation for all items.
|
||||||
foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
|
foreach ( $this->get_items( array( 'line_item', 'fee', 'discount' ) ) as $item_id => $item ) {
|
||||||
$item->calculate_taxes( $calculate_tax_for );
|
$item->calculate_taxes( $calculate_tax_for );
|
||||||
$item->save();
|
$item->save();
|
||||||
}
|
}
|
||||||
|
@ -1146,7 +1133,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
||||||
$existing_taxes = $this->get_taxes();
|
$existing_taxes = $this->get_taxes();
|
||||||
$saved_rate_ids = array();
|
$saved_rate_ids = array();
|
||||||
|
|
||||||
foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
|
foreach ( $this->get_items( array( 'line_item', 'fee', 'discount' ) ) as $item_id => $item ) {
|
||||||
$taxes = $item->get_taxes();
|
$taxes = $item->get_taxes();
|
||||||
foreach ( $taxes['total'] as $tax_rate_id => $tax ) {
|
foreach ( $taxes['total'] as $tax_rate_id => $tax ) {
|
||||||
$cart_taxes[ $tax_rate_id ] = isset( $cart_taxes[ $tax_rate_id ] ) ? $cart_taxes[ $tax_rate_id ] + (float) $tax : (float) $tax;
|
$cart_taxes[ $tax_rate_id ] = isset( $cart_taxes[ $tax_rate_id ] ) ? $cart_taxes[ $tax_rate_id ] + (float) $tax : (float) $tax;
|
||||||
|
@ -1197,16 +1184,23 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
||||||
* @return float calculated grand total.
|
* @return float calculated grand total.
|
||||||
*/
|
*/
|
||||||
public function calculate_totals( $and_taxes = true ) {
|
public function calculate_totals( $and_taxes = true ) {
|
||||||
$cart_subtotal = 0;
|
$cart_subtotal = 0;
|
||||||
$cart_total = 0;
|
$cart_total = 0;
|
||||||
$fee_total = 0;
|
$fee_total = 0;
|
||||||
$cart_subtotal_tax = 0;
|
$discount_total = 0;
|
||||||
$cart_total_tax = 0;
|
$discount_total_tax = 0;
|
||||||
|
$cart_subtotal_tax = 0;
|
||||||
|
$cart_total_tax = 0;
|
||||||
|
|
||||||
|
// Discounts are recalculated first based on the latest item costs.
|
||||||
|
$this->calculate_discounts();
|
||||||
|
|
||||||
|
// Calculate taxes for items, shipping, discounts.
|
||||||
if ( $and_taxes ) {
|
if ( $and_taxes ) {
|
||||||
$this->calculate_taxes();
|
$this->calculate_taxes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare the totals.
|
||||||
foreach ( $this->get_items() as $item ) {
|
foreach ( $this->get_items() as $item ) {
|
||||||
$cart_subtotal += $item->get_subtotal();
|
$cart_subtotal += $item->get_subtotal();
|
||||||
$cart_total += $item->get_total();
|
$cart_total += $item->get_total();
|
||||||
|
@ -1220,16 +1214,43 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
||||||
$fee_total += $item->get_total();
|
$fee_total += $item->get_total();
|
||||||
}
|
}
|
||||||
|
|
||||||
$grand_total = round( $cart_total + $fee_total + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() );
|
foreach ( $this->get_items( 'discount' ) as $item ) {
|
||||||
|
$discount_total += $item->get_total();
|
||||||
|
$discount_total_tax += $item->get_total_tax();
|
||||||
|
}
|
||||||
|
|
||||||
$this->set_discount_total( $cart_subtotal - $cart_total );
|
$grand_total = round( $cart_total + $discount_total + $fee_total + $this->get_shipping_total() + $this->get_cart_tax() + $this->get_shipping_tax(), wc_get_price_decimals() );
|
||||||
$this->set_discount_tax( $cart_subtotal_tax - $cart_total_tax );
|
|
||||||
|
$this->set_discount_total( $cart_subtotal - $cart_total + $discount_total );
|
||||||
|
$this->set_discount_tax( $cart_subtotal_tax - $cart_total_tax + $discount_total_tax );
|
||||||
$this->set_total( $grand_total );
|
$this->set_total( $grand_total );
|
||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
return $grand_total;
|
return $grand_total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate actual discount amounts for each discount row from line items.
|
||||||
|
*
|
||||||
|
* @todo consider moving to totals class.
|
||||||
|
*/
|
||||||
|
protected function calculate_discounts() {
|
||||||
|
$discounts = new WC_Discounts( $this );
|
||||||
|
$discount_items = $this->get_items( 'discount' );
|
||||||
|
|
||||||
|
// Re-calc manual discounts based on new line items.
|
||||||
|
foreach ( $discount_items as $discount ) {
|
||||||
|
$result = $discounts->apply_discount( ( 'fixed' === $discount->get_discount_type() ? $discount->get_amount() : $discount->get_amount() . '%' ), $discount->get_id() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set discount totals.
|
||||||
|
foreach ( $discounts->get_manual_discounts() as $manual_discount_key => $manual_discount ) {
|
||||||
|
$discount_item = $discount_items[ $manual_discount_key ];
|
||||||
|
$discount_item->set_total( wc_remove_number_precision( $manual_discount->get_discount_total() ) * -1 );
|
||||||
|
$discount_item->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get item subtotal - this is the cost before discount.
|
* Get item subtotal - this is the cost before discount.
|
||||||
*
|
*
|
||||||
|
|
|
@ -30,10 +30,35 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||||
<td class="item_cost" width="1%"> </td>
|
<td class="item_cost" width="1%"> </td>
|
||||||
<td class="quantity" width="1%"> </td>
|
<td class="quantity" width="1%"> </td>
|
||||||
<td class="line_cost" width="1%">
|
<td class="line_cost" width="1%">
|
||||||
<?php echo wc_price( $item->get_discount_total() ); ?>
|
<?php echo wc_price( $item->get_total() ); ?>
|
||||||
</td>
|
</td>
|
||||||
<?php
|
<?php
|
||||||
// taxes?
|
if ( ( $tax_data = $item->get_taxes() ) && wc_tax_enabled() ) {
|
||||||
|
foreach ( $order_taxes as $tax_item ) {
|
||||||
|
$tax_item_id = $tax_item->get_rate_id();
|
||||||
|
$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : '';
|
||||||
|
?>
|
||||||
|
<td class="line_tax" width="1%">
|
||||||
|
<div class="view">
|
||||||
|
<?php
|
||||||
|
echo ( '' !== $tax_item_total ) ? wc_price( wc_round_tax_total( $tax_item_total ), array( 'currency' => $order->get_currency() ) ) : '–';
|
||||||
|
|
||||||
|
if ( $refunded = $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'fee' ) ) {
|
||||||
|
echo '<small class="refunded">-' . wc_price( $refunded, array( 'currency' => $order->get_currency() ) ) . '</small>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<div class="edit" style="display: none;">
|
||||||
|
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>][<?php echo esc_attr( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $tax_item_total ) ) ? esc_attr( wc_format_localized_price( $tax_item_total ) ) : ''; ?>" class="line_tax wc_input_price" />
|
||||||
|
</div>
|
||||||
|
<div class="refund" style="display: none;">
|
||||||
|
<input type="text" name="refund_line_tax[<?php echo absint( $item_id ); ?>][<?php echo esc_attr( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" class="refund_line_tax wc_input_price" data-tax_id="<?php echo esc_attr( $tax_item_id ); ?>" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<td class="wc-order-edit-line-item">
|
<td class="wc-order-edit-line-item">
|
||||||
<?php if ( $order->is_editable() ) : ?>
|
<?php if ( $order->is_editable() ) : ?>
|
||||||
|
|
|
@ -256,9 +256,10 @@ class WC_Discounts {
|
||||||
* Apply a discount to all items.
|
* Apply a discount to all items.
|
||||||
*
|
*
|
||||||
* @param string|object $raw_discount Accepts a string (fixed or percent discounts), or WC_Coupon object.
|
* @param string|object $raw_discount Accepts a string (fixed or percent discounts), or WC_Coupon object.
|
||||||
|
* @param string $discount_id Optional ID for the discount. Generated if not defined.
|
||||||
* @return bool|WP_Error True if applied or WP_Error instance in failure.
|
* @return bool|WP_Error True if applied or WP_Error instance in failure.
|
||||||
*/
|
*/
|
||||||
public function apply_discount( $raw_discount ) {
|
public function apply_discount( $raw_discount, $discount_id = null ) {
|
||||||
if ( is_a( $raw_discount, 'WC_Coupon' ) ) {
|
if ( is_a( $raw_discount, 'WC_Coupon' ) ) {
|
||||||
return $this->apply_coupon( $raw_discount );
|
return $this->apply_coupon( $raw_discount );
|
||||||
}
|
}
|
||||||
|
@ -285,7 +286,9 @@ class WC_Discounts {
|
||||||
$discount->set_discount_total( min( $discount->get_amount(), $total_to_discount ) );
|
$discount->set_discount_total( min( $discount->get_amount(), $total_to_discount ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->manual_discounts[ $this->generate_discount_id( $discount ) ] = $discount;
|
$discount_id = $discount_id ? $discount_id : $this->generate_discount_id( $discount );
|
||||||
|
|
||||||
|
$this->manual_discounts[ $discount_id ] = $discount;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,46 @@ class WC_Order_Item_Discount extends WC_Order_Item {
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $extra_data = array(
|
protected $extra_data = array(
|
||||||
'amount' => 0, // Discount amount.
|
'amount' => 0, // Discount amount.
|
||||||
'discount_type' => 'fixed', // Fixed or percent type.
|
'discount_type' => 'fixed', // Fixed or percent type.
|
||||||
'discount_total' => 0,
|
'total' => '',
|
||||||
|
'total_tax' => '',
|
||||||
|
'taxes' => array(
|
||||||
|
'total' => array(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate item taxes.
|
||||||
|
*
|
||||||
|
* @since 3.2.0
|
||||||
|
* @param array $calculate_tax_for Location data to get taxes for. Required.
|
||||||
|
* @return bool True if taxes were calculated.
|
||||||
|
*/
|
||||||
|
public function calculate_taxes( $calculate_tax_for = array() ) {
|
||||||
|
if ( ! isset( $calculate_tax_for['country'], $calculate_tax_for['state'], $calculate_tax_for['postcode'], $calculate_tax_for['city'] ) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( wc_tax_enabled() && ( $order = $this->get_order() ) ) {
|
||||||
|
// Apportion taxes to order items.
|
||||||
|
$order = $this->get_order();
|
||||||
|
$tax_class_counts = array_count_values( $order->get_items_tax_classes() );
|
||||||
|
$item_count = $order->get_item_count();
|
||||||
|
$discount_taxes = array();
|
||||||
|
|
||||||
|
foreach ( $tax_class_counts as $tax_class => $tax_class_count ) {
|
||||||
|
$proportion = $tax_class_count / $item_count;
|
||||||
|
$cart_discount_proportion = $this->get_total() * $proportion;
|
||||||
|
$discount_taxes = wc_array_merge_recursive_numeric( $discount_taxes, WC_Tax::calc_tax( $cart_discount_proportion, WC_Tax::get_rates( $tax_class ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->set_taxes( array( 'total' => $discount_taxes ) );
|
||||||
|
} else {
|
||||||
|
$this->set_taxes( false );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Setters
|
| Setters
|
||||||
|
@ -33,10 +68,16 @@ class WC_Order_Item_Discount extends WC_Order_Item {
|
||||||
/**
|
/**
|
||||||
* Set amount.
|
* Set amount.
|
||||||
*
|
*
|
||||||
* @param string $value Value to set.
|
* @param string $raw_discount Value to set.
|
||||||
*/
|
*/
|
||||||
public function set_amount( $value ) {
|
public function set_amount( $raw_discount ) {
|
||||||
$this->set_prop( 'amount', $value );
|
if ( strstr( $raw_discount, '%' ) ) {
|
||||||
|
$this->set_prop( 'amount', trim( $raw_discount, '%' ) );
|
||||||
|
$this->set_discount_type( 'percent' );
|
||||||
|
} elseif ( is_numeric( $raw_discount ) && 0 < absint( $raw_discount ) ) {
|
||||||
|
$this->set_prop( 'amount', absint( $raw_discount ) );
|
||||||
|
$this->set_discount_type( 'fixed' );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,12 +90,39 @@ class WC_Order_Item_Discount extends WC_Order_Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set discount total.
|
* Set total.
|
||||||
*
|
*
|
||||||
* @param string $value Value to set.
|
* @param string $value Value to set.
|
||||||
*/
|
*/
|
||||||
public function set_discount_total( $value ) {
|
public function set_total( $value ) {
|
||||||
$this->set_prop( 'discount_total', wc_format_decimal( $value ) );
|
$this->set_prop( 'total', wc_format_decimal( $value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set total tax.
|
||||||
|
*
|
||||||
|
* @param string $value Value to set.
|
||||||
|
*/
|
||||||
|
public function set_total_tax( $value ) {
|
||||||
|
$this->set_prop( 'total_tax', wc_format_decimal( $value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set taxes.
|
||||||
|
*
|
||||||
|
* This is an array of tax ID keys with total amount values.
|
||||||
|
* @param array $raw_tax_data
|
||||||
|
*/
|
||||||
|
public function set_taxes( $raw_tax_data ) {
|
||||||
|
$raw_tax_data = maybe_unserialize( $raw_tax_data );
|
||||||
|
$tax_data = array(
|
||||||
|
'total' => array(),
|
||||||
|
);
|
||||||
|
if ( ! empty( $raw_tax_data['total'] ) ) {
|
||||||
|
$tax_data['total'] = array_map( 'wc_format_decimal', $raw_tax_data['total'] );
|
||||||
|
}
|
||||||
|
$this->set_prop( 'taxes', $tax_data );
|
||||||
|
$this->set_total_tax( array_sum( $tax_data['total'] ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -93,12 +161,32 @@ class WC_Order_Item_Discount extends WC_Order_Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get discount_total.
|
* Get total fee.
|
||||||
*
|
*
|
||||||
* @param string $context View or edit context.
|
* @param string $context
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function get_discount_total( $context = 'view' ) {
|
public function get_total( $context = 'view' ) {
|
||||||
return $this->get_prop( 'discount_total', $context );
|
return $this->get_prop( 'total', $context );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total tax.
|
||||||
|
*
|
||||||
|
* @param string $context
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_total_tax( $context = 'view' ) {
|
||||||
|
return $this->get_prop( 'total_tax', $context );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get fee taxes.
|
||||||
|
*
|
||||||
|
* @param string $context
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_taxes( $context = 'view' ) {
|
||||||
|
return $this->get_prop( 'taxes', $context );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,21 +18,22 @@ class WC_Order_Item_Discount_Data_Store extends Abstract_WC_Order_Item_Type_Data
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $internal_meta_keys = array( 'discount_type', 'discount_total', 'amount' );
|
protected $internal_meta_keys = array( 'discount_type', 'amount', '_line_total', '_line_tax', '_line_tax_data' );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read/populate data properties specific to this order item.
|
* Read/populate data properties specific to this order item.
|
||||||
*
|
*
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
* @param WC_Order_Item_Coupon $item
|
* @param WC_Order_Item_Discount $item
|
||||||
*/
|
*/
|
||||||
public function read( &$item ) {
|
public function read( &$item ) {
|
||||||
parent::read( $item );
|
parent::read( $item );
|
||||||
$id = $item->get_id();
|
$id = $item->get_id();
|
||||||
$item->set_props( array(
|
$item->set_props( array(
|
||||||
'discount_type' => get_metadata( 'order_item', $id, 'discount_type', true ),
|
'discount_type' => get_metadata( 'order_item', $id, 'discount_type', true ),
|
||||||
'discount_total' => get_metadata( 'order_item', $id, 'discount_total', true ),
|
'total' => get_metadata( 'order_item', $id, '_line_total', true ),
|
||||||
'amount' => get_metadata( 'order_item', $id, 'amount', true ),
|
'taxes' => get_metadata( 'order_item', $id, '_line_tax_data', true ),
|
||||||
|
'amount' => get_metadata( 'order_item', $id, 'amount', true ),
|
||||||
) );
|
) );
|
||||||
$item->set_object_read( true );
|
$item->set_object_read( true );
|
||||||
}
|
}
|
||||||
|
@ -42,13 +43,15 @@ class WC_Order_Item_Discount_Data_Store extends Abstract_WC_Order_Item_Type_Data
|
||||||
* Ran after both create and update, so $item->get_id() will be set.
|
* Ran after both create and update, so $item->get_id() will be set.
|
||||||
*
|
*
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
* @param WC_Order_Item_Coupon $item
|
* @param WC_Order_Item_Discount $item
|
||||||
*/
|
*/
|
||||||
public function save_item_data( &$item ) {
|
public function save_item_data( &$item ) {
|
||||||
$id = $item->get_id();
|
$id = $item->get_id();
|
||||||
$save_values = array(
|
$save_values = array(
|
||||||
'discount_type' => $item->get_discount_type( 'edit' ),
|
'discount_type' => $item->get_discount_type( 'edit' ),
|
||||||
'discount_total' => $item->get_discount_total( 'edit' ),
|
'_line_total' => $item->get_total( 'edit' ),
|
||||||
|
'_line_tax' => $item->get_total_tax( 'edit' ),
|
||||||
|
'_line_tax_data' => $item->get_taxes( 'edit' ),
|
||||||
'amount' => $item->get_amount( 'edit' ),
|
'amount' => $item->get_amount( 'edit' ),
|
||||||
);
|
);
|
||||||
foreach ( $save_values as $key => $value ) {
|
foreach ( $save_values as $key => $value ) {
|
||||||
|
|
|
@ -1169,3 +1169,62 @@ function wc_cart_round_discount( $value, $precision ) {
|
||||||
return round( $value, $precision );
|
return round( $value, $precision );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array merge and sum function.
|
||||||
|
*
|
||||||
|
* Source: https://gist.github.com/Nickology/f700e319cbafab5eaedc
|
||||||
|
*
|
||||||
|
* @since 3.2.0
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function wc_array_merge_recursive_numeric() {
|
||||||
|
$arrays = func_get_args();
|
||||||
|
|
||||||
|
// If there's only one array, it's already merged.
|
||||||
|
if ( 1 === count( $arrays ) ) {
|
||||||
|
return $arrays[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any items in $arrays that are NOT arrays.
|
||||||
|
foreach ( $arrays as $key => $array ) {
|
||||||
|
if ( ! is_array( $array ) ) {
|
||||||
|
unset( $arrays[ $key ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We start by setting the first array as our final array.
|
||||||
|
// We will merge all other arrays with this one.
|
||||||
|
$final = array_shift( $arrays );
|
||||||
|
|
||||||
|
foreach ( $arrays as $b ) {
|
||||||
|
foreach ( $final as $key => $value ) {
|
||||||
|
// If $key does not exist in $b, then it is unique and can be safely merged.
|
||||||
|
if ( ! isset( $b[ $key ] ) ) {
|
||||||
|
$final[ $key ] = $value;
|
||||||
|
} else {
|
||||||
|
// If $key is present in $b, then we need to merge and sum numeric values in both.
|
||||||
|
if ( is_numeric( $value ) && is_numeric( $b[ $key ] ) ) {
|
||||||
|
// If both values for these keys are numeric, we sum them.
|
||||||
|
$final[ $key ] = $value + $b[ $key ];
|
||||||
|
} elseif ( is_array( $value ) && is_array( $b[ $key ] ) ) {
|
||||||
|
// If both values are arrays, we recursively call ourself.
|
||||||
|
$final[ $key ] = wc_array_merge_recursive_numeric( $value, $b[ $key ] );
|
||||||
|
} else {
|
||||||
|
// If both keys exist but differ in type, then we cannot merge them.
|
||||||
|
// In this scenario, we will $b's value for $key is used.
|
||||||
|
$final[ $key ] = $b[ $key ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, we need to merge any keys that exist only in $b.
|
||||||
|
foreach ( $b as $key => $value ) {
|
||||||
|
if ( ! isset( $final[ $key ] ) ) {
|
||||||
|
$final[ $key ] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $final;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue