%PDF- %PDF-
Direktori : /home/bitrix/www/bitrix/modules/catalog/general/ |
Current File : /home/bitrix/www/bitrix/modules/catalog/general/product.php |
<? /** @global \CMain $APPLICATION */ use Bitrix\Main\Localization\Loc, Bitrix\Main, Bitrix\Currency, Bitrix\Catalog, Bitrix\Sale; Loc::loadMessages(__FILE__); class CAllCatalogProduct { const TYPE_PRODUCT = Catalog\ProductTable::TYPE_PRODUCT; const TYPE_SET = Catalog\ProductTable::TYPE_SET; const TYPE_SKU = Catalog\ProductTable::TYPE_SKU; const TYPE_OFFER = Catalog\ProductTable::TYPE_OFFER; const TYPE_FREE_OFFER = Catalog\ProductTable::TYPE_FREE_OFFER; const TYPE_EMPTY_SKU = Catalog\ProductTable::TYPE_EMPTY_SKU; const TIME_PERIOD_HOUR = Catalog\ProductTable::PAYMENT_PERIOD_HOUR; const TIME_PERIOD_DAY = Catalog\ProductTable::PAYMENT_PERIOD_DAY; const TIME_PERIOD_WEEK = Catalog\ProductTable::PAYMENT_PERIOD_WEEK; const TIME_PERIOD_MONTH = Catalog\ProductTable::PAYMENT_PERIOD_MONTH; const TIME_PERIOD_QUART = Catalog\ProductTable::PAYMENT_PERIOD_QUART; const TIME_PERIOD_SEMIYEAR = Catalog\ProductTable::PAYMENT_PERIOD_SEMIYEAR; const TIME_PERIOD_YEAR = Catalog\ProductTable::PAYMENT_PERIOD_YEAR; const TIME_PERIOD_DOUBLE_YEAR = Catalog\ProductTable::PAYMENT_PERIOD_DOUBLE_YEAR; /** @deprecated deprecated since catalog 17.6.3 */ protected static $arProductCache = array(); /** @deprecated deprecated since catalog 17.0.11 */ protected static $usedCurrency = null; /** @deprecated deprecated since catalog 17.5.1 */ protected static $optimalPriceWithVat = true; /** @deprecated deprecated since catalog 17.5.1 */ protected static $useDiscount = true; protected static $saleIncluded = null; protected static $useSaleDiscount = null; protected static $vatCache = array(); private static $existPriceTypeDiscounts = false; /** * @deprecated deprecated since catalog 17.0.11 * @see \Bitrix\Catalog\Product\Price\Calculation::setConfig() * * @param string $currency * @return void */ public static function setUsedCurrency($currency) { Catalog\Product\Price\Calculation::setConfig(array('CURRENCY' => $currency)); } /** * @deprecated deprecated since catalog 17.0.11 * @see \Bitrix\Catalog\Product\Price\Calculation::getConfig() * * @return null|string */ public static function getUsedCurrency() { $config = Catalog\Product\Price\Calculation::getConfig(); return $config['CURRENCY']; } /** * @deprecated deprecated since catalog 17.0.11 * @see \Bitrix\Catalog\Product\Price\Calculation::setConfig() * * @return void */ public static function clearUsedCurrency() { Catalog\Product\Price\Calculation::setConfig(array('CURRENCY' => null)); } /** * @deprecated deprecated since catalog 17.5.1 * @see \Bitrix\Catalog\Product\Price\Calculation::setConfig() * * @param bool $mode * @return void */ public static function setPriceVatIncludeMode($mode) { Catalog\Product\Price\Calculation::setConfig(array('RESULT_WITH_VAT' => $mode)); } /** * @deprecated deprecated since catalog 17.5.1 * @see \Bitrix\Catalog\Product\Price\Calculation::setConfig() * * @return bool */ public static function getPriceVatIncludeMode() { return Catalog\Product\Price\Calculation::isIncludingVat(); } /** * @deprecated deprecated since catalog 17.5.1 * @see \Bitrix\Catalog\Product\Price\Calculation::setConfig() * * @param bool $use * @return void */ public static function setUseDiscount($use) { Catalog\Product\Price\Calculation::setConfig(array('USE_DISCOUNTS' => $use)); } /** * @deprecated deprecated since catalog 17.5.1 * @see \Bitrix\Catalog\Product\Price\Calculation::getConfig() * * @return bool */ public static function getUseDiscount() { return Catalog\Product\Price\Calculation::isAllowedUseDiscounts(); } /** * @deprecated deprecated since catalog 17.6.3 * * @return void */ public static function ClearCache() { self::$arProductCache = []; self::$vatCache = []; } /** * @param array $product * @return bool */ public static function isAvailable($product) { $result = true; if (!empty($product) && is_array($product)) { if (isset($product['QUANTITY']) && isset($product['QUANTITY_TRACE']) && isset($product['CAN_BUY_ZERO'])) { $result = !((float)$product['QUANTITY'] <= 0 && $product['QUANTITY_TRACE'] == 'Y' && $product['CAN_BUY_ZERO'] == 'N'); } } return $result; } /** * @deprecated deprecated since catalog 15.5.2 * @see \Bitrix\Catalog\ProductTable::isExistProduct() * * @param int $intID * @return bool */ public static function IsExistProduct($intID) { return Catalog\ProductTable::isExistProduct($intID); } public static function CheckFields($ACTION, &$arFields, $ID = 0) { global $APPLICATION; $arMsg = array(); $boolResult = true; $ACTION = strtoupper($ACTION); $ID = (int)$ID; if ($ACTION == "ADD" && (!is_set($arFields, "ID") || (int)$arFields["ID"]<=0)) { $arMsg[] = array('id' => 'ID','text' => Loc::getMessage('KGP_EMPTY_ID')); $boolResult = false; } if ($ACTION != "ADD" && $ID <= 0) { $arMsg[] = array('id' => 'ID','text' => Loc::getMessage('KGP_EMPTY_ID')); $boolResult = false; } $clearFields = array( 'NEGATIVE_AMOUNT_TRACE', '~NEGATIVE_AMOUNT_TRACE', '~TYPE', '~AVAILABLE' ); if ($ACTION =='UPDATE') { $clearFields[] = 'ID'; $clearFields[] = '~ID'; } if ($ACTION == 'ADD') { $clearFields[] = 'BUNDLE'; $clearFields[] = '~BUNDLE'; } foreach ($clearFields as $fieldName) { if (array_key_exists($fieldName, $arFields)) unset($arFields[$fieldName]); } unset($fieldName, $clearFields); if ('ADD' == $ACTION) { if (!array_key_exists('SUBSCRIBE', $arFields)) $arFields['SUBSCRIBE'] = ''; if (!isset($arFields['TYPE'])) $arFields['TYPE'] = Catalog\ProductTable::TYPE_PRODUCT; $arFields['BUNDLE'] = Catalog\ProductTable::STATUS_NO; } if (is_set($arFields, "ID") || $ACTION=="ADD") $arFields["ID"] = (int)$arFields["ID"]; if (is_set($arFields, "QUANTITY") || $ACTION=="ADD") $arFields["QUANTITY"] = doubleval($arFields["QUANTITY"]); if (is_set($arFields, "QUANTITY_RESERVED") || $ACTION=="ADD") $arFields["QUANTITY_RESERVED"] = doubleval($arFields["QUANTITY_RESERVED"]); if (is_set($arFields, "OLD_QUANTITY")) $arFields["OLD_QUANTITY"] = doubleval($arFields["OLD_QUANTITY"]); if (is_set($arFields, "WEIGHT") || $ACTION=="ADD") $arFields["WEIGHT"] = doubleval($arFields["WEIGHT"]); if (is_set($arFields, "WIDTH") || $ACTION=="ADD") $arFields["WIDTH"] = doubleval($arFields["WIDTH"]); if (is_set($arFields, "LENGTH") || $ACTION=="ADD") $arFields["LENGTH"] = doubleval($arFields["LENGTH"]); if (is_set($arFields, "HEIGHT") || $ACTION=="ADD") $arFields["HEIGHT"] = doubleval($arFields["HEIGHT"]); if (is_set($arFields, "VAT_ID") || $ACTION=="ADD") $arFields["VAT_ID"] = intval($arFields["VAT_ID"]); if ((is_set($arFields, "VAT_INCLUDED") || $ACTION=="ADD") && ($arFields["VAT_INCLUDED"] != "Y")) $arFields["VAT_INCLUDED"] = "N"; if ((is_set($arFields, "QUANTITY_TRACE") || $ACTION=="ADD") && ($arFields["QUANTITY_TRACE"] != "Y" && $arFields["QUANTITY_TRACE"] != "N")) $arFields["QUANTITY_TRACE"] = "D"; if ((is_set($arFields, "CAN_BUY_ZERO") || $ACTION=="ADD") && ($arFields["CAN_BUY_ZERO"] != "Y" && $arFields["CAN_BUY_ZERO"] != "N")) $arFields["CAN_BUY_ZERO"] = "D"; if (isset($arFields['CAN_BUY_ZERO'])) $arFields['NEGATIVE_AMOUNT_TRACE'] = $arFields['CAN_BUY_ZERO']; if ((is_set($arFields, "PRICE_TYPE") || $ACTION=="ADD") && ($arFields["PRICE_TYPE"] != "R") && ($arFields["PRICE_TYPE"] != "T")) $arFields["PRICE_TYPE"] = "S"; if ((is_set($arFields, "RECUR_SCHEME_TYPE") || $ACTION=="ADD") && (strlen($arFields["RECUR_SCHEME_TYPE"]) <= 0 || !in_array($arFields["RECUR_SCHEME_TYPE"], Catalog\ProductTable::getPaymentPeriods(false)))) { $arFields["RECUR_SCHEME_TYPE"] = self::TIME_PERIOD_DAY; } if ((is_set($arFields, "RECUR_SCHEME_LENGTH") || $ACTION=="ADD") && (intval($arFields["RECUR_SCHEME_LENGTH"])<=0)) $arFields["RECUR_SCHEME_LENGTH"] = 0; if ((is_set($arFields, "TRIAL_PRICE_ID") || $ACTION=="ADD") && (intval($arFields["TRIAL_PRICE_ID"])<=0)) $arFields["TRIAL_PRICE_ID"] = false; if ((is_set($arFields, "WITHOUT_ORDER") || $ACTION=="ADD") && ($arFields["WITHOUT_ORDER"] != "Y")) $arFields["WITHOUT_ORDER"] = "N"; if ((is_set($arFields, "SELECT_BEST_PRICE") || $ACTION=="ADD") && ($arFields["SELECT_BEST_PRICE"] != "N")) $arFields["SELECT_BEST_PRICE"] = "Y"; $existPurchasingPrice = array_key_exists('PURCHASING_PRICE', $arFields); $existPurchasingCurrency = array_key_exists('PURCHASING_CURRENCY', $arFields); if ($ACTION == 'ADD') { $purchasingPrice = false; $purchasingCurrency = false; if ($existPurchasingPrice) { $purchasingPrice = static::checkPriceValue($arFields['PURCHASING_PRICE']); if ($purchasingPrice !== false) { $purchasingCurrency = static::checkPriceCurrency($arFields['PURCHASING_CURRENCY']); if ($purchasingCurrency === false) { $arMsg[] = array('id' => 'PURCHASING_CURRENCY','text' => Loc::getMessage('BT_MOD_CATALOG_PROD_ERR_COST_CURRENCY')); $boolResult = false; } } } $arFields['PURCHASING_PRICE'] = $purchasingPrice; $arFields['PURCHASING_CURRENCY'] = $purchasingCurrency; unset($purchasingCurrency, $purchasingPrice); } else { if ($existPurchasingPrice || $existPurchasingCurrency) { if ($existPurchasingPrice) { $arFields['PURCHASING_PRICE'] = static::checkPriceValue($arFields['PURCHASING_PRICE']); if ($arFields['PURCHASING_PRICE'] === false) { $arFields['PURCHASING_CURRENCY'] = false; } else { if ($existPurchasingCurrency) { $purchasingCurrency = static::checkPriceCurrency($arFields['PURCHASING_CURRENCY']); if ($purchasingCurrency === false) { $arMsg[] = array('id' => 'PURCHASING_CURRENCY', 'text' => Loc::getMessage('BT_MOD_CATALOG_PROD_ERR_COST_CURRENCY')); $boolResult = false; } else { $arFields['PURCHASING_CURRENCY'] = $purchasingCurrency; } unset($purchasingCurrency); } } } elseif ($existPurchasingCurrency) { $purchasingCurrency = static::checkPriceCurrency($arFields['PURCHASING_CURRENCY']); if ($purchasingCurrency === false) { $arMsg[] = array('id' => 'PURCHASING_CURRENCY', 'text' => Loc::getMessage('BT_MOD_CATALOG_PROD_ERR_COST_CURRENCY')); $boolResult = false; } else { $arFields['PURCHASING_CURRENCY'] = $purchasingCurrency; } unset($purchasingCurrency); } } } unset($existPurchasingCurrency, $existPurchasingPrice); if ((is_set($arFields, 'BARCODE_MULTI') || 'ADD' == $ACTION) && 'Y' != $arFields['BARCODE_MULTI']) $arFields['BARCODE_MULTI'] = 'N'; if (array_key_exists('SUBSCRIBE', $arFields)) { if ('Y' != $arFields['SUBSCRIBE'] && 'N' != $arFields['SUBSCRIBE']) $arFields['SUBSCRIBE'] = 'D'; } if (array_key_exists('BUNDLE', $arFields)) $arFields['BUNDLE'] = ($arFields['BUNDLE'] == Catalog\ProductTable::STATUS_YES ? Catalog\ProductTable::STATUS_YES : Catalog\ProductTable::STATUS_NO); if ($boolResult) { $availableFieldsList = array( 'QUANTITY', 'QUANTITY_TRACE', 'CAN_BUY_ZERO' ); $needCalculateAvailable = false; $copyFields = $arFields; if (isset($copyFields['QUANTITY_TRACE']) && $copyFields['QUANTITY_TRACE'] == 'D') $copyFields['QUANTITY_TRACE'] = Main\Config\Option::get('catalog', 'default_quantity_trace'); if (isset($copyFields['CAN_BUY_ZERO']) && $copyFields['CAN_BUY_ZERO'] == 'D') $copyFields['CAN_BUY_ZERO'] = Main\Config\Option::get('catalog', 'default_can_buy_zero'); if (!isset($arFields['AVAILABLE'])) { if ( !isset($arFields['TYPE']) || $arFields['TYPE'] == Catalog\ProductTable::TYPE_PRODUCT || $arFields['TYPE'] == Catalog\ProductTable::TYPE_OFFER || $arFields['TYPE'] == Catalog\ProductTable::TYPE_FREE_OFFER ) { if ( $ACTION == 'ADD' && ( $arFields['TYPE'] == Catalog\ProductTable::TYPE_PRODUCT || $arFields['TYPE'] == Catalog\ProductTable::TYPE_OFFER ) && !isset($arFields['AVAILABLE']) ) { $needCalculateAvailable = true; } elseif ($ACTION == 'UPDATE') { $needFields = array(); foreach ($availableFieldsList as $availableField) { if (isset($arFields[$availableField])) $needCalculateAvailable = true; else $needFields[] = $availableField; } unset($availableField); if ($needCalculateAvailable && !empty($needFields)) { $product = $productIterator = Catalog\ProductTable::getList(array( 'select' => $needFields, 'filter' => array('=ID' => $ID) ))->fetch(); if (!empty($product) && is_array($product)) { foreach ($availableFieldsList as $availableField) { if (isset($copyFields[$availableField])) continue; $copyFields[$availableField] = $product[$availableField]; } unset($availableField); } unset($product); } unset($needFields); } } elseif (isset($arFields['TYPE']) && $arFields['TYPE'] == CCatalogProduct::TYPE_SKU) { $offerList = CCatalogSku::getOffersList(array($ID), 0, array('ACTIVE' => 'Y'), array('ID')); if (!empty($offerList[$ID])) { $skuAvailable = false; $offerIterator = Catalog\ProductTable::getList(array( 'select' => array('ID', 'QUANTITY', 'QUANTITY_TRACE', 'CAN_BUY_ZERO'), 'filter' => array('@ID' => array_keys($offerList[$ID])) )); while ($offer = $offerIterator->fetch()) { if (Catalog\ProductTable::calculateAvailable($offer) == Catalog\ProductTable::STATUS_YES) $skuAvailable = true; } unset($offer, $offerIterator); if ($skuAvailable) { $arFields['AVAILABLE'] = 'Y'; $arFields['QUANTITY'] = '0'; $arFields['QUANTITY_TRACE'] = 'N'; $arFields['CAN_BUY'] = 'Y'; } else { $arFields['AVAILABLE'] = 'N'; $arFields['QUANTITY'] = '0'; $arFields['QUANTITY_TRACE'] = 'Y'; $arFields['CAN_BUY'] = 'N'; } } else { $arFields['AVAILABLE'] = 'N'; } unset($offerList); } } if ($needCalculateAvailable) $arFields['AVAILABLE'] = Catalog\ProductTable::calculateAvailable($copyFields); unset($copyFields); } if (!$boolResult) { $obError = new CAdminException($arMsg); $APPLICATION->ThrowException($obError); } return $boolResult; } /** * @deprecated deprecated since catalog 17.6.0 * @see \Bitrix\Catalog\Model\Product::add * * @param array $fields * @param bool $checkExist * @return bool */ public static function Add($fields, $checkExist = true) { $existProduct = false; $checkExist = ($checkExist !== false); if (empty($fields['ID'])) return false; $fields['ID'] = (int)$fields['ID']; if ($fields['ID'] <= 0) return false; if ($checkExist) { $data = Catalog\Model\Product::getCacheItem($fields['ID'], true); if (!empty($data)) $existProduct = !empty($data['ID']); unset($data); } self::normalizeFields($fields); if ($existProduct) $result = Catalog\Model\Product::update($fields['ID'], $fields); else $result = Catalog\Model\Product::add($fields); $success = $result->isSuccess(); if (!$success) self::convertErrors($result); unset($result); return $success; } /** * @deprecated deprecated since catalog 17.6.0 * @see \Bitrix\Catalog\Model\Product::update * * @param int $id * @param array $fields * @return bool */ public static function Update($id, $fields) { $id = (int)$id; if ($id <= 0) return false; if (!is_array($fields)) return false; self::normalizeFields($fields); $result = Catalog\Model\Product::update($id, $fields); $success = $result->isSuccess(); if (!$success) self::convertErrors($result); unset($result); return $success; } /** * @deprecated deprecated since catalog 17.6.0 * @see \Bitrix\Catalog\Model\Product::delete * * @param int $id * @return bool */ public static function Delete($id) { $id = (int)$id; if ($id <= 0) return false; $result = Catalog\Model\Product::delete($id); return $result->isSuccess(); } public static function ParseQueryBuildField($field) { $field = (string)$field; if ($field == '') return false; $field = strtoupper($field); if (strncmp($field, 'CATALOG_', 8) != 0) return false; $iNum = 0; $field = substr($field, 8); $p = strrpos($field, '_'); if ($p !== false && $p > 0) { $iNum = (int)substr($field, $p+1); if ($iNum > 0) $field = substr($field, 0, $p); } return array( 'FIELD' => $field, 'NUM' => $iNum ); } /** * @deprecated deprecated since catalog 17.6.2 * @see Catalog\Model\Product::getList * * @param int $ID * @return array|false */ public static function GetByID($ID) { $ID = (int)$ID; if ($ID <= 0) return false; $iterator = Catalog\Model\Product::getList([ 'select' => [ 'ID', 'QUANTITY', 'QUANTITY_RESERVED', 'QUANTITY_TRACE', 'QUANTITY_TRACE_ORIG', 'WEIGHT', 'WIDTH', 'LENGTH', 'HEIGHT', 'MEASURE', 'VAT_ID', 'VAT_INCLUDED', 'CAN_BUY_ZERO', 'CAN_BUY_ZERO_ORIG', 'NEGATIVE_AMOUNT_TRACE', 'NEGATIVE_AMOUNT_TRACE_ORIG', 'PRICE_TYPE', 'RECUR_SCHEME_TYPE', 'RECUR_SCHEME_LENGTH', 'TRIAL_PRICE_ID', 'WITHOUT_ORDER', 'SELECT_BEST_PRICE', 'TMP_ID', 'PURCHASING_PRICE', 'PURCHASING_CURRENCY', 'BARCODE_MULTI', 'SUBSCRIBE', 'SUBSCRIBE_ORIG', 'TYPE', 'BUNDLE', 'AVAILABLE', 'TIMESTAMP_X' ], 'filter' => ['=ID' => $ID] ]); $result = $iterator->fetch(); unset($iterator); if (empty($result)) return false; if ($result['TIMESTAMP_X'] !== null and $result['TIMESTAMP_X'] instanceof Main\Type\DateTime) { /** @noinspection PhpUndefinedMethodInspection */ $result['TIMESTAMP_X'] = $result['TIMESTAMP_X']->toString(); } return $result; } /** * @deprecated deprecated since catalog 17.6.0 * * @param $ID * @param bool $boolAllValues * @return array|bool */ public static function GetByIDEx($ID, $boolAllValues = false) { $boolAllValues = ($boolAllValues === true); $ID = (int)$ID; if ($ID <= 0) return false; $arFilter = array("ID" => $ID, "ACTIVE" => "Y", "ACTIVE_DATE" => "Y"); $dbIBlockElement = CIBlockElement::GetList(array(), $arFilter); if ($arIBlockElement = $dbIBlockElement->GetNext()) { if ($arIBlock = CIBlock::GetArrayByID($arIBlockElement["IBLOCK_ID"])) { $arIBlockElement["IBLOCK_ID"] = $arIBlock["ID"]; $arIBlockElement["IBLOCK_NAME"] = htmlspecialcharsbx($arIBlock["NAME"]); $arIBlockElement["~IBLOCK_NAME"] = $arIBlock["NAME"]; $arIBlockElement["PROPERTIES"] = false; $dbProps = CIBlockElement::GetProperty($arIBlock["ID"], $ID, "sort", "asc", array("ACTIVE"=>"Y", "NON_EMPTY"=>"Y")); if ($arProp = $dbProps->Fetch()) { $arAllProps = array(); do { $strID = (strlen($arProp["CODE"])>0 ? $arProp["CODE"] : $arProp["ID"]); if (is_array($arProp["VALUE"])) { foreach ($arProp["VALUE"] as &$strOneValue) { $strOneValue = htmlspecialcharsbx($strOneValue); } if (isset($strOneValue)) unset($strOneValue); } else { $arProp["VALUE"] = htmlspecialcharsbx($arProp["VALUE"]); } if (is_array($arProp["DEFAULT_VALUE"])) { foreach ($arProp["DEFAULT_VALUE"] as $index => $value) { if (is_string($value)) $arProp["DEFAULT_VALUE"][$index] = htmlspecialcharsbx($value); } } else { $arProp["DEFAULT_VALUE"] = htmlspecialcharsbx($arProp["DEFAULT_VALUE"]); } if ($boolAllValues && 'Y' == $arProp['MULTIPLE']) { if (!isset($arAllProps[$strID])) { $arAllProps[$strID] = array( "NAME" => htmlspecialcharsbx($arProp["NAME"]), "VALUE" => array($arProp["VALUE"]), "VALUE_ENUM" => array(htmlspecialcharsbx($arProp["VALUE_ENUM"])), "VALUE_XML_ID" => array(htmlspecialcharsbx($arProp["VALUE_XML_ID"])), "DEFAULT_VALUE" => $arProp["DEFAULT_VALUE"], "SORT" => htmlspecialcharsbx($arProp["SORT"]), "MULTIPLE" => $arProp['MULTIPLE'], ); } else { $arAllProps[$strID]['VALUE'][] = $arProp["VALUE"]; $arAllProps[$strID]['VALUE_ENUM'][] = htmlspecialcharsbx($arProp["VALUE_ENUM"]); $arAllProps[$strID]['VALUE_XML_ID'][] = htmlspecialcharsbx($arProp["VALUE_XML_ID"]); } } else { $arAllProps[$strID] = array( "NAME" => htmlspecialcharsbx($arProp["NAME"]), "VALUE" => $arProp["VALUE"], "VALUE_ENUM" => htmlspecialcharsbx($arProp["VALUE_ENUM"]), "VALUE_XML_ID" => htmlspecialcharsbx($arProp["VALUE_XML_ID"]), "DEFAULT_VALUE" => $arProp["DEFAULT_VALUE"], "SORT" => htmlspecialcharsbx($arProp["SORT"]), "MULTIPLE" => $arProp['MULTIPLE'], ); } } while($arProp = $dbProps->Fetch()); $arIBlockElement["PROPERTIES"] = $arAllProps; } // bugfix: 2007-07-31 by Sigurd $arIBlockElement["PRODUCT"] = CCatalogProduct::GetByID($ID); $dbPrices = CPrice::GetList(array("SORT" => "ASC"), array("PRODUCT_ID" => $ID)); if ($arPrices = $dbPrices->Fetch()) { $arAllPrices = array(); do { $arAllPrices[$arPrices["CATALOG_GROUP_ID"]] = array( "EXTRA_ID" => intval($arPrices["EXTRA_ID"]), "PRICE" => doubleval($arPrices["PRICE"]), "CURRENCY" => htmlspecialcharsbx($arPrices["CURRENCY"]) ); } while($arPrices = $dbPrices->Fetch()); $arIBlockElement["PRICES"] = $arAllPrices; } return $arIBlockElement; } } return false; } /** * @deprecated deprecated since catalog 15.0.0 * @see \CCatalogProductProvider * * @param int $ProductID * @param int|float $DeltaQuantity * @return bool */ public static function QuantityTracer($ProductID, $DeltaQuantity) { $boolClearCache = false; $ProductID = (int)$ProductID; if ($ProductID <= 0) return false; $DeltaQuantity = (float)$DeltaQuantity; if ($DeltaQuantity==0) return false; $rsProducts = CCatalogProduct::GetList( array(), array('ID' => $ProductID), false, false, array('ID', 'CAN_BUY_ZERO', 'NEGATIVE_AMOUNT_TRACE', 'QUANTITY_TRACE', 'QUANTITY', 'ELEMENT_IBLOCK_ID') ); if (($arProduct = $rsProducts->Fetch()) && ($arProduct["QUANTITY_TRACE"]=="Y")) { $strAllowNegativeAmount = $arProduct["NEGATIVE_AMOUNT_TRACE"]; $arFields = array(); $arFields["QUANTITY"] = (float)$arProduct["QUANTITY"] - $DeltaQuantity; if ('Y' != $arProduct['CAN_BUY_ZERO']) { if (defined("BX_COMP_MANAGED_CACHE")) { $boolClearCache = (0 >= $arFields["QUANTITY"]*$arProduct["QUANTITY"]); } } if ('Y' != $arProduct['CAN_BUY_ZERO'] || 'Y' != $strAllowNegativeAmount) { if (0 >= $arFields["QUANTITY"]) $arFields["QUANTITY"] = 0; } $arFields['OLD_QUANTITY'] = $arProduct["QUANTITY"]; CCatalogProduct::Update($arProduct["ID"], $arFields); if ($boolClearCache) CIBlock::clearIblockTagCache($arProduct['ELEMENT_IBLOCK_ID']); $arProduct['OLD_QUANTITY'] = $arFields['OLD_QUANTITY']; $arProduct['QUANTITY'] = $arFields['QUANTITY']; $arProduct['ALLOW_NEGATIVE_AMOUNT'] = $strAllowNegativeAmount; $arProduct['DELTA'] = $DeltaQuantity; foreach (GetModuleEvents("catalog", "OnProductQuantityTrace", true) as $arEvent) { ExecuteModuleEventEx($arEvent, array($arProduct["ID"], $arProduct)); } return true; } return false; } /** * @param int $productID * @param int|float $quantity * @param array $arUserGroups * @return bool|float|int */ public static function GetNearestQuantityPrice($productID, $quantity = 1, $arUserGroups = array()) { static $eventOnGetExists = null; static $eventOnResultExists = null; global $APPLICATION; if ($eventOnGetExists === true || $eventOnGetExists === null) { foreach (GetModuleEvents('catalog', 'OnGetNearestQuantityPrice', true) as $arEvent) { $eventOnGetExists = true; $mxResult = ExecuteModuleEventEx( $arEvent, array( $productID, $quantity, $arUserGroups ) ); if ($mxResult !== true) return $mxResult; } if ($eventOnGetExists === null) $eventOnGetExists = false; } // Check input params $productID = (int)$productID; if ($productID <= 0) { $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_PRODUCT_ID_ABSENT"), "NO_PRODUCT_ID"); return false; } $quantity = (float)$quantity; if ($quantity <= 0) { $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_QUANTITY_ABSENT"), "NO_QUANTITY"); return false; } if (!is_array($arUserGroups) && (int)$arUserGroups.'|' == (string)$arUserGroups.'|') $arUserGroups = array((int)$arUserGroups); if (!is_array($arUserGroups)) $arUserGroups = array(); if (!in_array(2, $arUserGroups)) $arUserGroups[] = 2; $quantityDifference = -1; $nearestQuantity = -1; // Find nearest quantity $priceTypeList = self::getAllowedPriceTypes($arUserGroups); if (empty($priceTypeList)) return false; $iterator = Catalog\PriceTable::getList(array( 'select' => array('ID', 'QUANTITY_FROM', 'QUANTITY_TO'), 'filter' => array( '=PRODUCT_ID' => $productID, '@CATALOG_GROUP_ID' => $priceTypeList, ) )); while ($arPriceList = $iterator->fetch()) { $arPriceList['QUANTITY_FROM'] = (float)$arPriceList['QUANTITY_FROM']; $arPriceList['QUANTITY_TO'] = (float)$arPriceList['QUANTITY_TO']; if ($quantity >= $arPriceList["QUANTITY_FROM"] && ($quantity <= $arPriceList["QUANTITY_TO"] || $arPriceList["QUANTITY_TO"] == 0)) { $nearestQuantity = $quantity; break; } if ($quantity < $arPriceList["QUANTITY_FROM"]) { $nearestQuantity_tmp = $arPriceList["QUANTITY_FROM"]; $quantityDifference_tmp = $arPriceList["QUANTITY_FROM"] - $quantity; } else { $nearestQuantity_tmp = $arPriceList["QUANTITY_TO"]; $quantityDifference_tmp = $quantity - $arPriceList["QUANTITY_TO"]; } if ($quantityDifference < 0 || $quantityDifference_tmp < $quantityDifference) { $quantityDifference = $quantityDifference_tmp; $nearestQuantity = $nearestQuantity_tmp; } } unset($arPriceList, $iterator); unset($priceTypeList); if ($eventOnResultExists === true || $eventOnResultExists === null) { foreach (GetModuleEvents('catalog', 'OnGetNearestQuantityPriceResult', true) as $arEvent) { $eventOnResultExists = true; if (ExecuteModuleEventEx($arEvent, array(&$nearestQuantity)) === false) return false; } if ($eventOnResultExists === null) $eventOnResultExists = false; } return ($nearestQuantity > 0 ? $nearestQuantity : false); } /** * @param int $intProductID * @param int|float $quantity * @param array $arUserGroups * @param string $renewal * @param array $priceList * @param bool|string $siteID * @param bool|array $arDiscountCoupons * @return array|bool */ public static function GetOptimalPrice($intProductID, $quantity = 1, $arUserGroups = array(), $renewal = "N", $priceList = array(), $siteID = false, $arDiscountCoupons = false) { static $eventOnGetExists = null; static $eventOnResultExists = null; global $APPLICATION; if ($eventOnGetExists === true || $eventOnGetExists === null) { foreach (GetModuleEvents('catalog', 'OnGetOptimalPrice', true) as $arEvent) { $eventOnGetExists = true; $mxResult = ExecuteModuleEventEx( $arEvent, array( $intProductID, $quantity, $arUserGroups, $renewal, $priceList, $siteID, $arDiscountCoupons ) ); if ($mxResult !== true) { self::updateUserHandlerOptimalPrice( $mxResult, ['PRODUCT_ID' => $intProductID] ); return $mxResult; } } if ($eventOnGetExists === null) $eventOnGetExists = false; } $intProductID = (int)$intProductID; if ($intProductID <= 0) { $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_PRODUCT_ID_ABSENT"), "NO_PRODUCT_ID"); return false; } $quantity = (float)$quantity; if ($quantity <= 0) { $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_QUANTITY_ABSENT"), "NO_QUANTITY"); return false; } if (!is_array($arUserGroups) && (int)$arUserGroups.'|' == (string)$arUserGroups.'|') $arUserGroups = array((int)$arUserGroups); if (!is_array($arUserGroups)) $arUserGroups = array(); if (!in_array(2, $arUserGroups)) $arUserGroups[] = 2; Main\Type\Collection::normalizeArrayValuesByInt($arUserGroups); $renewal = ($renewal == 'Y' ? 'Y' : 'N'); if ($siteID === false) $siteID = SITE_ID; $resultCurrency = Catalog\Product\Price\Calculation::getCurrency(); if (empty($resultCurrency)) { $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_NO_RESULT_CURRENCY")); return false; } $intIBlockID = (int)CIBlockElement::GetIBlockByID($intProductID); if ($intIBlockID <= 0) { $APPLICATION->ThrowException( Loc::getMessage( 'BT_MOD_CATALOG_PROD_ERR_ELEMENT_ID_NOT_FOUND', array('#ID#' => $intProductID) ), 'NO_ELEMENT' ); return false; } if (!isset($priceList) || !is_array($priceList)) $priceList = array(); if (empty($priceList)) { $priceTypeList = self::getAllowedPriceTypes($arUserGroups); if (empty($priceTypeList)) return false; $iterator = Catalog\PriceTable::getList(array( 'select' => array('ID', 'CATALOG_GROUP_ID', 'PRICE', 'CURRENCY'), 'filter' => array( '=PRODUCT_ID' => $intProductID, '@CATALOG_GROUP_ID' => $priceTypeList, array( 'LOGIC' => 'OR', '<=QUANTITY_FROM' => $quantity, '=QUANTITY_FROM' => null ), array( 'LOGIC' => 'OR', '>=QUANTITY_TO' => $quantity, '=QUANTITY_TO' => null ) ) )); while ($row = $iterator->fetch()) { $row['ELEMENT_IBLOCK_ID'] = $intIBlockID; $priceList[] = $row; } unset($row, $iterator); unset($priceTypeList); } else { foreach (array_keys($priceList) as $priceIndex) $priceList[$priceIndex]['ELEMENT_IBLOCK_ID'] = $intIBlockID; unset($priceIndex); } if (empty($priceList)) return false; $vat = CCatalogProduct::GetVATDataByID($intProductID); if (!empty($vat)) { $vat['RATE'] = (float)$vat['RATE'] * 0.01; } else { $vat = array('RATE' => 0.0, 'VAT_INCLUDED' => 'N'); } unset($iterator); $isNeedDiscounts = Catalog\Product\Price\Calculation::isAllowedUseDiscounts(); $resultWithVat = Catalog\Product\Price\Calculation::isIncludingVat(); if ($isNeedDiscounts) { if ($arDiscountCoupons === false) $arDiscountCoupons = CCatalogDiscountCoupon::GetCoupons(); } // $boolDiscountVat = ('N' != COption::GetOptionString('catalog', 'discount_vat', 'Y')); $boolDiscountVat = true; $minimalPrice = array(); if (self::$saleIncluded === null) self::initSaleSettings(); $isNeedleToMinimizeCatalogGroup = self::isNeedleToMinimizeCatalogGroup($priceList); foreach ($priceList as $priceData) { $priceData['VAT_RATE'] = $vat['RATE']; $priceData['VAT_INCLUDED'] = $vat['VAT_INCLUDED']; $currentPrice = (float)$priceData['PRICE']; if ($boolDiscountVat) { if ($priceData['VAT_INCLUDED'] == 'N') $currentPrice *= (1 + $priceData['VAT_RATE']); } else { if ($priceData['VAT_INCLUDED'] == 'Y') $currentPrice /= (1 + $priceData['VAT_RATE']); } if ($priceData['CURRENCY'] != $resultCurrency) $currentPrice = CCurrencyRates::ConvertCurrency($currentPrice, $priceData['CURRENCY'], $resultCurrency); $currentPrice = Catalog\Product\Price\Calculation::roundPrecision($currentPrice); $result = array( 'BASE_PRICE' => $currentPrice, 'COMPARE_PRICE' => $currentPrice, 'PRICE' => $currentPrice, 'CURRENCY' => $resultCurrency, 'DISCOUNT_LIST' => array(), 'RAW_PRICE' => $priceData ); if ($isNeedDiscounts) { $arDiscounts = CCatalogDiscount::GetDiscount( $intProductID, $intIBlockID, $priceData['CATALOG_GROUP_ID'], $arUserGroups, $renewal, $siteID, $arDiscountCoupons ); $discountResult = CCatalogDiscount::applyDiscountList($currentPrice, $resultCurrency, $arDiscounts); unset($arDiscounts); if ($discountResult === false) return false; $result['PRICE'] = $discountResult['PRICE']; $result['COMPARE_PRICE'] = $discountResult['PRICE']; $result['DISCOUNT_LIST'] = $discountResult['DISCOUNT_LIST']; unset($discountResult); } elseif($isNeedleToMinimizeCatalogGroup) { $calculateData = $priceData; $calculateData['PRICE'] = $currentPrice; $calculateData['CURRENCY'] = $resultCurrency; $possibleSalePrice = self::getPossibleSalePrice( $intProductID, $calculateData, $quantity, $siteID, $arUserGroups, $arDiscountCoupons ); unset($calculateData); if ($possibleSalePrice === null) return false; $result['COMPARE_PRICE'] = $possibleSalePrice; unset($possibleSalePrice); } if ($boolDiscountVat) { if (!$resultWithVat) { $result['PRICE'] /= (1 + $priceData['VAT_RATE']); $result['COMPARE_PRICE'] /= (1 + $priceData['VAT_RATE']); $result['BASE_PRICE'] /= (1 + $priceData['VAT_RATE']); } } else { if ($resultWithVat) { $result['PRICE'] *= (1 + $priceData['VAT_RATE']); $result['COMPARE_PRICE'] *= (1 + $priceData['VAT_RATE']); $result['BASE_PRICE'] *= (1 + $priceData['VAT_RATE']); } } $result['UNROUND_PRICE'] = $result['PRICE']; $result['UNROUND_BASE_PRICE'] = $result['BASE_PRICE']; if (Catalog\Product\Price\Calculation::isComponentResultMode()) { $result['BASE_PRICE'] = Catalog\Product\Price::roundPrice( $priceData['CATALOG_GROUP_ID'], $result['BASE_PRICE'], $resultCurrency ); $result['PRICE'] = Catalog\Product\Price::roundPrice( $priceData['CATALOG_GROUP_ID'], $result['PRICE'], $resultCurrency ); if ( empty($result['DISCOUNT_LIST']) || Catalog\Product\Price\Calculation::compare($result['BASE_PRICE'], $result['PRICE'], '<=') ) { $result['BASE_PRICE'] = $result['PRICE']; } $result['COMPARE_PRICE'] = $result['PRICE']; } if (empty($minimalPrice) || $minimalPrice['COMPARE_PRICE'] > $result['COMPARE_PRICE']) { $minimalPrice = $result; } unset($currentPrice, $result); } unset($priceData); unset($vat); $discountValue = ($minimalPrice['BASE_PRICE'] - $minimalPrice['PRICE']); $arResult = array( 'PRICE' => $minimalPrice['RAW_PRICE'], 'RESULT_PRICE' => array( 'PRICE_TYPE_ID' => $minimalPrice['RAW_PRICE']['CATALOG_GROUP_ID'], 'BASE_PRICE' => $minimalPrice['BASE_PRICE'], 'DISCOUNT_PRICE' => $minimalPrice['PRICE'], 'CURRENCY' => $resultCurrency, 'DISCOUNT' => $discountValue, 'PERCENT' => ( $minimalPrice['BASE_PRICE'] > 0 && $discountValue > 0 ? round((100*$discountValue)/$minimalPrice['BASE_PRICE'], 0) : 0 ), 'VAT_RATE' => $minimalPrice['RAW_PRICE']['VAT_RATE'], 'VAT_INCLUDED' => ($resultWithVat ? 'Y' : 'N'), 'UNROUND_BASE_PRICE' => $minimalPrice['UNROUND_BASE_PRICE'], 'UNROUND_DISCOUNT_PRICE' => $minimalPrice['UNROUND_PRICE'] ), 'DISCOUNT_PRICE' => $minimalPrice['PRICE'], 'DISCOUNT' => array(), 'DISCOUNT_LIST' => array(), 'PRODUCT_ID' => $intProductID ); if (!empty($minimalPrice['DISCOUNT_LIST'])) { reset($minimalPrice['DISCOUNT_LIST']); $arResult['DISCOUNT'] = current($minimalPrice['DISCOUNT_LIST']); $arResult['DISCOUNT_LIST'] = $minimalPrice['DISCOUNT_LIST']; } unset($minimalPrice); if ($eventOnResultExists === true || $eventOnResultExists === null) { foreach (GetModuleEvents('catalog', 'OnGetOptimalPriceResult', true) as $arEvent) { $eventOnResultExists = true; if (ExecuteModuleEventEx($arEvent, array(&$arResult)) === false) return false; } if ($eventOnResultExists === null) $eventOnResultExists = false; } return $arResult; } public static function GetOptimalPriceList(array $products, $arUserGroups = array(), $renewal = "N", $priceList = array(), $siteID = false, $needCoupons = true) { static $eventOnGetExists = null; static $eventOnResultExists = null; $needCoupons = ($needCoupons === true); $resultList = array(); $iblockListId = array(); $productIblockGetIdList = array(); $ignoreList = array(); $useDiscount = !\CCatalogDiscount::isUsedSaleDiscountOnly(); foreach ($products as $productId => $productData) { Catalog\Product\Price\Calculation::setConfig( array( 'USE_DISCOUNTS' => (isset($productData['BUNDLE_CHILD']) && $productData['BUNDLE_CHILD'] === true ? false : $useDiscount), ) ); foreach (GetModuleEvents('catalog', 'OnGetOptimalPrice', true) as $arEvent) { if (!empty($productData['QUANTITY_LIST'])) { foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity) { //TODO: remove this hack after refactoring new provider if ($quantity <= 0) continue; $mxResult = ExecuteModuleEventEx( $arEvent, array( $productId, $quantity, $arUserGroups, $renewal, $priceList, $siteID, $needCoupons ? false : array() ) ); if ($mxResult !== true) { self::updateUserHandlerOptimalPrice( $mxResult, ['PRODUCT_ID' => $productId] ); $resultList[$productId][$productData['BASKET_CODE']] = $mxResult; $ignoreList[$productId."|".$quantity] = true; continue 3; } } } } if (!empty($productData['QUANTITY_LIST'])) { foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity) { $resultList[$productId][$basketCode] = false; } } else { $resultList[$productId][$productData['BASKET_CODE']] = false; } if (!isset($iblockListId[$productId]) && isset($productData['IBLOCK_ID']) && $productData['IBLOCK_ID'] > 0) { $iblockListId[$productId] = $productData['IBLOCK_ID']; } if (!isset($iblockListId[$productId])) { $productIblockGetIdList[] = $productId; } } global $APPLICATION; if (!is_array($arUserGroups) && (int)$arUserGroups.'|' == (string)$arUserGroups.'|') $arUserGroups = array((int)$arUserGroups); if (!is_array($arUserGroups)) $arUserGroups = array(); if (!in_array(2, $arUserGroups)) $arUserGroups[] = 2; Main\Type\Collection::normalizeArrayValuesByInt($arUserGroups); $renewal = ($renewal == 'Y' ? 'Y' : 'N'); if ($siteID === false) $siteID = SITE_ID; $resultCurrency = Catalog\Product\Price\Calculation::getCurrency(); if (empty($resultCurrency)) { $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_NO_RESULT_CURRENCY")); return false; } if (!empty($productIblockGetIdList)) { $iblockIdList = CIBlockElement::GetIBlockByIDList($productIblockGetIdList); if (!empty($iblockIdList) && is_array($iblockIdList)) { $iblockListId = $iblockIdList + $iblockListId; } } if (!isset($priceList) || !is_array($priceList)) $priceList = array(); if (empty($priceList)) { $priceTypeList = self::getAllowedPriceTypes($arUserGroups); if (empty($priceTypeList)) { if (!empty($resultList)) { return $resultList; } return false; } $iterator = Catalog\PriceTable::getList(array( 'select' => array('ID', 'CATALOG_GROUP_ID', 'PRICE', 'CURRENCY', 'QUANTITY_FROM', 'QUANTITY_TO', 'PRODUCT_ID'), 'filter' => array( '=PRODUCT_ID' => array_keys($products), '@CATALOG_GROUP_ID' => $priceTypeList ), )); while ($row = $iterator->fetch()) { $row['ELEMENT_IBLOCK_ID'] = $iblockListId[$row['PRODUCT_ID']]; if (isset($products[$row['PRODUCT_ID']])) { $productData = $products[$row['PRODUCT_ID']]; if (!empty($productData['QUANTITY_LIST'])) { foreach ($productData['QUANTITY_LIST'] as $basketCode => $quantity) { if(isset($ignoreList[$row['PRODUCT_ID']."|".$quantity])) { continue 2; } } } $quantityList = array(); if (!isset($productData['QUANTITY'])) { $quantityList = array($productData['QUANTITY']); } if (!empty($productData['QUANTITY_LIST'])) { $quantityList = $productData['QUANTITY_LIST']; } foreach ($quantityList as $basketCode => $quantity) { $checkQuantity = abs(floatval($quantity)); if (($row['QUANTITY_FROM'] <= $checkQuantity || empty($row['QUANTITY_FROM'])) && ($row['QUANTITY_TO'] >= $checkQuantity || empty($row['QUANTITY_TO']))) { $row['QUANTITY'] = floatval($quantity); $row['BASKET_CODE'] = $basketCode; $priceList[] = $row; } } } } unset($row, $iterator); unset($cacheKey); } else { foreach ($priceList as $priceIndex => $priceData) { $priceList[$priceIndex]['ELEMENT_IBLOCK_ID'] = $iblockListId[$priceData['PRODUCT_ID']]; } unset($priceIndex); } if (empty($priceList)) { if (!empty($resultList)) { return $resultList; } return false; } \Bitrix\Main\Type\Collection::sortByColumn($priceList, 'BASKET_CODE'); $vatList = CCatalogProduct::GetVATDataByIDList(array_keys($products)); if (!empty($vatList)) { foreach ($vatList as $productId => $vatValue) { if ($vatValue === false) { $vatList[$productId] = array('RATE' => 0.0, 'VAT_INCLUDED' => 'N'); } else { $vatList[$productId]['RATE'] = (float)$vatList[$productId]['RATE'] * 0.01; } } } $isNeedDiscounts = Catalog\Product\Price\Calculation::isAllowedUseDiscounts(); $resultWithVat = Catalog\Product\Price\Calculation::isIncludingVat(); $boolDiscountVat = ('N' != COption::GetOptionString('catalog', 'discount_vat', 'Y')); $discountList = array(); if (self::$saleIncluded === null) self::initSaleSettings(); $isNeedleToMinimizeCatalogGroup = self::isNeedleToMinimizeCatalogGroup($priceList); $lastProductId = false; $lastBasketCode = false; $ignoreProductIdList = array(); $coupons = array(); $minimalPrice = array(); foreach ($priceList as $priceData) { $productId = $priceData['PRODUCT_ID']; $basketCode = $priceData['BASKET_CODE']; if (in_array($productId, $ignoreProductIdList)) { continue; } if ($lastBasketCode != $basketCode) { if ($lastBasketCode !== false) { foreach (GetModuleEvents('catalog', 'OnGetOptimalPriceResult', true) as $arEvent) { if (ExecuteModuleEventEx($arEvent, array(&$resultList[$lastProductId][$lastBasketCode])) === false) { continue; } } $productHash = array( 'MODULE' => 'catalog', 'PRODUCT_ID' => $lastProductId, 'BASKET_ID' => $lastBasketCode ); if (!empty($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST'])) { $applyCoupons = array(); foreach ($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST'] as $discount) { if (!empty($discount['COUPON'])) { $applyCoupons[] = $discount['COUPON']; } } if (!empty($applyCoupons)) { $resultApply = Sale\DiscountCouponsManager::setApplyByProduct($productHash, $applyCoupons); } } } if ($isNeedDiscounts && $needCoupons) { $coupons = static::getCoupons($productId, $basketCode); } $lastBasketCode = $basketCode; $lastProductId = $productId; Catalog\Product\Price\Calculation::setConfig( array( 'USE_DISCOUNTS' => (isset($products[$productId]['BUNDLE_CHILD']) && $products[$productId]['BUNDLE_CHILD'] === true ? false : $useDiscount), ) ); $isNeedDiscounts = Catalog\Product\Price\Calculation::isAllowedUseDiscounts(); } $vat = $vatList[$priceData['PRODUCT_ID']]; $priceData['VAT_RATE'] = $vat['RATE']; $priceData['VAT_INCLUDED'] = $vat['VAT_INCLUDED']; $currentPrice = (float)$priceData['PRICE']; if ($boolDiscountVat) { if ($priceData['VAT_INCLUDED'] == 'N') $currentPrice *= (1 + $priceData['VAT_RATE']); } else { if ($priceData['VAT_INCLUDED'] == 'Y') $currentPrice /= (1 + $priceData['VAT_RATE']); } if ($priceData['CURRENCY'] != $resultCurrency) $currentPrice = CCurrencyRates::ConvertCurrency($currentPrice, $priceData['CURRENCY'], $resultCurrency); $currentPrice = Catalog\Product\Price\Calculation::roundPrecision($currentPrice); $result = array( 'BASE_PRICE' => $currentPrice, 'COMPARE_PRICE' => $currentPrice, 'PRICE' => $currentPrice, 'CURRENCY' => $resultCurrency, 'DISCOUNT_LIST' => array(), 'RAW_PRICE' => $priceData ); if ($isNeedDiscounts) { $discountList[$priceData['PRODUCT_ID']] = \CCatalogDiscount::GetDiscount( $productId, $iblockListId[$priceData['PRODUCT_ID']], $priceData['CATALOG_GROUP_ID'], $arUserGroups, $renewal, $siteID, $coupons ); $discountResult = \CCatalogDiscount::applyDiscountList($currentPrice, $resultCurrency, $discountList[$priceData['PRODUCT_ID']]); if ($discountResult === false) { $ignoreProductIdList[] = $productId; $resultList[$productId][$basketCode] = false; continue; } $result['PRICE'] = $discountResult['PRICE']; $result['COMPARE_PRICE'] = $discountResult['PRICE']; $result['DISCOUNT_LIST'] = $discountResult['DISCOUNT_LIST']; unset($discountResult); } elseif($isNeedleToMinimizeCatalogGroup) { if (!isset($products[$productId]['QUANTITY_LIST'][$basketCode])) continue; $calculateData = $priceData; $calculateData['PRICE'] = $currentPrice; $calculateData['CURRENCY'] = $resultCurrency; $possibleSalePrice = self::getPossibleSalePrice( $productId, $calculateData, $products[$productId]['QUANTITY_LIST'][$basketCode], $siteID, $arUserGroups, ($needCoupons ? false: []) ); unset($calculateData); if ($possibleSalePrice === null) continue; $result['COMPARE_PRICE'] = $possibleSalePrice; unset($possibleSalePrice); } if ($boolDiscountVat) { if (!$resultWithVat) { $result['PRICE'] /= (1 + $priceData['VAT_RATE']); $result['COMPARE_PRICE'] /= (1 + $priceData['VAT_RATE']); $result['BASE_PRICE'] /= (1 + $priceData['VAT_RATE']); } } else { if ($resultWithVat) { $result['PRICE'] *= (1 + $priceData['VAT_RATE']); $result['COMPARE_PRICE'] *= (1 + $priceData['VAT_RATE']); $result['BASE_PRICE'] *= (1 + $priceData['VAT_RATE']); } } $result['UNROUND_PRICE'] = $result['PRICE']; $result['UNROUND_BASE_PRICE'] = $result['BASE_PRICE']; if (Catalog\Product\Price\Calculation::isComponentResultMode()) { $result['BASE_PRICE'] = Catalog\Product\Price::roundPrice( $priceData['CATALOG_GROUP_ID'], $result['BASE_PRICE'], $resultCurrency ); $result['PRICE'] = Catalog\Product\Price::roundPrice( $priceData['CATALOG_GROUP_ID'], $result['PRICE'], $resultCurrency ); if ( empty($result['DISCOUNT_LIST']) || Catalog\Product\Price\Calculation::compare($result['BASE_PRICE'], $result['PRICE'], '<=') ) { $result['BASE_PRICE'] = $result['PRICE']; } $result['COMPARE_PRICE'] = $result['PRICE']; } if ( empty($minimalPrice[$basketCode]) || $minimalPrice[$basketCode]['COMPARE_PRICE'] > $result['COMPARE_PRICE'] ) { $minimalPrice[$basketCode] = $result; } unset($currentPrice, $result); $discountValue = ($minimalPrice[$basketCode]['BASE_PRICE'] - $minimalPrice[$basketCode]['PRICE']); $productResult = array( 'PRICE' => $minimalPrice[$basketCode]['RAW_PRICE'], 'RESULT_PRICE' => array( 'PRICE_TYPE_ID' => $minimalPrice[$basketCode]['RAW_PRICE']['CATALOG_GROUP_ID'], 'BASE_PRICE' => $minimalPrice[$basketCode]['BASE_PRICE'], 'DISCOUNT_PRICE' => $minimalPrice[$basketCode]['PRICE'], 'CURRENCY' => $resultCurrency, 'DISCOUNT' => $discountValue, 'PERCENT' => ( $minimalPrice[$basketCode]['BASE_PRICE'] > 0 && $discountValue > 0 ? round((100 * $discountValue)/$minimalPrice[$basketCode]['BASE_PRICE'], 0) : 0 ), 'VAT_RATE' => $minimalPrice[$basketCode]['RAW_PRICE']['VAT_RATE'], 'VAT_INCLUDED' => ($resultWithVat ? 'Y' : 'N'), 'UNROUND_BASE_PRICE' => $minimalPrice[$basketCode]['UNROUND_BASE_PRICE'], 'UNROUND_DISCOUNT_PRICE' => $minimalPrice[$basketCode]['UNROUND_PRICE'] ), 'DISCOUNT_PRICE' => $minimalPrice[$basketCode]['PRICE'], 'DISCOUNT' => array(), 'DISCOUNT_LIST' => array(), 'PRODUCT_ID' => $productId ); if (!empty($minimalPrice[$basketCode]['DISCOUNT_LIST'])) { reset($minimalPrice[$basketCode]['DISCOUNT_LIST']); $productResult['DISCOUNT'] = current($minimalPrice[$basketCode]['DISCOUNT_LIST']); $productResult['DISCOUNT_LIST'] = $minimalPrice[$basketCode]['DISCOUNT_LIST']; } $resultList[$productId][$priceData['BASKET_CODE']] = $productResult; } unset($minimalPrice); unset($priceData); unset($vat); if ($lastBasketCode !== false) { foreach (GetModuleEvents('catalog', 'OnGetOptimalPriceResult', true) as $arEvent) { if (ExecuteModuleEventEx($arEvent, array(&$resultList[$lastProductId][$lastBasketCode])) === false) { break; } } $productHash = array( 'MODULE' => 'catalog', 'PRODUCT_ID' => $lastProductId, 'BASKET_ID' => $lastBasketCode ); if (!empty($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST'])) { $applyCoupons = array(); foreach ($resultList[$lastProductId][$lastBasketCode]['DISCOUNT_LIST'] as $discount) { if (!empty($discount['COUPON'])) { $applyCoupons[] = $discount['COUPON']; } } if (!empty($applyCoupons)) { Sale\DiscountCouponsManager::setApplyByProduct($productHash, $applyCoupons); } } } return $resultList; } /** * @param $productId * @param $basketCode * * @return array|bool */ private static function getCoupons($productId, $basketCode) { $productHash = array( 'MODULE' => 'catalog', 'PRODUCT_ID' => $productId, 'BASKET_ID' => $basketCode ); $coupons = Sale\DiscountCouponsManager::getForApply(array('MODULE_ID' => 'catalog'), $productHash); if (!empty($coupons)) { $coupons = array_keys($coupons); } return $coupons; } /** * @param float $price * @param string $currency * @param array $discounts * @return bool|float */ public static function CountPriceWithDiscount($price, $currency, $discounts) { static $eventOnGetExists = null; static $eventOnResultExists = null; if ($eventOnGetExists === true || $eventOnGetExists === null) { foreach (GetModuleEvents('catalog', 'OnCountPriceWithDiscount', true) as $arEvent) { $eventOnGetExists = true; $mxResult = ExecuteModuleEventEx($arEvent, array($price, $currency, $discounts)); if ($mxResult !== true) return $mxResult; } if ($eventOnGetExists === null) $eventOnGetExists = false; } $currency = CCurrency::checkCurrencyID($currency); if ($currency === false) return false; $price = (float)$price; if ($price <= 0) return $price; $currentMinPrice = $price; if (!empty($discounts) && is_array($discounts)) { $result = CCatalogDiscount::applyDiscountList($price, $currency, $discounts); if ($result === false) return false; $currentMinPrice = $result['PRICE']; } if ($eventOnResultExists === true || $eventOnResultExists === null) { foreach (GetModuleEvents('catalog', 'OnCountPriceWithDiscountResult', true) as $arEvent) { $eventOnResultExists = true; if (ExecuteModuleEventEx($arEvent, array(&$currentMinPrice)) === false) return false; } if ($eventOnResultExists === null) $eventOnResultExists = false; } return $currentMinPrice; } public static function GetProductSections($ID) { /** @global CStackCacheManager $stackCacheManager */ global $stackCacheManager; $ID = (int)$ID; if ($ID <= 0) return false; $cacheTime = CATALOG_CACHE_DEFAULT_TIME; if (defined('CATALOG_CACHE_TIME')) $cacheTime = intval(CATALOG_CACHE_TIME); $arProductSections = array(); $dbElementSections = CIBlockElement::GetElementGroups($ID, false, array('ID', 'ADDITIONAL_PROPERTY_ID')); while ($arElementSections = $dbElementSections->Fetch()) { if ((int)$arElementSections['ADDITIONAL_PROPERTY_ID'] > 0) continue; $arSectionsTmp = array(); $strCacheKey = "p".$arElementSections["ID"]; $stackCacheManager->SetLength("catalog_group_parents", 50); $stackCacheManager->SetTTL("catalog_group_parents", $cacheTime); if ($stackCacheManager->Exist("catalog_group_parents", $strCacheKey)) { $arSectionsTmp = $stackCacheManager->Get("catalog_group_parents", $strCacheKey); } else { $dbSection = CIBlockSection::GetList( array(), array('ID' => $arElementSections["ID"]), false, array( 'ID', 'IBLOCK_ID', 'LEFT_MARGIN', 'RIGHT_MARGIN', ) ); if ($arSection = $dbSection->Fetch()) { $dbSectionTree = CIBlockSection::GetList( array("LEFT_MARGIN" => "DESC"), array( "IBLOCK_ID" => $arSection["IBLOCK_ID"], "ACTIVE" => "Y", "GLOBAL_ACTIVE" => "Y", "IBLOCK_ACTIVE" => "Y", "<=LEFT_BORDER" => $arSection["LEFT_MARGIN"], ">=RIGHT_BORDER" => $arSection["RIGHT_MARGIN"] ), false, array('ID') ); while ($arSectionTree = $dbSectionTree->Fetch()) { $arSectionTree["ID"] = intval($arSectionTree["ID"]); $arSectionsTmp[] = $arSectionTree["ID"]; } unset($arSectionTree, $dbSectionTree); } unset($arSection, $dbSection); $stackCacheManager->Set("catalog_group_parents", $strCacheKey, $arSectionsTmp); } $arProductSections = array_merge($arProductSections, $arSectionsTmp); } unset($arElementSections, $dbElementSections); $arProductSections = array_unique($arProductSections); return $arProductSections; } public static function OnIBlockElementDelete($ProductID) { $result = Catalog\Model\Product::delete($ProductID); return $result->isSuccess(); } /** * @deprecated deprecated since catalog 17.6.3 * * @param array $arFields */ public static function OnAfterIBlockElementUpdate($arFields) {} public static function CheckProducts($arItemIDs) { if (!is_array($arItemIDs)) $arItemIDs = array($arItemIDs); Main\Type\Collection::normalizeArrayValuesByInt($arItemIDs); if (empty($arItemIDs)) return false; $arProductList = array(); $rsProducts = CCatalogProduct::GetList( array(), array('@ID' => $arItemIDs), false, false, array('ID') ); while ($arProduct = $rsProducts->Fetch()) { $arProduct['ID'] = (int)$arProduct['ID']; $arProductList[$arProduct['ID']] = true; } if (empty($arProductList)) return false; $boolFlag = true; foreach ($arItemIDs as &$intItemID) { if (!isset($arProductList[$intItemID])) { $boolFlag = false; break; } } unset($intItemID); return $boolFlag; } /** * Return payment period list. * * @deprecated deprected since catalog 17.0.0 * @see \Bitrix\Catalog\ProductTable::getPaymentPeriods * * @param bool $boolFull With description. * @return array */ public static function GetTimePeriodTypes($boolFull = false) { return Catalog\ProductTable::getPaymentPeriods($boolFull); } /** * Update result user handlers for event OnGetOptimalPrice. * * @param array &$userResult Optimal price array. * @param array $params GetOptimalPrice parameters. * @return void */ private static function updateUserHandlerOptimalPrice(&$userResult, array $params) { global $APPLICATION; if (empty($userResult) || !is_array($userResult)) { $userResult = false; return; } if ( (empty($userResult['PRICE']) || !is_array($userResult['PRICE'])) && ((empty($userResult['RESULT_PRICE']) || !is_array($userResult['RESULT_PRICE']))) ) { $userResult = false; return; } $resultCurrency = Catalog\Product\Price\Calculation::getCurrency(); if (empty($resultCurrency)) { $APPLICATION->ThrowException(Loc::getMessage("BT_MOD_CATALOG_PROD_ERR_NO_RESULT_CURRENCY")); $userResult = false; return; } if (!isset($userResult['PRODUCT_ID'])) $userResult['PRODUCT_ID'] = $params['PRODUCT_ID']; $oldDiscountExist = !empty($userResult['DISCOUNT']) && is_array($userResult['DISCOUNT']); if ($oldDiscountExist) { if (empty($userResult['DISCOUNT']['MODULE_ID'])) $userResult['DISCOUNT']['MODULE_ID'] = 'catalog'; if ($userResult['DISCOUNT']['CURRENCY'] != $resultCurrency) Catalog\DiscountTable::convertCurrency($userResult['DISCOUNT'], $resultCurrency); } if (!isset($userResult['DISCOUNT_LIST']) || !is_array($userResult['DISCOUNT_LIST'])) { $userResult['DISCOUNT_LIST'] = []; if ($oldDiscountExist) $userResult['DISCOUNT_LIST'][] = $userResult['DISCOUNT']; } unset($oldDiscountExist); foreach ($userResult['DISCOUNT_LIST'] as &$discount) { if (empty($discount['MODULE_ID'])) $discount['MODULE_ID'] = 'catalog'; if ($discount['CURRENCY'] != $resultCurrency) Catalog\DiscountTable::convertCurrency($discount, $resultCurrency); } unset($discount); if (isset($userResult['PRICE']) && is_array($userResult['PRICE'])) { if (!isset($userResult['PRICE']['VAT_RATE'])) { $vat = CCatalogProduct::GetVATDataByID($userResult['PRODUCT_ID']); if (!empty($vat)) $vat['RATE'] = (float)$vat['RATE'] * 0.01; else $vat = ['RATE' => 0.0, 'VAT_INCLUDED' => 'Y']; $userResult['PRICE']['VAT_RATE'] = $vat['RATE']; $userResult['PRICE']['VAT_INCLUDED'] = $vat['VAT_INCLUDED']; unset($vat); } } if (empty($userResult['RESULT_PRICE']) || !is_array($userResult['RESULT_PRICE'])) { $userResult['RESULT_PRICE'] = CCatalogDiscount::calculateDiscountList( $userResult['PRICE'], $resultCurrency, $userResult['DISCOUNT_LIST'], Catalog\Product\Price\Calculation::isIncludingVat() ); } if (!isset($userResult['RESULT_PRICE']['CURRENCY'])) $userResult['RESULT_PRICE']['CURRENCY'] = $resultCurrency; if (!isset($userResult['RESULT_PRICE']['PRICE_TYPE_ID'])) { if (isset($userResult['PRICE']['CATALOG_GROUP_ID'])) $userResult['RESULT_PRICE']['PRICE_TYPE_ID'] = $userResult['PRICE']['CATALOG_GROUP_ID']; } $componentResultMode = Catalog\Product\Price\Calculation::isComponentResultMode(); if (!isset($userResult['RESULT_PRICE']['UNROUND_DISCOUNT_PRICE'])) { $userResult['RESULT_PRICE']['UNROUND_DISCOUNT_PRICE'] = $userResult['RESULT_PRICE']['DISCOUNT_PRICE']; if ($componentResultMode) { $userResult['RESULT_PRICE']['DISCOUNT_PRICE'] = Catalog\Product\Price::roundPrice( $userResult['RESULT_PRICE']['PRICE_TYPE_ID'], $userResult['RESULT_PRICE']['DISCOUNT_PRICE'], $userResult['RESULT_PRICE']['CURRENCY'] ); } } if (!isset($userResult['RESULT_PRICE']['UNROUND_BASE_PRICE'])) { $userResult['RESULT_PRICE']['UNROUND_BASE_PRICE'] = $userResult['RESULT_PRICE']['BASE_PRICE']; if ($componentResultMode) { $userResult['RESULT_PRICE']['BASE_PRICE'] = Catalog\Product\Price::roundPrice( $userResult['RESULT_PRICE']['PRICE_TYPE_ID'], $userResult['RESULT_PRICE']['BASE_PRICE'], $userResult['RESULT_PRICE']['CURRENCY'] ); } } if ($componentResultMode) { if ( empty($userResult['DISCOUNT_LIST']) || Catalog\Product\Price\Calculation::compare( $userResult['RESULT_PRICE']['BASE_PRICE'], $userResult['RESULT_PRICE']['DISCOUNT_PRICE'], '<=' )) { $userResult['RESULT_PRICE']['BASE_PRICE'] = $userResult['RESULT_PRICE']['DISCOUNT_PRICE']; } } $discountValue = $userResult['RESULT_PRICE']['BASE_PRICE'] - $userResult['RESULT_PRICE']['DISCOUNT_PRICE']; $userResult['RESULT_PRICE']['DISCOUNT'] = $discountValue; $userResult['RESULT_PRICE']['PERCENT'] = ( $userResult['RESULT_PRICE']['BASE_PRICE'] > 0 && $discountValue > 0 ? round((100*$discountValue)/$userResult['RESULT_PRICE']['BASE_PRICE'], 0) : 0 ); unset($discountValue); if (!isset($userResult['RESULT_PRICE']['VAT_RATE'])) { if (isset($userResult['PRICE']['VAT_RATE'])) { $userResult['RESULT_PRICE']['VAT_RATE'] = $userResult['PRICE']['VAT_RATE']; $userResult['RESULT_PRICE']['VAT_INCLUDED'] = $userResult['PRICE']['VAT_INCLUDED']; } else { $vat = CCatalogProduct::GetVATDataByID($userResult['PRODUCT_ID']); if (!empty($vat)) $vat['RATE'] = (float)$vat['RATE'] * 0.01; else $vat = ['RATE' => 0.0, 'VAT_INCLUDED' => 'Y']; $userResult['RESULT_PRICE']['VAT_RATE'] = $vat['RATE']; $userResult['RESULT_PRICE']['VAT_INCLUDED'] = $vat['VAT_INCLUDED']; unset($vat); } } $userResult['DISCOUNT_PRICE'] = $userResult['RESULT_PRICE']['DISCOUNT_PRICE']; } /** * @deprecated deprecated since catalog 15.0.0 * @see CCatalogDiscount::applyDiscountList() * @see CCatalogDiscount::primaryDiscountFilter() * * @param array &$arDiscount * @param array &$arPriceDiscount * @param array &$arDiscSave * @param array &$arParams * * @return void */ protected static function __PrimaryDiscountFilter(&$arDiscount, &$arPriceDiscount, &$arDiscSave, &$arParams) { if (isset($arParams['PRICE']) && isset($arParams['CURRENCY'])) { $arParams['PRICE'] = (float)$arParams['PRICE']; $arParams['BASE_PRICE'] = $arParams['PRICE']; if ($arParams['PRICE'] > 0) { $arPriceDiscount = array(); $arDiscSave = array(); foreach ($arDiscount as $arOneDiscount) { $changeData = ($arParams['CURRENCY'] != $arOneDiscount['CURRENCY']); /** @noinspection PhpUnusedLocalVariableInspection */ $dblDiscountValue = 0.0; $arOneDiscount['PRIORITY'] = (int)$arOneDiscount['PRIORITY']; if (CCatalogDiscount::TYPE_FIX == $arOneDiscount['VALUE_TYPE']) { $dblDiscountValue = ( !$changeData ? $arOneDiscount['VALUE'] : round( CCurrencyRates::ConvertCurrency($arOneDiscount['VALUE'], $arOneDiscount['CURRENCY'], $arParams['CURRENCY']), CATALOG_VALUE_PRECISION ) ); if ($arParams['PRICE'] < $dblDiscountValue) continue; $arOneDiscount['DISCOUNT_CONVERT'] = $dblDiscountValue; if ($changeData) $arOneDiscount['VALUE'] = $arOneDiscount['DISCOUNT_CONVERT']; } elseif (CCatalogDiscount::TYPE_SALE == $arOneDiscount['VALUE_TYPE']) { $dblDiscountValue = ( !$changeData ? $arOneDiscount['VALUE'] : round( CCurrencyRates::ConvertCurrency($arOneDiscount['VALUE'], $arOneDiscount['CURRENCY'], $arParams['CURRENCY']), CATALOG_VALUE_PRECISION ) ); if ($arParams['PRICE'] <= $dblDiscountValue) continue; $arOneDiscount['DISCOUNT_CONVERT'] = $dblDiscountValue; if ($changeData) $arOneDiscount['VALUE'] = $arOneDiscount['DISCOUNT_CONVERT']; } elseif (CCatalogDiscount::TYPE_PERCENT == $arOneDiscount['VALUE_TYPE']) { if (100 < $arOneDiscount["VALUE"]) continue; if ($arOneDiscount['TYPE'] == CCatalogDiscount::ENTITY_ID && $arOneDiscount["MAX_DISCOUNT"] > 0) { $dblDiscountValue = ( !$changeData ? $arOneDiscount['MAX_DISCOUNT'] : round( CCurrencyRates::ConvertCurrency($arOneDiscount['MAX_DISCOUNT'], $arOneDiscount['CURRENCY'], $arParams['CURRENCY']), CATALOG_VALUE_PRECISION ) ); $arOneDiscount['DISCOUNT_CONVERT'] = $dblDiscountValue; if ($changeData) $arOneDiscount['MAX_DISCOUNT'] = $arOneDiscount['DISCOUNT_CONVERT']; } } if ($changeData) $arOneDiscount['CURRENCY'] = $arParams['CURRENCY']; if ($arOneDiscount['TYPE'] == CCatalogDiscountSave::ENTITY_ID) { $arDiscSave[] = $arOneDiscount; } else { $arPriceDiscount[$arOneDiscount['PRIORITY']][] = $arOneDiscount; } } if (!empty($arPriceDiscount)) krsort($arPriceDiscount); } } } /** * @deprecated deprecated since catalog 15.0.0 * @see CCatalogDiscount::applyDiscountList() * @see CCatalogDiscount::calculatePriorityLevel() * * @param array &$arDiscounts * @param array &$arResultDiscount * @param array &$arParams * * @return bool */ protected static function __CalcOnePriority(&$arDiscounts, &$arResultDiscount, &$arParams) { $boolResult = false; if (isset($arParams['PRICE']) && isset($arParams['CURRENCY'])) { $arParams['PRICE'] = (float)$arParams['PRICE']; $arParams['BASE_PRICE'] = (float)$arParams['BASE_PRICE']; if ($arParams['PRICE'] > 0) { $dblCurrentPrice = $arParams['PRICE']; do { $dblMinPrice = -1; $strMinKey = -1; $boolApply = false; foreach ($arDiscounts as $strDiscountKey => $arOneDiscount) { $boolDelete = false; $dblPriceTmp = -1; switch($arOneDiscount['VALUE_TYPE']) { case CCatalogDiscount::TYPE_PERCENT: $dblTempo = round(( CCatalogDiscount::getUseBasePrice() ? $arParams['BASE_PRICE'] : $dblCurrentPrice )*$arOneDiscount['VALUE']/100, CATALOG_VALUE_PRECISION ); if (isset($arOneDiscount['DISCOUNT_CONVERT'])) { if ($dblTempo > $arOneDiscount['DISCOUNT_CONVERT']) $dblTempo = $arOneDiscount['DISCOUNT_CONVERT']; } $dblPriceTmp = $dblCurrentPrice - $dblTempo; break; case CCatalogDiscount::TYPE_FIX: if ($arOneDiscount['DISCOUNT_CONVERT'] > $dblCurrentPrice) { $boolDelete = true; } else { $dblPriceTmp = $dblCurrentPrice - $arOneDiscount['DISCOUNT_CONVERT']; } break; case CCatalogDiscount::TYPE_SALE: if (!($arOneDiscount['DISCOUNT_CONVERT'] < $dblCurrentPrice)) { $boolDelete = true; } else { $dblPriceTmp = $arOneDiscount['DISCOUNT_CONVERT']; } break; } if ($boolDelete) { unset($arDiscounts[$strDiscountKey]); } else { if (-1 == $dblMinPrice || $dblMinPrice > $dblPriceTmp) { $dblMinPrice = $dblPriceTmp; $strMinKey = $strDiscountKey; $boolApply = true; } } } if ($boolApply) { $dblCurrentPrice = $dblMinPrice; $arResultDiscount[] = $arDiscounts[$strMinKey]; if ('Y' == $arDiscounts[$strMinKey]['LAST_DISCOUNT']) { $arDiscounts = array(); $arParams['LAST_DISCOUNT'] = 'Y'; } unset($arDiscounts[$strMinKey]); } } while (!empty($arDiscounts)); if ($boolApply) { $arParams['PRICE'] = $dblCurrentPrice; } $boolResult = true; } } return $boolResult; } /** * @deprecated deprecated since catalog 15.0.0 * @see CCatalogDiscount::applyDiscountList() * @see CCatalogDiscount::calculateDiscSave() * * @param array &$arDiscSave * @param array &$arResultDiscount * @param array &$arParams * * @return bool */ protected static function __CalcDiscSave(&$arDiscSave, &$arResultDiscount, &$arParams) { $boolResult = false; if (isset($arParams['PRICE']) && isset($arParams['CURRENCY'])) { $arParams['PRICE'] = (float)$arParams['PRICE']; if (0 < $arParams['PRICE']) { $dblCurrentPrice = $arParams['PRICE']; $dblMinPrice = -1; $strMinKey = -1; $boolApply = false; foreach ($arDiscSave as $strDiscountKey => $arOneDiscount) { $dblPriceTmp = -1; $boolDelete = false; switch($arOneDiscount['VALUE_TYPE']) { case CCatalogDiscountSave::TYPE_PERCENT: $dblPriceTmp = round($dblCurrentPrice*(1 - $arOneDiscount['VALUE']/100.0), CATALOG_VALUE_PRECISION); break; case CCatalogDiscountSave::TYPE_FIX: if ($arOneDiscount['DISCOUNT_CONVERT'] > $dblCurrentPrice) { $boolDelete = true; } else { $dblPriceTmp = $dblCurrentPrice - $arOneDiscount['DISCOUNT_CONVERT']; } break; } if (!$boolDelete) { if (-1 == $dblMinPrice || $dblMinPrice > $dblPriceTmp) { $dblMinPrice = $dblPriceTmp; $strMinKey = $strDiscountKey; $boolApply = true; } } } if ($boolApply) { $arParams['PRICE'] = $dblMinPrice; $arResultDiscount[] = $arDiscSave[$strMinKey]; } $boolResult = true; } } return $boolResult; } protected static function getQueryBuildCurrencyScale($filter, $priceTypeId) { $result = array(); if (!isset($filter['CATALOG_CURRENCY_SCALE_'.$priceTypeId])) return $result; $currencyId = Currency\CurrencyManager::checkCurrencyID($filter['CATALOG_CURRENCY_SCALE_'.$priceTypeId]); if ($currencyId === false) return $result; $currency = CCurrency::GetByID($currencyId); if (empty($currency)) return $result; $result['CURRENCY'] = $currency['CURRENCY']; $result['BASE_RATE'] = $currency['CURRENT_BASE_RATE']; return $result; } protected static function getQueryBuildPriceScaled($prices, $scale) { $result = array(); $scale = (float)$scale; if (!is_array($prices)) $prices = array($prices); if (empty($prices) || $scale <= 0) return $result; foreach ($prices as &$value) $result[] = (float)$value*$scale; unset($value); return $result; } protected static function initSaleSettings() { if (self::$saleIncluded === null) self::$saleIncluded = Main\Loader::includeModule('sale'); if (self::$saleIncluded) { self::$useSaleDiscount = (string)Main\Config\Option::get('sale', 'use_sale_discount_only') == 'Y'; if (self::$useSaleDiscount) { //TODO: replace runtime to reference after sale 17.5.2 will be stable $row = Sale\Internals\DiscountEntitiesTable::getList(array( 'select' => array('ID'), 'filter' => array( '=MODULE_ID' => 'catalog', '=ENTITY' => 'PRICE', '=FIELD_ENTITY' => 'CATALOG_GROUP_ID', '=FIELD_TABLE' => 'CATALOG_GROUP_ID', '=ACTIVE_DISCOUNT.ACTIVE' => 'Y' ), 'runtime' => array( new Main\Entity\ReferenceField( 'ACTIVE_DISCOUNT', 'Bitrix\Sale\Internals\Discount', array('=this.DISCOUNT_ID' => 'ref.ID'), array('join_type' => 'LEFT') ) ), 'limit' => 1, ))->fetch(); self::$existPriceTypeDiscounts = !empty($row); unset($row); } } } private static function isNeedleToMinimizeCatalogGroup(array $priceList) { if (self::$saleIncluded === null) self::initSaleSettings(); if ( !self::$saleIncluded || !self::$useSaleDiscount || count($priceList) < 2 ) return false; return self::$existPriceTypeDiscounts; } private static function getPossibleSalePrice($intProductID, array $priceData, $quantity, $siteID, array $userGroups, $coupons) { $possibleSalePrice = null; if (empty($priceData)) return $possibleSalePrice; $isCompatibilityUsed = Sale\Compatible\DiscountCompatibility::isUsed(); Sale\Compatible\DiscountCompatibility::stopUsageCompatible(); $freezeCoupons = (empty($coupons) && is_array($coupons)); if ($freezeCoupons) Sale\DiscountCouponsManager::freezeCouponStorage(); /** @var \Bitrix\Sale\Basket $basket */ static $basket = null, /** @var \Bitrix\Sale\BasketItem $basketItem */ $basketItem = null; if ($basket !== null) { if ($basket->getSiteId() != $siteID) { $basket = null; $basketItem = null; } } if ($basket === null) { $basket = Sale\Basket::create($siteID); $basketItem = $basket->createItem('catalog', $intProductID); } $fields = array( 'PRODUCT_ID' => $intProductID, 'QUANTITY' => $quantity, 'LID' => $siteID, 'PRODUCT_PRICE_ID' => $priceData['ID'], 'PRICE' => $priceData['PRICE'], 'BASE_PRICE' => $priceData['PRICE'], 'DISCOUNT_PRICE' => 0, 'CURRENCY' => $priceData['PRICE'], 'CAN_BUY' => 'Y', 'DELAY' => 'N', 'PRICE_TYPE_ID' => (int)$priceData['CATALOG_GROUP_ID'] ); /** @noinspection PhpInternalEntityUsedInspection */ $basketItem->setFieldsNoDemand($fields); $discount = Sale\Discount::buildFromBasket($basket, new Sale\Discount\Context\UserGroup($userGroups)); $discount->setExecuteModuleFilter(array('all', 'catalog')); $discount->calculate(); $calcResults = $discount->getApplyResult(true); if ($calcResults && !empty($calcResults['PRICES']['BASKET'])) { $possibleSalePrice = reset($calcResults['PRICES']['BASKET']); $possibleSalePrice = $possibleSalePrice['PRICE']; } if ($freezeCoupons) Sale\DiscountCouponsManager::unFreezeCouponStorage(); if ($isCompatibilityUsed === true) { Sale\Compatible\DiscountCompatibility::revertUsageCompatible(); } return $possibleSalePrice; } private static function checkPriceValue($price) { $result = false; if ($price !== null && $price !== false) { if (is_string($price)) { $price = str_replace(',', '.', $price); if ($price !== '' && is_numeric($price)) { $price = (float)$price; if (is_finite($price)) $result = $price; } } elseif ( is_int($price) || (is_float($price) && is_finite($price)) ) { $result = $price; } } return $result; } private static function checkPriceCurrency($currency) { $result = false; if ($currency !== null && $currency !== false && $currency !== '') $result = $currency; return $result; } /** * @param array $userGroups * @return array */ private static function getAllowedPriceTypes(array $userGroups) { static $priceTypeCache = array(); Main\Type\Collection::normalizeArrayValuesByInt($userGroups, true); if (empty($userGroups)) return array(); $cacheKey = 'U'.implode('_', $userGroups); if (!isset($priceTypeCache[$cacheKey])) { $priceTypeCache[$cacheKey] = array(); $priceIterator = Catalog\GroupAccessTable::getList(array( 'select' => array('CATALOG_GROUP_ID'), 'filter' => array('@GROUP_ID' => $userGroups, '=ACCESS' => Catalog\GroupAccessTable::ACCESS_BUY), 'order' => array('CATALOG_GROUP_ID' => 'ASC') )); while ($priceType = $priceIterator->fetch()) { $priceTypeId = (int)$priceType['CATALOG_GROUP_ID']; $priceTypeCache[$cacheKey][$priceTypeId] = $priceTypeId; unset($priceTypeId); } unset($priceType, $priceIterator); } return $priceTypeCache[$cacheKey]; } private static function convertErrors(Main\Entity\Result $result) { global $APPLICATION; $oldMessages = array(); foreach ($result->getErrorMessages() as $errorText) $oldMessages[] = array('text' => $errorText); unset($errorText); if (!empty($oldMessages)) { $error = new CAdminException($oldMessages); $APPLICATION->ThrowException($error); unset($error); } unset($oldMessages); } private static function normalizeFields(array &$fields) { if (isset($fields['QUANTITY']) && is_string($fields['QUANTITY']) && $fields['QUANTITY'] === '') $fields['QUANTITY'] = 0; if (isset($fields['QUANTITY_RESERVED']) && is_string($fields['QUANTITY_RESERVED']) && $fields['QUANTITY_RESERVED'] === '') $fields['QUANTITY_RESERVED'] = 0; if (isset($fields['WEIGHT']) && is_string($fields['WEIGHT']) && $fields['WEIGHT'] === '') $fields['WEIGHT'] = 0; } }