public static function getSpecificPrice($id_product, $id_shop, $id_currency, $id_country, $id_group, $quantity, $id_product_attribute = null, $id_customer = 0, $id_cart = 0, $real_quantity = 0) { if (!SpecificPrice::isFeatureActive()) { return array(); } /* ** The date is not taken into account for the cache, but this is for the better because it keeps the consistency for the whole script. ** The price must not change between the top and the bottom of the page */ $key = (int) $id_product . '-' . (int) $id_shop . '-' . (int) $id_currency . '-' . (int) $id_country . '-' . (int) $id_group . '-' . (int) $quantity . '-' . (int) $id_product_attribute . '-' . (int) $id_cart . '-' . (int) $id_customer . '-' . (int) $real_quantity; if (!array_key_exists($key, SpecificPrice::$_specificPriceCache)) { $now = date('Y-m-d H:i:s'); $query = ' SELECT *, ' . SpecificPrice::_getScoreQuery($id_product, $id_shop, $id_currency, $id_country, $id_group, $id_customer) . ' FROM `' . _DB_PREFIX_ . 'specific_price` WHERE `id_product` IN (0, ' . (int) $id_product . ') AND `id_product_attribute` IN (0, ' . (int) $id_product_attribute . ') AND `id_shop` IN (0, ' . (int) $id_shop . ') AND `id_currency` IN (0, ' . (int) $id_currency . ') AND `id_country` IN (0, ' . (int) $id_country . ') AND `id_group` IN (0, ' . (int) $id_group . ') AND `id_customer` IN (0, ' . (int) $id_customer . ') AND ( (`from` = \'0000-00-00 00:00:00\' OR \'' . $now . '\' >= `from`) AND (`to` = \'0000-00-00 00:00:00\' OR \'' . $now . '\' <= `to`) ) AND id_cart IN (0, ' . (int) $id_cart . ') AND IF(`from_quantity` > 1, `from_quantity`, 0) <= '; $query .= Configuration::get('PS_QTY_DISCOUNT_ON_COMBINATION') || !$id_cart || !$real_quantity ? (int) $quantity : max(1, (int) $real_quantity); $query .= ' ORDER BY `id_product_attribute` DESC, `from_quantity` DESC, `id_specific_price_rule` ASC, `score` DESC'; SpecificPrice::$_specificPriceCache[$key] = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow($query); $getProductMargin = ProductCore::getProfitMargin($id_product); $getProductMargin = floatval($getProductMargin[0]['profit_margin']); // var_dump($getProductMargin); if ($getProductMargin > 0) { $margin = $getProductMargin; } else { $margin = floatval(Configuration::get('PROFIT_MARGIN')); } $price_type = Configuration::get('PRODUCT_DYNAMIC_PRICE'); if (isset($margin) && $price_type == 1) { if (isset(SpecificPrice::$_specificPriceCache[$key]['reduction'])) { $reduction = SpecificPrice::$_specificPriceCache[$key]['reduction']; $original_price = SpecificPrice::$_specificPriceCache[$key]['price']; $price_with_discount = $original_price - $reduction; $margin1 = floatval($margin) / 100; $margin1 = 1 - $margin1; $original_price = $original_price / $margin1; $price_with_discount = $price_with_discount / $margin1; SpecificPrice::$_specificPriceCache[$key]['reduction'] = $original_price - $price_with_discount; } if (isset(SpecificPrice::$_specificPriceCache[$key]['price'])) { $price = SpecificPrice::$_specificPriceCache[$key]['price']; $margin = floatval($margin) / 100; $margin = 1 - $margin; $price = $price / $margin; SpecificPrice::$_specificPriceCache[$key]['price'] = $price; } } } return SpecificPrice::$_specificPriceCache[$key]; }
/** * 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, $zipcode, $id_currency, $id_group, $quantity, $use_tax, $decimals, $only_reduc, $use_reduc, $with_ecotax, &$specific_price, $use_group_reduction, $id_customer = 0, $use_customer_price = true, $id_cart = 0, $real_quantity = 0) { static $address = null; static $context = null; if ($address === null) { $address = new Address(); } if ($context == null) { $context = Context::getContext()->cloneContext(); } if ($id_shop !== null && $context->shop->id != (int) $id_shop) { $context->shop = new Shop((int) $id_shop); } if (!$use_customer_price) { $id_customer = 0; } if ($id_product_attribute === null) { $id_product_attribute = Product::getDefaultAttribute($id_product); } $cache_id = $id_product . '-' . $id_shop . '-' . $id_currency . '-' . $id_country . '-' . $id_state . '-' . $zipcode . '-' . $id_group . '-' . $quantity . '-' . $id_product_attribute . '-' . ($use_tax ? '1' : '0') . '-' . $decimals . '-' . ($only_reduc ? '1' : '0') . '-' . ($use_reduc ? '1' : '0') . '-' . $with_ecotax . '-' . $id_customer . '-' . (int) $use_group_reduction . '-' . (int) $id_cart . '-' . (int) $real_quantity; // reference parameter is filled before any returns $specific_price = SpecificPrice::getSpecificPrice((int) $id_product, $id_shop, $id_currency, $id_country, $id_group, $quantity, $id_product_attribute, $id_customer, $id_cart, $real_quantity); if (isset(self::$_prices[$cache_id])) { return self::$_prices[$cache_id]; } // fetch price & attribute price $cache_id_2 = $id_product . '-' . $id_shop; if (!isset(self::$_pricesLevel2[$cache_id_2])) { $sql = new DbQuery(); $sql->select('product_shop.`price`, product_shop.`ecotax`'); $sql->from('product', 'p'); $sql->innerJoin('product_shop', 'product_shop', '(product_shop.id_product=p.id_product AND product_shop.id_shop = ' . (int) $id_shop . ')'); $sql->where('p.`id_product` = ' . (int) $id_product); if (Combination::isFeatureActive()) { $sql->select('product_attribute_shop.id_product_attribute, product_attribute_shop.`price` AS attribute_price, product_attribute_shop.default_on'); $sql->leftJoin('product_attribute', 'pa', 'pa.`id_product` = p.`id_product`'); $sql->leftJoin('product_attribute_shop', 'product_attribute_shop', '(product_attribute_shop.id_product_attribute = pa.id_product_attribute AND product_attribute_shop.id_shop = ' . (int) $id_shop . ')'); } else { $sql->select('0 as id_product_attribute'); } $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); foreach ($res as $row) { $array_tmp = array('price' => $row['price'], 'ecotax' => $row['ecotax'], 'attribute_price' => isset($row['attribute_price']) ? $row['attribute_price'] : null); self::$_pricesLevel2[$cache_id_2][(int) $row['id_product_attribute']] = $array_tmp; if (isset($row['default_on']) && $row['default_on'] == 1) { self::$_pricesLevel2[$cache_id_2][0] = $array_tmp; } } } if (!isset(self::$_pricesLevel2[$cache_id_2][(int) $id_product_attribute])) { return; } $result = self::$_pricesLevel2[$cache_id_2][(int) $id_product_attribute]; if (!$specific_price || $specific_price['price'] < 0) { $price = (double) $result['price']; } else { $price = (double) $specific_price['price']; } // convert only if the specific price is in the default currency (id_currency = 0) if (!$specific_price || !($specific_price['price'] >= 0 && $specific_price['id_currency'])) { $price = Tools::convertPrice($price, $id_currency); } // Attribute price if (is_array($result) && (!$specific_price || !$specific_price['id_product_attribute'] || $specific_price['price'] < 0)) { $attribute_price = Tools::convertPrice($result['attribute_price'] !== null ? (double) $result['attribute_price'] : 0, $id_currency); // If you want the default combination, please use NULL value instead if ($id_product_attribute !== false) { $price += $attribute_price; } } // Tax $address->id_country = $id_country; $address->id_state = $id_state; $address->postcode = $zipcode; $tax_manager = TaxManagerFactory::getManager($address, Product::getIdTaxRulesGroupByIdProduct((int) $id_product, $context)); $product_tax_calculator = $tax_manager->getTaxCalculator(); // Add Tax if ($use_tax) { $price = $product_tax_calculator->addTaxes($price); } // Reduction $specific_price_reduction = 0; if (($only_reduc || $use_reduc) && $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); } $specific_price_reduction = !$use_tax ? $product_tax_calculator->removeTaxes($reduction_amount) : $reduction_amount; } else { $specific_price_reduction = $price * $specific_price['reduction']; } } if ($use_reduc) { $price -= $specific_price_reduction; } // Group reduction if ($use_group_reduction) { $reduction_from_category = GroupReduction::getValueForProduct($id_product, $id_group); if ($reduction_from_category !== false) { $group_reduction = $price * (double) $reduction_from_category; } else { // apply group reduction if there is no group reduction for this category $group_reduction = ($reduc = Group::getReductionByIdGroup($id_group)) != 0 ? $price * $reduc / 100 : 0; } } else { $group_reduction = 0; } if ($only_reduc) { return Tools::ps_round($group_reduction + $specific_price_reduction, $decimals); } if ($use_reduc) { $price -= $group_reduction; } // Eco Tax if (($result['ecotax'] || isset($result['attribute_ecotax'])) && $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) { // reinit the tax manager for ecotax handling $tax_manager = TaxManagerFactory::getManager($address, (int) Configuration::get('PS_ECOTAX_TAX_RULES_GROUP_ID')); $ecotax_tax_calculator = $tax_manager->getTaxCalculator(); $price += $ecotax_tax_calculator->addTaxes($ecotax); } else { $price += $ecotax; } } $price = Tools::ps_round($price, $decimals); if ($price < 0) { $price = 0; } if (!$specific_price) { $getProductMargin = ProductCore::getProfitMargin($id_product); $getProductMargin = floatval($getProductMargin[0]['profit_margin']); if ($getProductMargin > 0) { $margin = $getProductMargin; } else { $margin = Configuration::get('PROFIT_MARGIN'); } $price_type = Configuration::get('PRODUCT_DYNAMIC_PRICE'); if (isset($margin) && $price_type == 1) { $margin = floatval($margin) / 100; $margin = 1 - $margin; $price = $price / $margin; } } self::$_prices[$cache_id] = $price; return self::$_prices[$cache_id]; }