public function calculate_taxes($cart = null, $packages = null, $return_packages = false) { global $woocommerce; if (get_option('woocommerce_calc_taxes', 0) != 'yes') { if ($return_packages) { return $packages; } return; } $default_shipping_location = array($woocommerce->customer->get_shipping_country(), $woocommerce->customer->get_shipping_state(), $woocommerce->customer->get_shipping_postcode()); $merge = false; if (!is_object($cart)) { $cart = $woocommerce->cart; $merge = true; } if (isset($_POST['action']) && $_POST['action'] == 'woocommerce_update_shipping_method') { return $cart; } if (!$packages) { $packages = $cart->get_shipping_packages(); } if (count($packages) < 2) { return; } // clear the taxes arrays remove tax totals from the grand total $old_taxes = $cart->taxes; $old_tax_total = $cart->tax_total; $old_shipping_taxes = $cart->shipping_taxes; $old_shipping_tax_total = $cart->shipping_tax_total; $old_total = $cart->total; $cart_total_without_taxes = $old_total - ($old_tax_total + $old_shipping_tax_total); // deduct taxes from the subtotal $cart->subtotal -= $old_tax_total; $item_taxes = array(); $cart_taxes = array(); foreach ($packages as $idx => $package) { if (isset($package['destination']) && !$this->wcms->is_address_empty($package['destination'])) { $woocommerce->customer->calculated_shipping(true); $woocommerce->customer->set_shipping_location($package['destination']['country'], $package['destination']['state'], $package['destination']['postcode']); } $tax_rates = array(); $shop_tax_rates = array(); /** * Calculate subtotals for items. This is done first so that discount logic can use the values. */ foreach ($package['contents'] as $cart_item_key => $values) { $_product = $values['data']; // Prices $line_price = $_product->get_price() * $values['quantity']; $line_subtotal = 0; $line_subtotal_tax = 0; if (!$_product->is_taxable()) { $line_subtotal = $line_price; } elseif ($cart->prices_include_tax) { // Get base tax rates if (empty($shop_tax_rates[$_product->tax_class])) { $shop_tax_rates[$_product->tax_class] = $cart->tax->get_shop_base_rate($_product->tax_class); } // Get item tax rates if (empty($tax_rates[$_product->get_tax_class()])) { $tax_rates[$_product->get_tax_class()] = $cart->tax->get_rates($_product->get_tax_class()); } $base_tax_rates = $shop_tax_rates[$_product->tax_class]; $item_tax_rates = $tax_rates[$_product->get_tax_class()]; /** * ADJUST TAX - Calculations when base tax is not equal to the item tax */ if ($item_tax_rates !== $base_tax_rates) { // Work out a new base price without the shop's base tax $taxes = $cart->tax->calc_tax($line_price, $base_tax_rates, true, true); // Now we have a new item price (excluding TAX) $line_subtotal = $line_price - array_sum($taxes); // Now add modifed taxes $tax_result = $cart->tax->calc_tax($line_subtotal, $item_tax_rates); $line_subtotal_tax = array_sum($tax_result); /** * Regular tax calculation (customer inside base and the tax class is unmodified */ } else { // Calc tax normally $taxes = $cart->tax->calc_tax($line_price, $item_tax_rates, true); $line_subtotal_tax = array_sum($taxes); $line_subtotal = $line_price - array_sum($taxes); } /** * Prices exclude tax * * This calculation is simpler - work with the base, untaxed price. */ } else { // Get item tax rates if (empty($tax_rates[$_product->get_tax_class()])) { $tax_rates[$_product->get_tax_class()] = WC_MS_Compatibility::get_tax_rates($_product->get_tax_class()); } $item_tax_rates = $tax_rates[$_product->get_tax_class()]; // Base tax for line before discount - we will store this in the order data $taxes = WC_MS_Compatibility::calc_tax($line_price, $item_tax_rates); $line_subtotal_tax = array_sum($taxes); $line_subtotal = $line_price; } // Add to main subtotal $cart->subtotal += $line_subtotal_tax; } /** * Calculate totals for items */ foreach ($package['contents'] as $cart_item_key => $values) { $_product = $values['data']; // Prices $base_price = $_product->get_price(); $line_price = $_product->get_price() * $values['quantity']; // Tax data $taxes = array(); $discounted_taxes = array(); if (!$_product->is_taxable()) { // Discounted Price (price with any pre-tax discounts applied) $discounted_price = $cart->get_discounted_price($values, $base_price, true); $line_subtotal_tax = 0; $line_subtotal = $line_price; $line_tax = 0; $line_total = WC_MS_Compatibility::round_tax($discounted_price * $values['quantity']); /** * Prices include tax */ } elseif ($cart->prices_include_tax) { $base_tax_rates = $shop_tax_rates[$_product->tax_class]; $item_tax_rates = $tax_rates[$_product->get_tax_class()]; /** * ADJUST TAX - Calculations when base tax is not equal to the item tax */ if ($item_tax_rates !== $base_tax_rates) { // Work out a new base price without the shop's base tax $taxes = $cart->tax->calc_tax($line_price, $base_tax_rates, true, true); // Now we have a new item price (excluding TAX) $line_subtotal = woocommerce_round_tax_total($line_price - array_sum($taxes)); // Now add modifed taxes $taxes = $cart->tax->calc_tax($line_subtotal, $item_tax_rates); $line_subtotal_tax = array_sum($taxes); // Adjusted price (this is the price including the new tax rate) $adjusted_price = ($line_subtotal + $line_subtotal_tax) / $values['quantity']; // Apply discounts $discounted_price = $cart->get_discounted_price($values, $adjusted_price, true); $discounted_taxes = $cart->tax->calc_tax($discounted_price * $values['quantity'], $item_tax_rates, true); $line_tax = array_sum($discounted_taxes); $line_total = $discounted_price * $values['quantity'] - $line_tax; /** * Regular tax calculation (customer inside base and the tax class is unmodified */ } else { // Work out a new base price without the shop's base tax $taxes = $cart->tax->calc_tax($line_price, $item_tax_rates, true); // Now we have a new item price (excluding TAX) $line_subtotal = $line_price - array_sum($taxes); $line_subtotal_tax = array_sum($taxes); // Calc prices and tax (discounted) $discounted_price = $cart->get_discounted_price($values, $base_price, true); $discounted_taxes = $cart->tax->calc_tax($discounted_price * $values['quantity'], $item_tax_rates, true); $line_tax = array_sum($discounted_taxes); $line_total = $discounted_price * $values['quantity'] - $line_tax; } // Tax rows - merge the totals we just got foreach (array_keys($cart_taxes + $discounted_taxes) as $key) { $cart_taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($cart_taxes[$key]) ? $cart_taxes[$key] : 0); } /** * Prices exclude tax */ } else { $item_tax_rates = $tax_rates[$_product->get_tax_class()]; // Work out a new base price without the shop's base tax $taxes = WC_MS_Compatibility::calc_tax($line_price, $item_tax_rates); // Now we have the item price (excluding TAX) $line_subtotal = $line_price; $line_subtotal_tax = array_sum($taxes); // Now calc product rates $discounted_price = $cart->get_discounted_price($values, $base_price, true); $discounted_taxes = WC_MS_Compatibility::calc_tax($discounted_price * $values['quantity'], $item_tax_rates); $discounted_tax_amount = array_sum($discounted_taxes); $line_tax = $discounted_tax_amount; $line_total = $discounted_price * $values['quantity']; // Tax rows - merge the totals we just got foreach (array_keys($cart_taxes + $discounted_taxes) as $key) { $cart_taxes[$key] = (isset($discounted_taxes[$key]) ? $discounted_taxes[$key] : 0) + (isset($cart_taxes[$key]) ? $cart_taxes[$key] : 0); } } // Store costs + taxes for lines if (!isset($item_taxes[$cart_item_key])) { $item_taxes[$cart_item_key]['line_total'] = $line_total; $item_taxes[$cart_item_key]['line_tax'] = $line_tax; $item_taxes[$cart_item_key]['line_subtotal'] = $line_subtotal; $item_taxes[$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; $item_taxes[$cart_item_key]['line_tax_data'] = array('total' => $discounted_taxes, 'subtotal' => $taxes); } else { $item_taxes[$cart_item_key]['line_total'] += $line_total; $item_taxes[$cart_item_key]['line_tax'] += $line_tax; $item_taxes[$cart_item_key]['line_subtotal'] += $line_subtotal; $item_taxes[$cart_item_key]['line_subtotal_tax'] += $line_subtotal_tax; $item_taxes[$cart_item_key]['line_tax_data']['total'] += $discounted_taxes; $item_taxes[$cart_item_key]['line_tax_data']['subtotal'] += $taxes; } $packages[$idx]['contents'][$cart_item_key]['line_total'] = $line_total; $packages[$idx]['contents'][$cart_item_key]['line_tax'] = $line_tax; $packages[$idx]['contents'][$cart_item_key]['line_subtotal'] = $line_subtotal; $packages[$idx]['contents'][$cart_item_key]['line_subtotal_tax'] = $line_subtotal_tax; $packages[$idx]['contents'][$cart_item_key]['line_tax_data'] = array('total' => $discounted_taxes, 'subtotal' => $taxes); } } foreach ($item_taxes as $cart_item_key => $taxes) { if (!isset($cart->cart_contents[$cart_item_key])) { continue; } $product_id = $cart->cart_contents[$cart_item_key]['product_id']; $woocommerce->cart->recurring_cart_contents = array(); $cart->cart_contents[$cart_item_key]['line_total'] = $taxes['line_total']; $cart->cart_contents[$cart_item_key]['line_tax'] = $taxes['line_tax']; $cart->cart_contents[$cart_item_key]['line_subtotal'] = $taxes['line_subtotal']; $cart->cart_contents[$cart_item_key]['line_subtotal_tax'] = $taxes['line_subtotal_tax']; $cart->cart_contents[$cart_item_key]['line_tax_data'] = $taxes['line_tax_data']; // Set recurring taxes for subscription products if (class_exists('WC_Subscriptions_Product') && WC_Subscriptions_Product::is_subscription($product_id)) { $woocommerce->cart->recurring_cart_contents[$product_id]['recurring_line_total'] = $taxes['line_total']; $woocommerce->cart->recurring_cart_contents[$product_id]['recurring_line_tax'] = $taxes['line_tax']; $woocommerce->cart->recurring_cart_contents[$product_id]['recurring_line_subtotal'] = $taxes['line_subtotal']; $woocommerce->cart->recurring_cart_contents[$product_id]['recurring_line_subtotal_tax'] = $taxes['line_subtotal_tax']; } } // Total up/round taxes and shipping taxes if ($cart->round_at_subtotal) { $cart->tax_total = WC_MS_Compatibility::get_tax_total($cart_taxes); $cart->taxes = array_map('WC_MS_Compatibility::round_tax', $cart_taxes); } else { $cart->tax_total = array_sum($cart_taxes); $cart->taxes = array_map('WC_MS_Compatibility::round_tax', $cart_taxes); } if ($merge) { $woocommerce->cart = $cart; } // Setting an empty default customer shipping location prevents // subtotal calculation from applying the incorrect taxes based // on the shipping address. But do not remove the shipping country // to satisfy the validation done on WC_Checkout $woocommerce->customer->calculated_shipping(false); $woocommerce->customer->set_shipping_location($woocommerce->customer->get_shipping_country(), '', ''); if ($return_packages) { return $packages; } // store the modified packages array wcms_session_set('wcms_packages', $packages); return $cart; }
public function generate_address_session($packages) { global $woocommerce; $fields = $woocommerce->countries->get_address_fields($woocommerce->countries->get_base_country(), 'shipping_'); $data = array(); $rel = array(); foreach ($packages as $pkg_idx => $package) { if (!isset($package['full_address']) || empty($package['full_address']['postcode']) || empty($package['full_address']['country'])) { continue; } $items = $package['contents']; foreach ($items as $cart_key => $item) { $qty = $item['quantity']; $product_id = $item['product_id']; $sig = $cart_key . '_' . $product_id . '_'; $address_id = 0; $i = 1; for ($x = 0; $x < $qty; $x++) { $rel[$address_id][] = $cart_key; while (isset($data['shipping_first_name_' . $sig . $i])) { $i++; } $_sig = $sig . $i; if ($fields) { foreach ($fields as $key => $field) { $address_key = str_replace('shipping_', '', $key); $data[$key . '_' . $_sig] = $package['full_address'][$address_key]; } } } } } wcms_session_set('cart_item_addresses', $data); wcms_session_set('address_relationships', $rel); }
function update_order_review($post) { global $woocommerce; $ship_methods = array(); $data = array(); parse_str($post, $data); if (isset($data['shipping_methods']) && is_array($data['shipping_methods'])) { foreach ($data['shipping_methods'] as $x => $method) { list($id, $label) = explode('||', $method); $ship_methods[$x] = array('id' => $id, 'label' => $label); //$_SESSION['shipping_methods'][$x] = array( 'id' => $id, 'label' => $label); } } elseif (isset($data['shipping_method']) && $data['shipping_method'] != 'multiple_shipping') { //$_SESSION['shipping_methods'][0] = array( 'id' => $data['shipping_method'], 'label' => $data['shipping_method']); $ship_methods[0] = array('id' => $data['shipping_method'], 'label' => $data['shipping_method']); } wcms_session_set('shipping_methods', $ship_methods); }