• Модуль: iblock
  • Путь к файлу: ~/bitrix/modules/iblock/lib/component/base.php
  • Класс: BitrixIblockComponentBase
  • Вызов: Base::calculatePriceBlock
protected function calculatePriceBlock(array $product, array $priceBlock, $ratio, $defaultBlock = false)
{
	if (empty($product) || empty($priceBlock))
		return null;

	$enableCompatible = $defaultBlock && $this->isEnableCompatible();

	if ($enableCompatible && !$this->arParams['USE_PRICE_COUNT'])
		$this->fillCompatibleRawPriceFields($product['ID'], $priceBlock);

	$userGroups = $this->getUserGroups();

	$baseCurrency = CurrencyCurrencyManager::getBaseCurrency();
	/** @var null|array $minimalPrice */
	$minimalPrice = null;
	/** @var null|array $minimalBuyerPrice */
	$minimalBuyerPrice = null;
	$fullPrices = array();

	$currencyConvert = $this->arParams['CONVERT_CURRENCY'] === 'Y';
	$resultCurrency = ($currencyConvert ? $this->storage['CONVERT_CURRENCY']['CURRENCY_ID'] : null);

	$vatRate = (float)$product['PRODUCT']['VAT_RATE'];
	$percentVat = $vatRate * 0.01;
	$percentPriceWithVat = 1 + $percentVat;
	$vatInclude = $product['PRODUCT']['VAT_INCLUDED'] === 'Y';

	$oldPrices = array();
	$oldMinPrice = false;
	$oldMatrix = false;
	if ($enableCompatible && $this->arParams['USE_PRICE_COUNT'])
	{
		$oldMatrix = $this->getCompatibleFieldValue($product['ID'], 'PRICE_MATRIX');
		if (empty($oldMatrix))
		{
			$oldMatrix = $this->getEmptyPriceMatrix();
			$oldMatrix['AVAILABLE'] = $product['PRODUCT']['AVAILABLE'];
		}
	}

	foreach ($priceBlock as $rawPrice)
	{
		$priceType = (int)$rawPrice['CATALOG_GROUP_ID'];
		$price = (float)$rawPrice['PRICE'];
		if (!$vatInclude)
			$price *= $percentPriceWithVat;
		$currency = $rawPrice['CURRENCY'];

		$changeCurrency = $currencyConvert && $currency !== $resultCurrency;
		if ($changeCurrency)
		{
			$price = CCurrencyRates::ConvertCurrency($price, $currency, $resultCurrency);
			$currency = $resultCurrency;
		}

		$discounts = array();
		if (CIBlockPriceTools::isEnabledCalculationDiscounts())
		{
			CCatalogDiscountSave::Disable();
			$discounts = CCatalogDiscount::GetDiscount(
				$product['ID'],
				$product['IBLOCK_ID'],
				array($priceType),
				$userGroups,
				'N',
				$this->getSiteId(),
				array()
			);
			CCatalogDiscountSave::Enable();
		}
		$discountPrice = CCatalogProduct::CountPriceWithDiscount(
			$price,
			$currency,
			$discounts
		);
		if ($discountPrice !== false)
		{
			$priceWithVat = array(
				'UNROUND_BASE_PRICE' => $price,
				'UNROUND_PRICE' => $discountPrice,
				'BASE_PRICE' => CatalogProductPrice::roundPrice(
					$priceType,
					$price,
					$currency
				),
				'PRICE' => CatalogProductPrice::roundPrice(
					$priceType,
					$discountPrice,
					$currency
				)
			);

			$price /= $percentPriceWithVat;
			$discountPrice /= $percentPriceWithVat;

			$priceWithoutVat = array(
				'UNROUND_BASE_PRICE' => $price,
				'UNROUND_PRICE' => $discountPrice,
				'BASE_PRICE' => CatalogProductPrice::roundPrice(
					$priceType,
					$price,
					$currency
				),
				'PRICE' => CatalogProductPrice::roundPrice(
					$priceType,
					$discountPrice,
					$currency
				)
			);

			if ($this->arParams['PRICE_VAT_INCLUDE'])
				$priceRow = $priceWithVat;
			else
				$priceRow = $priceWithoutVat;
			$priceRow['ID'] = $rawPrice['ID'];
			$priceRow['PRICE_TYPE_ID'] = $rawPrice['CATALOG_GROUP_ID'];
			$priceRow['CURRENCY'] = $currency;

			if (
				empty($discounts)
				|| ($priceRow['BASE_PRICE'] <= $priceRow['PRICE'])
			)
			{
				$priceRow['BASE_PRICE'] = $priceRow['PRICE'];
				$priceRow['DISCOUNT'] = 0;
				$priceRow['PERCENT'] = 0;
			}
			else
			{
				$priceRow['DISCOUNT'] = $priceRow['BASE_PRICE'] - $priceRow['PRICE'];
				$priceRow['PERCENT'] = roundEx(100*$priceRow['DISCOUNT']/$priceRow['BASE_PRICE'], 0);
			}
			if (isset($this->arParams['PRICE_VAT_SHOW_VALUE']) && $this->arParams['PRICE_VAT_SHOW_VALUE'])
				$priceRow['VAT'] = ($vatRate > 0 ? $priceWithVat['PRICE'] - $priceWithoutVat['PRICE'] : 0);

			if ($this->arParams['FILL_ITEM_ALL_PRICES'])
				$fullPrices[$priceType] = $priceRow;

			$priceRow['QUANTITY_FROM'] = $rawPrice['QUANTITY_FROM'];
			$priceRow['QUANTITY_TO'] = $rawPrice['QUANTITY_TO'];
			$priceRow['QUANTITY_HASH'] = $this->getQuantityRangeHash($rawPrice);
			$priceRow['MEASURE_RATIO_ID'] = $rawPrice['MEASURE_RATIO_ID'] ?? null;
			$priceRow['PRICE_SCALE'] = CCurrencyRates::ConvertCurrency(
				$priceRow['PRICE'],
				$priceRow['CURRENCY'],
				$baseCurrency
			);
			$priceRow['BASE_PRICE_SCALE'] = $rawPrice['PRICE_SCALE'];

			if (
				$minimalPrice === null
				|| $minimalPrice['PRICE_SCALE'] > $priceRow['PRICE_SCALE']
			)
			{
				$minimalPrice = $priceRow;
			}
			elseif (
				$minimalPrice['PRICE_SCALE'] == $priceRow['PRICE_SCALE']
				&& $minimalPrice['BASE_PRICE_SCALE'] > $priceRow['BASE_PRICE_SCALE']
			)
			{
				$minimalPrice = $priceRow;
			}
			if (isset($this->storage['PRICES_CAN_BUY'][$priceRow['PRICE_TYPE_ID']]))
			{
				if (
					$minimalBuyerPrice === null
					|| $minimalBuyerPrice['PRICE_SCALE'] > $priceRow['PRICE_SCALE']
				)
				{
					$minimalBuyerPrice = $priceRow;
				}
				elseif (
					$minimalBuyerPrice['PRICE_SCALE'] == $priceRow['PRICE_SCALE']
					&& $minimalBuyerPrice['BASE_PRICE_SCALE'] > $priceRow['BASE_PRICE_SCALE']
				)
				{
					$minimalBuyerPrice = $priceRow;
				}
			}

			if ($enableCompatible)
			{
				if ($this->arParams['USE_PRICE_COUNT'])
				{
					$rowIndex = $this->getQuantityRangeHash($rawPrice);
					$oldMatrix['ROWS'][$rowIndex] = array(
						'QUANTITY_FROM' => (float)$rawPrice['QUANTITY_FROM'],
						'QUANTITY_TO' => (float)$rawPrice['QUANTITY_TO']
					);
					if (!isset($oldMatrix['MATRIX'][$priceType]))
					{
						$oldMatrix['MATRIX'][$priceType] = array();
						$oldMatrix['COLS'][$priceType] = $this->storage['PRICE_TYPES'][$priceType];
					}
					$oldMatrix['MATRIX'][$priceType][$rowIndex] = array(
						'ID' => $priceRow['ID'],
						'PRICE' => $priceRow['BASE_PRICE'],
						'DISCOUNT_PRICE' => $priceRow['PRICE'],
						'UNROUND_DISCOUNT_PRICE' => $priceRow['UNROUND_PRICE'],
						'CURRENCY' => $priceRow['CURRENCY'],
						'VAT_RATE' => $percentVat
					);
					if ($changeCurrency)
					{
						$oldMatrix['MATRIX'][$priceType][$rowIndex]['ORIG_CURRENCY'] = $rawPrice['CURRENCY'];
						$oldMatrix['MATRIX'][$priceType][$rowIndex]['ORIG_PRICE'] = CCurrencyRates::ConvertCurrency(
							$priceRow['BASE_PRICE'],
							$priceRow['CURRENCY'],
							$rawPrice['CURRENCY']
						);
						$oldMatrix['MATRIX'][$priceType][$rowIndex]['ORIG_DISCOUNT_PRICE'] = CCurrencyRates::ConvertCurrency(
							$priceRow['PRICE'],
							$priceRow['CURRENCY'],
							$rawPrice['CURRENCY']
						);
						$oldMatrix['MATRIX'][$priceType][$rowIndex]['ORIG_VAT_RATE'] = $percentVat; // crazy key, but above all the compatibility
					}
				}
				else
				{
					$priceCode = $this->storage['PRICES_MAP'][$priceType];
					$oldPriceRow = array(
						'PRICE_ID' => $priceRow['PRICE_TYPE_ID'],
						'ID' => $priceRow['ID'],
						'CAN_ACCESS' => ($this->storage['PRICES'][$priceCode]['CAN_VIEW'] ? 'Y' : 'N'),
						'CAN_BUY' => ($this->storage['PRICES'][$priceCode]['CAN_BUY'] ? 'Y' : 'N'),
						'MIN_PRICE' => 'N',
						'CURRENCY' => $priceRow['CURRENCY'],
						'VALUE_VAT' => $priceWithVat['UNROUND_BASE_PRICE'],
						'VALUE_NOVAT' => $priceWithoutVat['UNROUND_BASE_PRICE'],
						'DISCOUNT_VALUE_VAT' => $priceWithVat['UNROUND_PRICE'],
						'DISCOUNT_VALUE_NOVAT' => $priceWithoutVat['UNROUND_PRICE'],
						'ROUND_VALUE_VAT' => $priceWithVat['PRICE'],
						'ROUND_VALUE_NOVAT' => $priceWithoutVat['PRICE'],
						'VALUE' => $priceRow['BASE_PRICE'],
						'UNROUND_DISCOUNT_VALUE' => $priceRow['UNROUND_PRICE'],
						'DISCOUNT_VALUE' => $priceRow['PRICE'],
						'DISCOUNT_DIFF' => $priceRow['DISCOUNT'],
						'DISCOUNT_DIFF_PERCENT' => $priceRow['PERCENT']
					);
					$oldPriceRow['VATRATE_VALUE'] = $oldPriceRow['VALUE_VAT'] - $oldPriceRow['VALUE_NOVAT'];
					$oldPriceRow['DISCOUNT_VATRATE_VALUE'] = $oldPriceRow['DISCOUNT_VALUE_VAT'] - $oldPriceRow['DISCOUNT_VALUE_NOVAT'];
					$oldPriceRow['ROUND_VATRATE_VALUE'] = $oldPriceRow['ROUND_VALUE_VAT'] - $oldPriceRow['ROUND_VALUE_NOVAT'];
					if ($changeCurrency)
						$oldPriceRow['ORIG_CURRENCY'] = $rawPrice['CURRENCY'];
					$oldPrices[$priceCode] = $oldPriceRow;
					unset($oldPriceRow);
				}
			}
		}
		unset($discounts);
		unset($priceType);
	}
	unset($price);

	$minimalPriceId = null;
	if (is_array($minimalBuyerPrice))
		$minimalPrice = $minimalBuyerPrice;
	if (is_array($minimalPrice))
	{
		unset($minimalPrice['PRICE_SCALE']);
		unset($minimalPrice['BASE_PRICE_SCALE']);
		$minimalPriceId = $minimalPrice['PRICE_TYPE_ID'];
		$prepareFields = array(
			'BASE_PRICE', 'PRICE', 'DISCOUNT'
		);
		if (isset($this->arParams['PRICE_VAT_SHOW_VALUE']) && $this->arParams['PRICE_VAT_SHOW_VALUE'])
			$prepareFields[] = 'VAT';

		foreach ($prepareFields as $fieldName)
		{
			$minimalPrice['PRINT_'.$fieldName] = CCurrencyLang::CurrencyFormat(
				$minimalPrice[$fieldName],
				$minimalPrice['CURRENCY'],
				true
			);
			$minimalPrice['RATIO_'.$fieldName] = $minimalPrice[$fieldName]*$ratio;
			$minimalPrice['PRINT_RATIO_'.$fieldName] = CCurrencyLang::CurrencyFormat(
				$minimalPrice['RATIO_'.$fieldName],
				$minimalPrice['CURRENCY'],
				true
			);
		}
		unset($fieldName);

		if ($this->arParams['FILL_ITEM_ALL_PRICES'])
		{
			foreach (array_keys($fullPrices) as $priceType)
			{
				foreach ($prepareFields as $fieldName)
				{
					$fullPrices[$priceType]['PRINT_'.$fieldName] = CCurrencyLang::CurrencyFormat(
						$fullPrices[$priceType][$fieldName],
						$fullPrices[$priceType]['CURRENCY'],
						true
					);
					$fullPrices[$priceType]['RATIO_'.$fieldName] = $fullPrices[$priceType][$fieldName]*$ratio;
					$fullPrices[$priceType]['PRINT_RATIO_'.$fieldName] = CCurrencyLang::CurrencyFormat(
						$minimalPrice['RATIO_'.$fieldName],
						$minimalPrice['CURRENCY'],
						true
					);
				}
				unset($fieldName);
			}
			unset($priceType);
		}

		unset($prepareFields);
	}

	if ($enableCompatible)
	{
		if ($this->arParams['USE_PRICE_COUNT'])
		{
			$oldMatrix['CAN_BUY'] = array_values($this->storage['PRICES_CAN_BUY']);
			$this->oldData[$product['ID']]['PRICE_MATRIX'] = $oldMatrix;
		}
		else
		{
			$convertFields = array(
				'VALUE_NOVAT', 'VALUE_VAT', 'VATRATE_VALUE',
				'DISCOUNT_VALUE_NOVAT', 'DISCOUNT_VALUE_VAT', 'DISCOUNT_VATRATE_VALUE'
			);

			$prepareFields = array(
				'VALUE_NOVAT', 'VALUE_VAT', 'VATRATE_VALUE',
				'DISCOUNT_VALUE_NOVAT', 'DISCOUNT_VALUE_VAT', 'DISCOUNT_VATRATE_VALUE',
				'VALUE', 'DISCOUNT_VALUE', 'DISCOUNT_DIFF'
			);

			if (!empty($oldPrices))
			{
				foreach (array_keys($oldPrices) as $index)
				{
					foreach ($prepareFields as $fieldName)
						$oldPrices[$index]['PRINT_'.$fieldName] = CCurrencyLang::CurrencyFormat(
							$oldPrices[$index][$fieldName],
							$oldPrices[$index]['CURRENCY'],
							true
						);
					unset($fieldName);
					if (isset($oldPrices[$index]['ORIG_CURRENCY']))
					{
						foreach ($convertFields as $fieldName)
							$oldPrices[$index]['ORIG_' . $fieldName] = CCurrencyRates::ConvertCurrency(
								$oldPrices[$index][$fieldName],
								$oldPrices[$index]['CURRENCY'],
								$oldPrices[$index]['ORIG_CURRENCY']
							);
						unset($fieldName);
					}
					if ($oldPrices[$index]['PRICE_ID'] === $minimalPriceId)
					{
						$oldPrices[$index]['MIN_PRICE'] = 'Y';
						$oldMinPrice = $oldPrices[$index];
					}
				}
				unset($index);
			}
			unset($prepareFields);

			$this->oldData[$product['ID']]['PRICES'] = $oldPrices;
			$this->oldData[$product['ID']]['MIN_PRICE'] = $oldMinPrice;
		}
	}
	unset($oldMatrix, $oldMinPrice, $oldPrices);

	if (!$this->arParams['FILL_ITEM_ALL_PRICES'])
		return $minimalPrice;

	return array(
		'MINIMAL_PRICE' => $minimalPrice,
		'ALL_PRICES' => array(
			'QUANTITY_FROM' => $minimalPrice['QUANTITY_FROM'],
			'QUANTITY_TO' => $minimalPrice['QUANTITY_TO'],
			'QUANTITY_HASH' => $minimalPrice['QUANTITY_HASH'],
			'MEASURE_RATIO_ID' => $minimalPrice['MEASURE_RATIO_ID'],
			'PRICES' => $fullPrices
		)
	);
}