/** * Adjusts the price from get_price for the selected attributes * @author Nathan Hyde <*****@*****.**> * @author curlyroger from his post at <http://www.phpshop.org/phpbb/viewtopic.php?t=3052> * * @param int $product_id * @param string $description * @return array The adjusted price information */ function get_adjusted_attribute_price($product_id, $description = '') { global $mosConfig_secret; $auth = $_SESSION['auth']; $price = $this->get_price($product_id); $base_price = $price["product_price"]; $setprice = 0; $set_price = false; $adjustment = 0; // We must care for custom attribute fields! Their value can be freely given // by the customer, so we mustn't include them into the price calculation // Thanks to AryGroup@ua.fm for the good advice if (empty($_REQUEST["custom_attribute_fields"])) { if (!empty($_SESSION["custom_attribute_fields"])) { $custom_attribute_fields = vmGet($_SESSION, "custom_attribute_fields", array()); $custom_attribute_fields_check = vmGet($_SESSION, "custom_attribute_fields_check", array()); } else { $custom_attribute_fields = $custom_attribute_fields_check = array(); } } else { $custom_attribute_fields = $_SESSION["custom_attribute_fields"] = vmGet($_REQUEST, "custom_attribute_fields", array()); $custom_attribute_fields_check = $_SESSION["custom_attribute_fields_check"] = vmGet($_REQUEST, "custom_attribute_fields_check", array()); } // if we've been given a description to deal with, get the adjusted price if ($description != '') { // description is safe to use at this point cause it's set to '' require_once CLASSPATH . 'ps_product_attribute.php'; $product_attributes = ps_product_attribute::getAdvancedAttributes($product_id, true); $attribute_keys = explode(";", $description); for ($i = 0; $i < sizeof($attribute_keys); $i++) { $temp_desc = $attribute_keys[$i]; $temp_desc = trim($temp_desc); // Get the key name (e.g. "Color" ) $this_key = substr($temp_desc, 0, strpos($temp_desc, ":")); $this_value = substr($temp_desc, strpos($temp_desc, ":") + 1); if (in_array($this_key, $custom_attribute_fields)) { if (@$custom_attribute_fields_check[$this_key] == md5($mosConfig_secret . $this_key)) { // the passed value is valid, don't use it for calculating prices continue; } } if (isset($product_attributes[$this_key]['values'][$this_value])) { $modifier = $product_attributes[$this_key]['values'][$this_value]['adjustment']; $operand = $product_attributes[$this_key]['values'][$this_value]['operand']; // if we have a number, allow the adjustment if (true == is_numeric($modifier)) { // Now add or sub the modifier on if ($operand == "+") { $adjustment += $modifier; } else { if ($operand == "-") { $adjustment -= $modifier; } else { if ($operand == '=') { // NOTE: the +=, so if we have 2 sets they get added // this could be moded to say, if we have a set_price, then // calc the diff from the base price and start from there if we encounter // another set price... just a thought. $setprice += $modifier; $set_price = true; } } } } } else { continue; } } } // no set price was set from the attribs if ($set_price == false) { $price["product_price"] = $base_price + $adjustment * (1 - $auth["shopper_group_discount"] / 100); } else { // otherwise, set the price // add the base price to the price set in the attributes // then subtract the adjustment amount // we could also just add the set_price to the adjustment... not sure on that one. if (!empty($adjustment)) { $setprice += $adjustment; } $setprice *= 1 - $auth["shopper_group_discount"] / 100; $price["product_price"] = $setprice; } // don't let negative prices get by, set to 0 if ($price["product_price"] < 0) { $price["product_price"] = 0; } // Get the DISCOUNT AMOUNT $discount_info = $this->get_discount($product_id); $my_taxrate = $this->get_product_taxrate($product_id); // If discounts are applied after tax, but prices are shown without tax, // AND tax is EU mode and shopper is not in the EU, // then ps_product::get_product_taxrate() returns 0, so $my_taxrate = 0. // But, the discount still needs to be reduced by the shopper's tax rate, so we obtain it here: if (PAYMENT_DISCOUNT_BEFORE != '1' && $auth["show_price_including_tax"] != 1 && !ps_checkout::tax_based_on_vendor_address()) { $db = new ps_DB(); $ps_vendor_id = $_SESSION["ps_vendor_id"]; require_once CLASSPATH . 'ps_checkout.php'; if (!ps_checkout::tax_based_on_vendor_address()) { if ($auth["user_id"] > 0) { $q = "SELECT state, country FROM #__{vm}_user_info WHERE user_id='" . $auth["user_id"] . "'"; $db->query($q); $db->next_record(); $state = $db->f("state"); $country = $db->f("country"); $q = "SELECT tax_rate FROM #__{vm}_tax_rate WHERE tax_country='{$country}' "; if (!empty($state)) { $q .= "AND (tax_state='{$state}' OR tax_state=' {$state} ' OR tax_state='-')"; } $db->query($q); if ($db->next_record()) { $my_taxrate = $db->f("tax_rate"); } else { $my_taxrate = 0; } } else { $my_taxrate = 0; } } else { if (empty($_SESSION['taxrate'][$ps_vendor_id])) { // let's get the store's tax rate $q = "SELECT `tax_rate` FROM #__{vm}_vendor, #__{vm}_tax_rate "; $q .= "WHERE tax_country=vendor_country AND #__{vm}_vendor.vendor_id=1 "; // !! Important !! take the highest available tax rate for the store's country $q .= "ORDER BY `tax_rate` DESC"; $db->query($q); if ($db->next_record()) { $my_taxrate = $db->f("tax_rate"); } else { $my_taxrate = 0; } } } } // Apply the discount if (!empty($discount_info["amount"])) { $undiscounted_price = $base_price; switch ($discount_info["is_percent"]) { case 0: if (PAYMENT_DISCOUNT_BEFORE == '1') { // If we subtract discounts BEFORE tax // Subtract the whole discount $price["product_price"] -= $discount_info["amount"]; } else { // But, if we subtract discounts AFTER tax // Subtract the untaxed portion of the discount $price["product_price"] -= $discount_info["amount"] / ($my_taxrate + 1); } break; case 1: $price["product_price"] -= $price["product_price"] * ($discount_info["amount"] / 100); break; } } return $price; }
/** * Calculate the tax charges for the current order. * You can switch the way, taxes are calculated: * either based on the VENDOR address, * or based on the ship-to address. * ! Creates the global $order_tax_details * * @param float $order_taxable * @param array $d * @return float */ function calc_order_tax($order_taxable, $d) { global $order_tax_details, $discount_factor; $total = 0; $order_tax = 0; $auth = $_SESSION['auth']; $ps_vendor_id = $_SESSION["ps_vendor_id"]; $db = new ps_DB(); $ship_to_info_id = vmGet($_REQUEST, 'ship_to_info_id'); require_once CLASSPATH . 'ps_tax.php'; $ps_tax = new ps_tax(); $discount_factor = 1; // Shipping address based TAX if (!ps_checkout::tax_based_on_vendor_address()) { $q = "SELECT state, country FROM #__{vm}_user_info "; $q .= "WHERE user_info_id='" . $ship_to_info_id . "'"; $db->query($q); $db->next_record(); $state = $db->f("state"); $country = $db->f("country"); $q = "SELECT * FROM #__{vm}_tax_rate WHERE tax_country='{$country}' "; if (!empty($state)) { $q .= "AND (tax_state='{$state}' OR tax_state=' {$state} ')"; } $db->query($q); if ($db->next_record()) { $rate = $order_taxable * floatval($db->f("tax_rate")); if (empty($rate)) { $order_tax = 0.0; } else { $cart = $_SESSION['cart']; $order_tax = 0.0; if ((!empty($_SESSION['coupon_discount']) || !empty($d['payment_discount'])) && PAYMENT_DISCOUNT_BEFORE == '1') { require_once CLASSPATH . 'ps_product.php'; $ps_product = new ps_product(); for ($i = 0; $i < $cart["idx"]; $i++) { $item_weight = ps_shipping_method::get_weight($cart[$i]["product_id"]) * $cart[$i]['quantity']; if ($item_weight != 0 or TAX_VIRTUAL) { $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]); $price['product_price'] = $GLOBALS['CURRENCY']->convert($price['product_price'], $price['product_currency']); $tax_rate = $db->f("tax_rate"); $use_coupon_discount = @$_SESSION['coupon_discount']; //if( !empty( $_SESSION['coupon_discount'] )) { // if( $auth["show_price_including_tax"] == 1 ) { // $use_coupon_discount = $_SESSION['coupon_discount'] / ($tax_rate+1); // } //} $factor = 100 * ($use_coupon_discount + @$d['payment_discount']) / $this->_subtotal; $price["product_price"] = $price["product_price"] - $factor * $price["product_price"] / 100; @($order_tax_details[$tax_rate] += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]); $order_tax += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]; $total += $price["product_price"] * $cart[$i]["quantity"]; } else { $order_tax += 0.0; } } } else { $order_tax = $rate; } } } else { $order_tax = 0.0; } $order_tax_details[$db->f('tax_rate')] = $order_tax; } else { // Calculate the Tax with a tax rate for every product $cart = $_SESSION['cart']; $order_tax = 0.0; $total = 0.0; if ((!empty($_SESSION['coupon_discount']) || !empty($d['payment_discount'])) && PAYMENT_DISCOUNT_BEFORE == '1') { // We need to recalculate the tax details when the discounts are applied // BEFORE taxes - because they affect the product subtotals then $order_tax_details = array(); } require_once CLASSPATH . 'ps_product.php'; $ps_product = new ps_product(); require_once CLASSPATH . 'ps_shipping_method.php'; for ($i = 0; $i < $cart["idx"]; $i++) { $item_weight = ps_shipping_method::get_weight($cart[$i]["product_id"]) * $cart[$i]['quantity']; if ($item_weight != 0 or TAX_VIRTUAL) { $price = $ps_product->get_adjusted_attribute_price($cart[$i]["product_id"], $cart[$i]["description"]); $price['product_price'] = $GLOBALS['CURRENCY']->convert($price['product_price'], $price['product_currency']); $tax_rate = $ps_product->get_product_taxrate($cart[$i]["product_id"]); if ((!empty($_SESSION['coupon_discount']) || !empty($d['payment_discount'])) && PAYMENT_DISCOUNT_BEFORE == '1') { $use_coupon_discount = @$_SESSION['coupon_discount']; if (!empty($_SESSION['coupon_discount'])) { if ($auth["show_price_including_tax"] == 1) { $use_coupon_discount = $_SESSION['coupon_discount'] / ($tax_rate + 1); } } $factor = 100 * ($use_coupon_discount + @$d['payment_discount']) / $this->_subtotal; $price["product_price"] = $price["product_price"] - $factor * $price["product_price"] / 100; @($order_tax_details[$tax_rate] += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]); } $order_tax += $price["product_price"] * $tax_rate * $cart[$i]["quantity"]; $total += $price["product_price"] * $cart[$i]["quantity"]; } } if ((!empty($_SESSION['coupon_discount']) || !empty($d['payment_discount'])) && PAYMENT_DISCOUNT_BEFORE != '1') { // Here we need to re-calculate the Discount // because we assume the Discount is "including Tax" $discounted_total = @$d['order_subtotal_withtax'] - @$_SESSION['coupon_discount'] - @$d['payment_discount']; if ($discounted_total != @$d['order_subtotal_withtax'] && @$d['order_subtotal_withtax'] > 0.0) { $discount_factor = $discounted_total / $d['order_subtotal_withtax']; foreach ($order_tax_details as $rate => $value) { $order_tax_details[$rate] = $value * $discount_factor; } } } if (is_object($this->_SHIPPING)) { $taxrate = $this->_SHIPPING->get_tax_rate(); if ($taxrate) { $rate = $this->_SHIPPING->get_rate($d); if ($auth["show_price_including_tax"] == 1) { @($order_tax_details[$taxrate] += $rate - $rate / ($taxrate + 1)); } else { @($order_tax_details[$taxrate] += $rate * $taxrate); } } } } return round($order_tax, 2); }
//} // SHOW TAX $tax_display = ''; // mauri start if (empty($_REQUEST['ship_to_info_id']) && $auth["user_id"] > 0 && !ps_checkout::tax_based_on_vendor_address()) { $db = new ps_DB(); $q = "SELECT user_info_id FROM #__{vm}_user_info "; $q .= "WHERE user_id = '" . $auth["user_id"] . "' "; $q .= "AND address_type = 'BT' "; $db->query($q); $db->next_record(); $_REQUEST['ship_to_info_id'] = $db->f("user_info_id"); ps_checkout::tax_based_on_vendor_address($_REQUEST['ship_to_info_id']); } // mauri end if (!empty($_REQUEST['ship_to_info_id']) || ps_checkout::tax_based_on_vendor_address()) { $show_tax = true; if ($weight_total != 0 or TAX_VIRTUAL == '1') { $order_taxable = $ps_checkout->calc_order_taxable($vars); $tax_total = $ps_checkout->calc_order_tax($order_taxable, $vars); } else { $tax_total = 0; } if ($auth['show_price_including_tax']) { $tax_total *= $discount_factor; } $tax_total += $shipping_tax; $tax_total = round($tax_total, 5); $tax_display = $GLOBALS['CURRENCY_DISPLAY']->getFullValue($tax_total); $tax_display .= ps_checkout::show_tax_details($order_tax_details); }