WC_Cart_Totals::calculate_item_subtotals
Subtotals are costs before discounts.
To prevent rounding issues we need to work with the inclusive price where possible otherwise we'll see errors such as when working with a 9.99 inc price, 20% VAT which would be 8.325 leading to totals being 1p off.
Pre tax coupons come off the price the customer thinks they are paying - tax is calculated afterwards.
e.g. $100 bike with $10 coupon = customer pays $90 and tax worked backwards from that.
Method of the class: WC_Cart_Totals{}
Hooks from the method
Returns
null. Nothing (null).
Usage
// protected - for code of main (parent) or child class $result = $this->calculate_item_subtotals();
Changelog
| Since 3.2.0 | Introduced. |
WC_Cart_Totals::calculate_item_subtotals() WC Cart Totals::calculate item subtotals code WC 10.4.3
protected function calculate_item_subtotals() {
$merged_subtotal_taxes = array(); // Taxes indexed by tax rate ID for storage later.
$adjust_non_base_location_prices = apply_filters( 'woocommerce_adjust_non_base_location_prices', true );
$customer = $this->cart->get_customer();
$is_customer_vat_exempt = $customer && $customer->get_is_vat_exempt();
foreach ( $this->items as $item_key => $item ) {
if ( $item->price_includes_tax ) {
if ( $is_customer_vat_exempt ) {
$item = $this->remove_item_base_taxes( $item );
} elseif ( $adjust_non_base_location_prices ) {
$item = $this->adjust_non_base_location_price( $item );
}
}
$item->subtotal = $item->price;
if ( $this->calculate_tax && $item->product->is_taxable() ) {
$item->subtotal_taxes = WC_Tax::calc_tax( $item->subtotal, $item->tax_rates, $item->price_includes_tax );
$item->subtotal_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $item->subtotal_taxes ) );
if ( $item->price_includes_tax ) {
// Use unrounded taxes so we can re-calculate from the orders screen accurately later.
$item->subtotal = $item->subtotal - array_sum( $item->subtotal_taxes );
}
foreach ( $item->subtotal_taxes as $rate_id => $rate ) {
if ( ! isset( $merged_subtotal_taxes[ $rate_id ] ) ) {
$merged_subtotal_taxes[ $rate_id ] = 0;
}
$merged_subtotal_taxes[ $rate_id ] += $this->round_line_tax( $rate );
}
}
$this->cart->cart_contents[ $item_key ]['line_tax_data'] = array( 'subtotal' => wc_remove_number_precision_deep( $item->subtotal_taxes ) );
$this->cart->cart_contents[ $item_key ]['line_subtotal'] = wc_remove_number_precision( $item->subtotal );
$this->cart->cart_contents[ $item_key ]['line_subtotal_tax'] = wc_remove_number_precision( $item->subtotal_tax );
}
$items_subtotal = $this->get_rounded_items_total( $this->get_values_for_total( 'subtotal' ) );
// Prices are not rounded here because they should already be rounded based on settings in `get_rounded_items_total` and in `round_line_tax` method calls.
$this->set_total( 'items_subtotal', $items_subtotal );
$this->set_total( 'items_subtotal_tax', array_sum( $merged_subtotal_taxes ) );
$this->cart->set_subtotal( $this->get_total( 'items_subtotal' ) );
$this->cart->set_subtotal_tax( $this->get_total( 'items_subtotal_tax' ) );
}