/** * Return the product tax rate * * @param integer $id_product * @param integer $id_address * @return Tax */ public static function getProductTaxRate($id_product, $id_address = null) { $id_country = (int) Country::getDefaultCountryId(); $id_state = 0; $id_county = 0; $rate = 0; if (!empty($id_address)) { $address_infos = Address::getCountryAndState($id_address); if ($address_infos['id_country']) { $id_country = (int) $address_infos['id_country']; $id_state = (int) $address_infos['id_state']; $id_county = (int) County::getIdCountyByZipCode($address_infos['id_state'], $address_infos['postcode']); } if (!empty($address_infos['vat_number']) && $address_infos['id_country'] != Configuration::get('VATNUMBER_COUNTRY') && Configuration::get('VATNUMBER_MANAGEMENT')) { return 0; } } return Tax::getProductTaxRateViaRules((int) $id_product, (int) $id_country, (int) $id_state, (int) $id_county); }
/** * Price calculation / Get product price * * @param integer $id_shop Shop id * @param integer $id_product Product id * @param integer $id_product_attribute Product attribute id * @param integer $id_country Country id * @param integer $id_state State id * @param integer $id_currency Currency id * @param integer $id_group Group id * @param integer $quantity Quantity Required for Specific prices : quantity discount application * @param boolean $use_tax with (1) or without (0) tax * @param integer $decimals Number of decimals returned * @param boolean $only_reduc Returns only the reduction amount * @param boolean $use_reduc Set if the returned amount will include reduction * @param boolean $with_ecotax insert ecotax in price output. * @param variable_reference $specific_price_output If a specific price applies regarding the previous parameters, this variable is filled with the corresponding SpecificPrice object * @return float Product price **/ public static function priceCalculation($id_shop, $id_product, $id_product_attribute, $id_country, $id_state, $id_county, $id_currency, $id_group, $quantity, $use_tax, $decimals, $only_reduc, $use_reduc, $with_ecotax, &$specific_price, $use_groupReduction) { // Caching if ($id_product_attribute === NULL) { $product_attribute_label = 'NULL'; } else { $product_attribute_label = $id_product_attribute === false ? 'false' : $id_product_attribute; } $cacheId = $id_product . '-' . $id_shop . '-' . $id_currency . '-' . $id_country . '-' . $id_state . '-' . $id_county . '-' . $id_group . '-' . $quantity . '-' . $product_attribute_label . '-' . ($use_tax ? '1' : '0') . '-' . $decimals . '-' . ($only_reduc ? '1' : '0') . '-' . ($use_reduc ? '1' : '0') . '-' . $with_ecotax; // reference parameter is filled before any returns $specific_price = SpecificPrice::getSpecificPrice((int) $id_product, $id_shop, $id_currency, $id_country, $id_group, $quantity); if (isset(self::$_prices[$cacheId])) { return self::$_prices[$cacheId]; } // fetch price & attribute price $cacheId2 = $id_product . '-' . $id_product_attribute; if (!isset(self::$_pricesLevel2[$cacheId2])) { self::$_pricesLevel2[$cacheId2] = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' SELECT p.`price`, ' . ($id_product_attribute ? 'pa.`price`' : 'IFNULL((SELECT pa.price FROM `' . _DB_PREFIX_ . 'product_attribute` pa WHERE id_product = ' . (int) $id_product . ' AND default_on = 1), 0)') . ' AS attribute_price, p.`ecotax` ' . ($id_product_attribute ? ', pa.`ecotax` AS attribute_ecotax' : '') . ' FROM `' . _DB_PREFIX_ . 'product` p ' . ($id_product_attribute ? 'LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON pa.`id_product_attribute` = ' . (int) $id_product_attribute : '') . ' WHERE p.`id_product` = ' . (int) $id_product); } $result = self::$_pricesLevel2[$cacheId2]; $price = (double) (!$specific_price or $specific_price['price'] == 0) ? $result['price'] : $specific_price['price']; // convert only if the specific price is in the default currency (id_currency = 0) if (!$specific_price or !($specific_price['price'] > 0 and $specific_price['id_currency'])) { $price = Tools::convertPrice($price, $id_currency); } // Attribute price $attribute_price = Tools::convertPrice(array_key_exists('attribute_price', $result) ? (double) $result['attribute_price'] : 0, $id_currency); if ($id_product_attribute !== false) { // If you want the default combination, please use NULL value instead $price += $attribute_price; } // TaxRate calculation $tax_rate = Tax::getProductTaxRateViaRules((int) $id_product, (int) $id_country, (int) $id_state, (int) $id_county); if ($tax_rate === false) { $tax_rate = 0; } // Add Tax if ($use_tax) { $price = $price * (1 + $tax_rate / 100); } $price = Tools::ps_round($price, $decimals); // Reduction $reduc = 0; if (($only_reduc or $use_reduc) and $specific_price) { if ($specific_price['reduction_type'] == 'amount') { $reduction_amount = $specific_price['reduction']; if (!$specific_price['id_currency']) { $reduction_amount = Tools::convertPrice($reduction_amount, $id_currency); } $reduc = Tools::ps_round(!$use_tax ? $reduction_amount / (1 + $tax_rate / 100) : $reduction_amount, $decimals); } else { $reduc = Tools::ps_round($price * $specific_price['reduction'], $decimals); } } if ($only_reduc) { return $reduc; } if ($use_reduc) { $price -= $reduc; } // Group reduction if ($use_groupReduction) { if ($reductionFromCategory = (double) GroupReduction::getValueForProduct($id_product, $id_group)) { $price -= $price * $reductionFromCategory; } else { // apply group reduction if there is no group reduction for this category $price *= (100 - Group::getReductionByIdGroup($id_group)) / 100; } } $price = Tools::ps_round($price, $decimals); // Eco Tax if (($result['ecotax'] or isset($result['attribute_ecotax'])) and $with_ecotax) { $ecotax = $result['ecotax']; if (isset($result['attribute_ecotax']) && $result['attribute_ecotax'] > 0) { $ecotax = $result['attribute_ecotax']; } if ($id_currency) { $ecotax = Tools::convertPrice($ecotax, $id_currency); } if ($use_tax) { $taxRate = TaxRulesGroup::getTaxesRate((int) Configuration::get('PS_ECOTAX_TAX_RULES_GROUP_ID'), (int) $id_country, (int) $id_state, (int) $id_county); $price += $ecotax * (1 + $taxRate / 100); } else { $price += $ecotax; } } $price = Tools::ps_round($price, $decimals); if ($price < 0) { $price = 0; } self::$_prices[$cacheId] = $price; return self::$_prices[$cacheId]; }
public static function getPriceRangeForSearchBloc($search, $id_criterion_group, $id_currency, $id_country, $id_group, $count_product = false, $selected_criterion = array(), $selected_criteria_groups_type = array()) { global $cookie; if (!$id_country) { $id_country = (int) (version_compare(_PS_VERSION_, '1.5.0.0', '>=') ? Context::getContext()->country->id : Country::getDefaultCountryId()); } $search['display_empty_criteria'] = false; $leftJoinWhereCriterion = self::makeLeftJoinWhereCriterion('getPriceRangeForSearchBloc', $search, $cookie->id_lang, $selected_criterion, $selected_criteria_groups_type, $id_criterion_group, false, $id_currency, $id_country, $id_group, true, true); $now = date('Y-m-d H:i:s'); $minIdProduct = self::getMinIdProductSlider($search, $id_criterion_group, $id_currency, $id_country, $id_group, $count_product, $selected_criterion, $selected_criteria_groups_type); list($taxConversion, $taxConversionForReduction, $specificPriceCondition, $specificPriceGroupCondition) = self::getPriceRangeConditions($id_group); if ($leftJoinWhereCriterion['nbSelectedCriterions'] > 0 && ($leftJoinWhereCriterion['priceIncluded'] || $leftJoinWhereCriterion['productTableIncluded'])) { $specificPriceCondition .= $specificPriceGroupCondition; } $return = array(); $query_min = 'SELECT app.price_wt as min_price, app.`reduction_amount`, app.`reduction_type`, app.`reduction_tax`, app.id_currency, acp.id_product, app.id_country, ' . self::_getScoreQuery(version_compare(_PS_VERSION_, '1.5.0.0', '>=') ? Context::getContext()->shop->id : 0, $id_currency, $id_country, $id_group, true, true) . ' FROM `' . _DB_PREFIX_ . 'pm_advancedsearch_product_price_' . (int) $search['id_search'] . '` app LEFT JOIN `' . _DB_PREFIX_ . 'pm_advancedsearch_cache_product_' . (int) $search['id_search'] . '` acp ON (app.`id_cache_product` = acp.`id_cache_product`)' . (AdvancedSearchCoreClass::_isFilledArray($leftJoinWhereCriterion['join']) ? implode(' ', $leftJoinWhereCriterion['join']) : '') . ' WHERE acp.`id_product` = ' . (int) $minIdProduct . ' AND ' . ' ((app.`from` = \'0000-00-00 00:00:00\' OR \'' . $now . '\' >= app.`from`) AND (app.`to` = \'0000-00-00 00:00:00\' OR \'' . $now . '\' <= app.`to`)) AND ' . ' ((app.`valid_id_specific_price`=1 AND app.`is_specific`=1 AND app.`id_currency` IN (0, ' . (int) $id_currency . ')) OR app.`has_no_specific`=1) AND ' . (AdvancedSearchCoreClass::_isFilledArray($leftJoinWhereCriterion['where']) ? implode(' AND ', $leftJoinWhereCriterion['where']) : ' 1 ') . ' AND app.`id_country` IN (0, ' . (int) $id_country . ') ' . ' AND app.`id_group` IN (0, ' . (int) $id_group . ') ' . (version_compare(_PS_VERSION_, '1.5.0.0', '>=') ? ' AND app.`id_shop` IN (0, ' . implode(', ', Shop::getContextListShopID()) . ') ' : '') . ' ORDER BY score DESC, ' . $specificPriceCondition . ' ASC'; $row = Db::getInstance()->getRow($query_min); if (version_compare(_PS_VERSION_, '1.5.0.0', '>=')) { $tax_rate = Tax::getProductTaxRate((int) $row['id_product']); } else { $tax_rate = Tax::getProductTaxRateViaRules((int) $row['id_product'], (int) $id_country, 0, 0); if ($tax_rate === false) { $tax_rate = 0; } } $reduction_amount = $row['reduction_amount']; $reduction_type = $row['reduction_type']; $reduction_tax = $row['reduction_tax']; if (floor($row['min_price']) == 0) { $reduction_amount = 0; } if (Product::$_taxCalculationMethod != PS_TAX_EXC) { if ($reduction_type == 'amount') { if (!$reduction_tax) { $reduction_amount = $reduction_amount * (1 + $tax_rate / 100); } $price_ttc = $row['min_price'] * (1 + $tax_rate / 100) - $reduction_amount; } else { $price_ttc = ($row['min_price'] - $reduction_amount) * (1 + $tax_rate / 100); } $return[0]['min_price'] = floor($price_ttc); } else { if ($reduction_type == 'amount') { if ($reduction_tax) { $reduction_amount = $reduction_amount / (1 + $tax_rate / 100); } } $return[0]['min_price'] = floor($row['min_price'] - $reduction_amount); } $return[0]['min_price_id_currency'] = $row['id_currency']; $return[0]['min_price'] = self::getGroupReducedPrice((int) $row['id_product'], $id_group, $return[0]['min_price']); $maxIdProduct = self::getMaxIdProductSlider($search, $id_criterion_group, $id_currency, $id_country, $id_group, $count_product, $selected_criterion, $selected_criteria_groups_type); $query_max = 'SELECT app.price_wt as max_price, app.`reduction_amount`, app.`reduction_type`, app.`reduction_tax`, acp.id_product, app.id_currency, app.id_country, ' . self::_getScoreQuery(version_compare(_PS_VERSION_, '1.5.0.0', '>=') ? Context::getContext()->shop->id : 0, $id_currency, $id_country, $id_group, true, true) . ' FROM `' . _DB_PREFIX_ . 'pm_advancedsearch_product_price_' . (int) $search['id_search'] . '` app LEFT JOIN `' . _DB_PREFIX_ . 'pm_advancedsearch_cache_product_' . (int) $search['id_search'] . '` acp ON (app.`id_cache_product` = acp.`id_cache_product`)' . (AdvancedSearchCoreClass::_isFilledArray($leftJoinWhereCriterion['join']) ? implode(' ', $leftJoinWhereCriterion['join']) : '') . ' WHERE acp.`id_product` = ' . (int) $maxIdProduct . ' AND ' . ' ((app.`from` = \'0000-00-00 00:00:00\' OR \'' . $now . '\' >= app.`from`) AND (app.`to` = \'0000-00-00 00:00:00\' OR \'' . $now . '\' <= app.`to`)) AND ' . ' ((app.`valid_id_specific_price`=1 AND app.`is_specific`=1 AND app.`id_currency` IN (0, ' . (int) $id_currency . ')) OR app.`has_no_specific`=1) AND ' . (AdvancedSearchCoreClass::_isFilledArray($leftJoinWhereCriterion['where']) ? implode(' AND ', $leftJoinWhereCriterion['where']) : ' 1 ') . ' AND app.`id_country` IN (0, ' . (int) $id_country . ') ' . ' AND app.`id_group` IN (0, ' . (int) $id_group . ') ' . (version_compare(_PS_VERSION_, '1.5.0.0', '>=') ? ' AND app.`id_shop` IN (0, ' . implode(', ', Shop::getContextListShopID()) . ') ' : '') . ' ORDER BY score DESC, ' . $specificPriceCondition . ' DESC'; $row = Db::getInstance()->getRow($query_max); if (version_compare(_PS_VERSION_, '1.5.0.0', '>=')) { $tax_rate = Tax::getProductTaxRate((int) $row['id_product']); } else { $tax_rate = Tax::getProductTaxRateViaRules((int) $row['id_product'], (int) $id_country, 0, 0); if ($tax_rate === false) { $tax_rate = 0; } } $reduction_amount = $row['reduction_amount']; $reduction_type = $row['reduction_type']; $reduction_tax = $row['reduction_tax']; if (Product::$_taxCalculationMethod != PS_TAX_EXC) { if ($reduction_type == 'amount') { if (!$reduction_tax) { $reduction_amount = $reduction_amount * (1 + $tax_rate / 100); } $price_ttc = $row['max_price'] * (1 + $tax_rate / 100) - $reduction_amount; } else { $price_ttc = ($row['max_price'] - $reduction_amount) * (1 + $tax_rate / 100); } $return[0]['max_price'] = ceil($price_ttc); } else { if ($reduction_type == 'amount') { if ($reduction_tax) { $reduction_amount = $reduction_amount / (1 + $tax_rate / 100); } } $return[0]['max_price'] = ceil($row['max_price'] - $reduction_amount); } $return[0]['max_price_id_currency'] = $row['id_currency']; $return[0]['max_price'] = self::getGroupReducedPrice((int) $row['id_product'], $id_group, $return[0]['max_price']); return $return; }