/** * Calculate products and shipping taxes * * @param array $cart Cart data * @param array $group_key Group number * @param array $group_products Products data * @param array $shipping_rates * @param array $auth Auth data * @return boolean Always false */ function fn_calculate_taxes(&$cart, $group_key, &$group_products, &$shipping_rates, $auth) { /** * Prepare params before applying products and shipping taxes to cart * * @param array $cart Cart data * @param array $group_products Products data * @param array $shipping_rates * @param array $auth Auth data */ fn_set_hook('calculate_taxes_pre', $cart, $group_products, $shipping_rates, $auth); $calculated_data = array(); if (Registry::get('settings.General.tax_calculation') == 'unit_price') { // Tax calculation method based on UNIT PRICE // Calculate product taxes foreach ($group_products as $k => $product) { $taxes = fn_get_product_taxes($k, $cart, $group_products); if (empty($taxes)) { continue; } if (isset($product['subtotal'])) { if ($product['price'] == $product['subtotal'] && $product['amount'] != 1) { $price = fn_format_price($product['price']); } else { $price = fn_format_price($product['subtotal'] / $product['amount']); } $calculated_data['P_' . $k] = fn_calculate_tax_rates($taxes, $price, $product['amount'], $auth, $cart); $group_products[$k]['tax_summary'] = array('included' => 0, 'added' => 0, 'total' => 0); // tax summary for 1 unit of product $cart['products'][$k]['tax_summary'] = array('included' => 0, 'added' => 0, 'total' => 0); // tax summary for 1 unit of product // Apply taxes to product subtotal if (!empty($calculated_data['P_' . $k])) { foreach ($calculated_data['P_' . $k] as $_k => $v) { $group_products[$k]['taxes'][$_k] = $v; $cart['products'][$k]['taxes'][$_k] = $v; if ($taxes[$_k]['price_includes_tax'] != 'Y') { $group_products[$k]['tax_summary']['added'] += $v['tax_subtotal']; $cart['products'][$k]['tax_summary']['added'] += $v['tax_subtotal']; } else { $group_products[$k]['tax_summary']['included'] += $v['tax_subtotal']; $cart['products'][$k]['tax_summary']['included'] += $v['tax_subtotal']; } } $group_products[$k]['tax_summary']['total'] = $group_products[$k]['tax_summary']['added'] + $group_products[$k]['tax_summary']['included']; $cart['products'][$k]['tax_summary']['total'] = $cart['products'][$k]['tax_summary']['added'] + $cart['products'][$k]['tax_summary']['included']; } } } // Calculate shipping taxes if (!empty($shipping_rates)) { foreach ($shipping_rates as $shipping_id => $shipping) { $taxes = fn_get_shipping_taxes($shipping_id, $shipping_rates, $cart); if (!empty($taxes)) { $shipping_rates[$shipping_id]['taxes'] = array(); $calculate_rate = true; if (!empty($cart['chosen_shipping'][$group_key]) && $cart['chosen_shipping'][$group_key] == $shipping_id) { $calculated_data['S_' . $group_key . '_' . $shipping_id] = fn_calculate_tax_rates($taxes, $shipping['rate'], 1, $auth, $cart); if (!empty($calculated_data['S_' . $group_key . '_' . $shipping_id])) { foreach ($calculated_data['S_' . $group_key . '_' . $shipping_id] as $__k => $__v) { if ($taxes[$__k]['price_includes_tax'] != 'Y') { $cart['display_shipping_cost'] += Registry::get('settings.Appearance.cart_prices_w_taxes') == 'Y' ? $__v['tax_subtotal'] : 0; $cart['tax_subtotal'] += $__v['tax_subtotal']; } if ($cart['stored_taxes'] == 'Y') { $cart['taxes'][$__k]['applies']['S_' . $group_key . '_' . $shipping_id] = $__v['tax_subtotal']; } } $shipping_rates[$shipping_id]['taxes']['S_' . $group_key . '_' . $shipping_id] = $calculated_data['S_' . $group_key . '_' . $shipping_id]; $calculate_rate = false; } } if ($calculate_rate) { $cur_shipping_rates = fn_calculate_tax_rates($taxes, $shipping['rate'], 1, $auth, $cart); if (!empty($cur_shipping_rates)) { $shipping_rates[$shipping_id]['taxes'] = $cur_shipping_rates; } } } } foreach ($shipping_rates as $shipping_id => $shipping) { // Calculate taxes for each shipping rate $taxes = fn_get_shipping_taxes($shipping_id, $shipping_rates, $cart); $shipping_rates[$shipping_id]['taxed_price'] = 0; unset($shipping_rates[$shipping_id]['inc_tax']); if (!empty($taxes)) { $shipping_rates[$shipping_id]['taxes'] = array(); $tax = fn_calculate_tax_rates($taxes, fn_format_price($shipping['rate']), 1, $auth, $cart); $shipping_rates[$shipping_id]['taxes'] = $tax; if (!empty($tax) && Registry::get('settings.Appearance.cart_prices_w_taxes') == 'Y') { foreach ($tax as $_id => $_tax) { if ($_tax['price_includes_tax'] != 'Y') { $shipping_rates[$shipping_id]['taxed_price'] += $_tax['tax_subtotal']; } } $shipping_rates[$shipping_id]['inc_tax'] = true; } if (!empty($shipping_rates[$shipping_id]['rate']) && $shipping_rates[$shipping_id]['taxed_price'] > 0) { $shipping_rates[$shipping_id]['taxed_price'] += $shipping_rates[$shipping_id]['rate']; } } } } } else { // Tax calculation method based on SUBTOTAL // Calculate discounted subtotal if (!isset($cart['subtotal_discount'])) { $cart['subtotal_discount'] = 0; } $discounted_subtotal = $cart['subtotal'] - $cart['subtotal_discount']; if ($discounted_subtotal < 0) { $discounted_subtotal = 0; } // Get discount distribution coefficient (DDC) between taxes if ($cart['subtotal'] > 0) { $ddc = $discounted_subtotal / $cart['subtotal']; } else { $ddc = 1; } // // Group subtotal by taxes // $subtotal = array(); // Get products taxes foreach ($group_products as $cart_id => $product) { $taxes = fn_get_product_taxes($cart_id, $cart, $group_products); if (!empty($taxes)) { foreach ($taxes as $tax_id => $tax) { if (empty($subtotal[$tax_id])) { $subtotal[$tax_id] = fn_init_tax_subtotals($tax); } $_subtotal = $product['price'] == $product['subtotal'] && $product['amount'] != 1 ? fn_format_price($product['price'] * $product['amount']) : $product['subtotal']; $subtotal[$tax_id]['subtotal'] += $_subtotal; $subtotal[$tax_id]['applies']['P'] += $_subtotal; $subtotal[$tax_id]['applies']['items']['P'][$cart_id] = true; if (isset($product['company_id'])) { if (!isset($subtotal[$tax_id]['group'][$group_key])) { $subtotal[$tax_id]['group'][$group_key]['products'] = 0; } $subtotal[$tax_id]['group'][$group_key]['products'] += $_subtotal; $priority_stack['products'][$group_key] = -1; $applied_taxes['products'][$group_key] = 0; } } } } // Get shipping taxes if (!empty($shipping_rates)) { foreach ($shipping_rates as $shipping_id => $shipping) { // Calculate taxes for each shipping rate $taxes = fn_get_shipping_taxes($shipping_id, $shipping_rates, $cart); $shipping_rates[$shipping_id]['taxed_price'] = 0; unset($shipping_rates[$shipping_id]['inc_tax']); // Display shipping with taxes at cart/checkout page if (!empty($taxes)) { $shipping_rates[$shipping_id]['taxes'] = array(); $tax = fn_calculate_tax_rates($taxes, fn_format_price($shipping['rate']), 1, $auth, $cart); $shipping_rates[$shipping_id]['taxes'] = $tax; if (!empty($tax) && Registry::get('settings.Appearance.cart_prices_w_taxes') == 'Y') { foreach ($tax as $_id => $_tax) { if ($_tax['price_includes_tax'] != 'Y') { $shipping_rates[$shipping_id]['taxed_price'] += $_tax['tax_subtotal']; } } $shipping_rates[$shipping_id]['inc_tax'] = true; } if (!empty($shipping_rates[$shipping_id]['rate']) && $shipping_rates[$shipping_id]['taxed_price'] > 0) { $shipping_rates[$shipping_id]['taxed_price'] += $shipping_rates[$shipping_id]['rate']; } } if (!isset($cart['chosen_shipping'][$group_key]) || $cart['chosen_shipping'][$group_key] != $shipping_id) { continue; } // Add shipping taxes to "tax" array if (!empty($taxes)) { foreach ($taxes as $tax_id => $tax) { if (empty($subtotal[$tax_id])) { $subtotal[$tax_id] = fn_init_tax_subtotals($tax); } $subtotal[$tax_id]['subtotal'] += $shipping['rate']; $subtotal[$tax_id]['applies']['S'] += $shipping['rate']; $subtotal[$tax_id]['applies']['items']['S'][$group_key][$shipping_id] = true; /* if (!isset($subtotal[$tax_id]['groups'][$group_key]['shippings'])) { $subtotal[$tax_id]['groups'][$group_key]['shippings'] = 0; } $subtotal[$tax_id]['groups'][$group_key]['shippings'] += $shipping['rate'];*/ $priority_stack['shippings'][$group_key] = -1; $applied_taxes['shippings'][$group_key] = 0; } } } } if (!empty($subtotal)) { $subtotal = fn_sort_array_by_key($subtotal, 'priority'); } // Apply DDC and calculate tax rates $calculated_taxes = array(); if (empty($priority_stack)) { $priority_stack['products'][0] = -1; $priority_stack['shippings'][0] = -1; $applied_taxes['products'][0] = 0; $applied_taxes['shippings'][0] = 0; } foreach ($subtotal as $tax_id => $_st) { if (empty($_st['tax_id'])) { $_st['tax_id'] = $tax_id; } $product_tax = fn_calculate_tax_rates(array($_st), fn_format_price($_st['applies']['P'] * $ddc), 1, $auth, $cart); $shipping_tax = fn_calculate_tax_rates(array($_st), fn_format_price($_st['applies']['S']), 1, $auth, $cart); if (empty($product_tax) && empty($shipping_tax)) { continue; } if (empty($_st['groups'])) { $_st['groups'][0]['products'] = $_st['applies']['P']; $_st['groups'][0]['shippings'] = $_st['applies']['S']; } foreach ($_st['groups'] as $group_key => $applies) { $apply_tax_stack = array('products' => 0, 'shippings' => 0); if (!isset($priority_stack['products'][$group_key])) { $priority_stack['products'][$group_key] = -1; } if (!isset($priority_stack['shippings'][$group_key])) { $priority_stack['shippings'][$group_key] = -1; } if ($priority_stack['products'][$group_key] < 0 && !empty($applies['products'])) { $priority_stack['products'][$group_key] = $_st['priority']; } elseif (!empty($applies['products']) && $priority_stack['products'][$group_key] != $_st['priority']) { $apply_tax_stack['products'] = $applied_taxes['products'][$group_key]; $priority_stack['products'][$group_key] = $_st['priority']; } if ($priority_stack['shippings'][$group_key] < 0 && !empty($applies['shippings'])) { $priority_stack['shippings'][$group_key] = $_st['priority']; } elseif (!empty($applies['shippings']) && $priority_stack['shippings'][$group_key] != $_st['priority']) { $apply_tax_stack['shippings'] = $applied_taxes['shippings'][$group_key]; $priority_stack['shippings'][$group_key] = $_st['priority']; } if (empty($calculated_data[$tax_id])) { $calculated_data[$tax_id] = empty($product_tax) ? reset($shipping_tax) : reset($product_tax); } if (!empty($applies['products'])) { $products_tax = fn_calculate_tax_rates(array($_st), fn_format_price($applies['products'] * $ddc + $apply_tax_stack['products']), 1, $auth, $cart); } else { $products_tax[$tax_id]['tax_subtotal'] = 0; } if (!empty($applies['shippings'])) { $shippings_tax = fn_calculate_tax_rates(array($_st), fn_format_price($applies['shippings'] + $apply_tax_stack['shippings']), 1, $auth, $cart); } else { $shippings_tax[$tax_id]['tax_subtotal'] = 0; } if (!isset($applied_taxes['products'][$group_key])) { $applied_taxes['products'][$group_key] = 0; } if (!isset($applied_taxes['shippings'][$group_key])) { $applied_taxes['shippings'][$group_key] = 0; } if ($_st['price_includes_tax'] != 'Y') { $applied_taxes['products'][$group_key] += $products_tax[$tax_id]['tax_subtotal']; $applied_taxes['shippings'][$group_key] += $shippings_tax[$tax_id]['tax_subtotal']; } if (!isset($calculated_data[$tax_id]['applies']['P'])) { $calculated_data[$tax_id]['applies']['P'] = 0; } if (!isset($calculated_data[$tax_id]['applies']['S'])) { $calculated_data[$tax_id]['applies']['S'] = 0; } $calculated_data[$tax_id]['applies']['P'] += $products_tax[$tax_id]['tax_subtotal']; $calculated_data[$tax_id]['applies']['S'] += $shippings_tax[$tax_id]['tax_subtotal']; $calculated_data[$tax_id]['applies']['items'] = $_st['applies']['items']; $calculated_data[$tax_id]['tax_subtotal'] = $calculated_data[$tax_id]['applies']['P'] + $calculated_data[$tax_id]['applies']['S']; } } } /** * Processes products data after applying products and shipping taxes to cart) * * @param array $cart Cart data * @param array $group_products Products data * @param array $shipping_rates Shipping rates data * @param array $auth Auth data * @param array $calculated_data Payment taxes data */ fn_set_hook('calculate_taxes_post', $cart, $group_products, $shipping_rates, $auth, $calculated_data); return $calculated_data; }
function fn_calculate_taxes(&$cart, &$cart_products, &$shipping_rates, $auth) { $calculated_data = array(); if (Registry::get('settings.General.tax_calculation') == 'unit_price') { // Tax calculation method based on UNIT PRICE // Calculate product taxes foreach ($cart_products as $k => $product) { $taxes = fn_get_product_taxes($k, $cart, $cart_products); if (empty($taxes)) { continue; } if (isset($product['subtotal'])) { $price = fn_format_price($product['subtotal'] / $product['amount']); $calculated_data['P_' . $k] = fn_calculate_tax_rates($taxes, $price, $product['amount'], $auth, $cart); $cart_products[$k]['tax_summary'] = array('included' => 0, 'added' => 0, 'total' => 0); // tax summary for 1 unit of product // Apply taxes to product subtotal if (!empty($calculated_data['P_' . $k])) { foreach ($calculated_data['P_' . $k] as $_k => $v) { $cart_products[$k]['taxes'][$_k] = $v; if ($taxes[$_k]['price_includes_tax'] != 'Y') { $cart_products[$k]['tax_summary']['added'] += $v['tax_subtotal']; } else { $cart_products[$k]['tax_summary']['included'] += $v['tax_subtotal']; } } $cart_products[$k]['tax_summary']['total'] = $cart_products[$k]['tax_summary']['added'] + $cart_products[$k]['tax_summary']['included']; } } } // Calculate shipping taxes if (!empty($shipping_rates)) { foreach ($shipping_rates as $shipping_id => $shipping) { $taxes = fn_get_shipping_taxes($shipping_id, $shipping_rates, $cart); if (!empty($taxes)) { $shipping_rates[$shipping_id]['taxes'] = array(); $calculate_rate = true; if (!empty($cart['shipping'][$shipping_id])) { foreach ($cart['shipping'][$shipping_id]['rates'] as $k => $v) { $calculated_data['S_' . $shipping_id . '_' . $k] = fn_calculate_tax_rates($taxes, $v, 1, $auth, $cart); if (!empty($calculated_data['S_' . $shipping_id . '_' . $k])) { foreach ($calculated_data['S_' . $shipping_id . '_' . $k] as $__k => $__v) { if ($taxes[$__k]['price_includes_tax'] != 'Y') { $cart['display_shipping_cost'] += Registry::get('settings.Appearance.cart_prices_w_taxes') == 'Y' ? $__v['tax_subtotal'] : 0; $cart['tax_subtotal'] += $__v['tax_subtotal']; } if ($cart['stored_taxes'] == 'Y') { $cart['taxes'][$__k]['applies']['S_' . $shipping_id . '_' . $k] = $__v['tax_subtotal']; } } $shipping_rates[$shipping_id]['taxes']['S_' . $shipping_id . '_' . $k] = $calculated_data['S_' . $shipping_id . '_' . $k]; $calculate_rate = false; } } } if ($calculate_rate) { foreach ($shipping['rates'] as $k => $v) { if (isset($shipping['rates'][$k])) { $cur_shipping_rates = fn_calculate_tax_rates($taxes, $v, 1, $auth, $cart); if (!empty($cur_shipping_rates)) { $shipping_rates[$shipping_id]['taxes']['S_' . $shipping_id . '_' . $k] = $cur_shipping_rates; } } } } } } } } else { // Tax calculation method based on SUBTOTAL // Calculate discounted subtotal if (!isset($cart['subtotal_discount'])) { $cart['subtotal_discount'] = 0; } $discounted_subtotal = $cart['original_subtotal'] - $cart['subtotal_discount']; // Get discount distribution coefficient (DDC) between taxes $ddc = $discounted_subtotal / $cart['original_subtotal']; // // Group subtotal by taxes // $subtotal = array(); // Get products taxes foreach ($cart_products as $k => $product) { $taxes = fn_get_product_taxes($k, $cart, $cart_products); if (!empty($taxes)) { foreach ($taxes as $tax_id => $tax) { if (empty($subtotal[$tax_id])) { $subtotal[$tax_id] = $tax; $subtotal[$tax_id]['subtotal'] = $subtotal[$tax_id]['applies']['P'] = $subtotal[$tax_id]['applies']['S'] = 0; $subtotal[$tax_id]['applies']['items']['P'] = $subtotal[$tax_id]['applies']['items']['S'] = array(); } $subtotal[$tax_id]['subtotal'] += $product['subtotal']; $subtotal[$tax_id]['applies']['P'] += $product['subtotal']; $subtotal[$tax_id]['applies']['items']['P'][$k] = true; } } } // Get shipping taxes if (!empty($shipping_rates)) { foreach ($shipping_rates as $shipping_id => $shipping) { // Calculate taxes for each shipping rate $taxes = fn_get_shipping_taxes($shipping_id, $shipping_rates, $cart); if (!empty($taxes)) { $shipping_rates[$shipping_id]['taxes'] = array(); foreach ($shipping['rates'] as $k => $v) { $tax = fn_calculate_tax_rates($taxes, fn_format_price($v), 1, $auth, $cart); $shipping_rates[$shipping_id]['taxes']['S_' . $shipping_id . '_' . $k] = $tax; } } if (!isset($cart['shipping'][$shipping_id])) { continue; } if (!empty($taxes)) { foreach ($taxes as $tax_id => $tax) { if (empty($subtotal[$tax_id])) { $subtotal[$tax_id] = $tax; $subtotal[$tax_id]['subtotal'] = $subtotal[$tax_id]['applies']['P'] = $subtotal[$tax_id]['applies']['S'] = 0; $subtotal[$tax_id]['applies']['items']['P'] = $subtotal[$tax_id]['applies']['items']['S'] = array(); } $subtotal[$tax_id]['subtotal'] += array_sum($cart['shipping'][$shipping_id]['rates']); $subtotal[$tax_id]['applies']['S'] += array_sum($cart['shipping'][$shipping_id]['rates']); $subtotal[$tax_id]['applies']['items']['S'][$shipping_id] = true; } } } } // Apply DDC and calculate tax rates $calculated_taxes = array(); foreach ($subtotal as $tax_id => $_st) { if (empty($_st['tax_id'])) { $_st['tax_id'] = $tax_id; } $tax = fn_calculate_tax_rates(array($_st), fn_format_price($_st['applies']['P'] * $ddc + $_st['applies']['S']), 1, $auth, $cart); if (empty($tax)) { continue; } $calculated_data[$tax_id] = reset($tax); $products_tax = fn_calculate_tax_rates(array($_st), fn_format_price($_st['applies']['P'] * $ddc), 1, $auth, $cart); $calculated_data[$tax_id]['applies']['P'] = $products_tax[$tax_id]['tax_subtotal']; $shipping_tax = fn_calculate_tax_rates(array($_st), fn_format_price($_st['applies']['S']), 1, $auth, $cart); $calculated_data[$tax_id]['applies']['S'] = $shipping_tax[$tax_id]['tax_subtotal']; $calculated_data[$tax_id]['tax_subtotal'] = $products_tax[$tax_id]['tax_subtotal'] + $shipping_tax[$tax_id]['tax_subtotal']; $calculated_data[$tax_id]['applies']['items'] = $_st['applies']['items']; } } fn_apply_calculated_taxes($calculated_data, $cart); return false; }