16 private static $separateSkuMode =
null;
18 private static $productPrices = [];
20 private static $basePriceType =
null;
22 private static $priceTypes =
null;
24 private static $extraList =
null;
26 private static $productList = [];
29 private static $queryElementDate;
38 return '\Bitrix\Catalog\PriceTable';
63 if (self::$separateSkuMode ===
null)
68 if (empty(self::$extraList) || self::$basePriceType == 0)
73 $iterator = Catalog\PriceTable::getList([
74 'select' => [
'ID',
'PRODUCT_ID',
'CATALOG_GROUP_ID',
'PRICE',
'CURRENCY',
'QUANTITY_FROM',
'QUANTITY_TO'],
75 'filter' => [
'=ID' => $id]
77 $price = $iterator->fetch();
82 $price[
'CATALOG_GROUP_ID'] = (int)$price[
'CATALOG_GROUP_ID'];
83 if ($price[
'CATALOG_GROUP_ID'] != self::$basePriceType)
86 $productId = (int)$price[
'PRODUCT_ID'];
92 !self::$separateSkuMode
98 $currency = \CCurrency::GetByID($price[
'CURRENCY']);
102 $filter = ORM\Query\Query::filter();
103 $filter->where(
'PRODUCT_ID',
'=', $productId);
104 $filter->where(
'CATALOG_GROUP_ID',
'!=', self::$basePriceType);
105 $filter->whereIn(
'EXTRA_ID', array_keys(self::$extraList));
106 if ($price[
'QUANTITY_FROM'] ===
null)
107 $filter->whereNull(
'QUANTITY_FROM');
109 $filter->where(
'QUANTITY_FROM',
'=', (
int)$price[
'QUANTITY_FROM']);
111 if ($price[
'QUANTITY_TO'] ===
null)
112 $filter->whereNull(
'QUANTITY_TO');
114 $filter->where(
'QUANTITY_TO',
'=', (
int)$price[
'QUANTITY_TO']);
117 $updatePriceTypes = [];
118 $iterator = Catalog\PriceTable::getList([
119 'select' => [
'ID',
'EXTRA_ID',
'CATALOG_GROUP_ID',
'QUANTITY_FROM',
'QUANTITY_TO'],
122 while ($row = $iterator->fetch())
125 'PRICE' => $price[
'PRICE']*self::$extraList[$row[
'EXTRA_ID']],
126 'CURRENCY' => $price[
'CURRENCY'],
127 'TIMESTAMP_X' => $datetime
129 $fields[
'PRICE_SCALE'] = $fields[
'PRICE']*$currency[
'CURRENT_BASE_RATE'];
131 $result = Catalog\PriceTable::update($row[
'ID'], $fields);
132 if ($result->isSuccess())
133 $updatePriceTypes[$row[
'CATALOG_TYPE_ID']] = $row[
'CATALOG_TYPE_ID'];
135 unset($result, $fields, $currency, $index);
136 unset($row, $iterator);
154 $fields = $data[
'fields'];
155 parent::prepareForAdd($result, $id, $fields);
156 if (!$result->isSuccess())
159 if (self::$separateSkuMode ===
null)
161 self::loadSettings();
164 static $defaultValues =
null,
167 if ($defaultValues ===
null)
171 'CATALOG_GROUP_ID' => 0,
175 'QUANTITY_FROM' =>
null,
176 'QUANTITY_TO' =>
null,
185 $fields = array_merge($defaultValues, array_diff_key($fields, $blackList));
187 $fields[
'PRODUCT_ID'] = (int)$fields[
'PRODUCT_ID'];
188 if ($fields[
'PRODUCT_ID'] <= 0)
195 $fields[
'CATALOG_GROUP_ID'] = (int)$fields[
'CATALOG_GROUP_ID'];
196 if (!isset(self::$priceTypes[$fields[
'CATALOG_GROUP_ID']]))
205 if ($fields[
'CATALOG_GROUP_ID'] == self::$basePriceType)
207 $fields[
'EXTRA_ID'] =
null;
208 if (isset($data[
'actions'][
'OLD_RECOUNT']))
210 if ($data[
'actions'][
'OLD_RECOUNT'] ===
true)
211 $data[
'actions'][
'PARENT_PRICE'] =
true;
216 if ($fields[
'TMP_ID'] !==
null)
217 $fields[
'TMP_ID'] = mb_substr($fields[
'TMP_ID'], 0, 40);
219 static::checkQuantityRange($result, $fields);
221 if ($fields[
'EXTRA_ID'] !==
null)
223 $fields[
'EXTRA_ID'] = (int)$fields[
'EXTRA_ID'];
224 if (!isset(self::$extraList[$fields[
'EXTRA_ID']]))
226 unset($fields[
'EXTRA_ID']);
231 (!isset($fields[
'PRICE']) && !isset($fields[
'CURRENCY']))
232 || (isset($data[
'actions'][
'OLD_RECOUNT']) && $data[
'actions'][
'OLD_RECOUNT'] ===
true)
234 self::calculatePriceFromBase(
null, $fields);
238 if ($fields[
'PRICE'] ===
null)
246 $fields[
'PRICE'] = self::checkPriceValue($fields[
'PRICE']);
247 if ($fields[
'PRICE'] ===
null || $fields[
'PRICE'] < 0)
254 $fields[
'CURRENCY'] = (string)$fields[
'CURRENCY'];
255 if (!Currency\CurrencyManager::isCurrencyExist($fields[
'CURRENCY']))
262 if ($result->isSuccess())
265 if (isset($fields[
'PRICE_SCALE']))
266 $fields[
'PRICE_SCALE'] = self::checkPriceValue($fields[
'PRICE_SCALE']);
268 if (!isset($fields[
'PRICE_SCALE']))
271 $currency = \CCurrency::GetByID($fields[
'CURRENCY']);
272 $fields[
'PRICE_SCALE'] = $fields[
'PRICE']*$currency[
'CURRENT_BASE_RATE'];
276 if (isset($data[
'actions'][
'PARENT_PRICE']))
277 unset($data[
'actions'][
'PARENT_PRICE']);
278 if (!self::$separateSkuMode)
282 $data[
'actions'][
'PARENT_PRICE'] =
true;
285 if (isset($data[
'actions'][
'RECOUNT_PRICES']))
287 if ($fields[
'CATALOG_GROUP_ID'] != self::$basePriceType)
288 unset($data[
'actions'][
'RECOUNT_PRICES']);
290 $data[
'actions'][
'RECOUNT_PRICES'] =
true;
293 $data[
'fields'] = $fields;
318 if (self::$separateSkuMode ===
null)
320 self::loadSettings();
323 $fields = $data[
'fields'];
324 parent::prepareForUpdate($result, $id, $fields);
325 if (!$result->isSuccess())
332 $fields = array_diff_key($fields, $blackList);
334 if (array_key_exists(
'PRODUCT_ID', $fields))
336 $fields[
'PRODUCT_ID'] = (int)$fields[
'PRODUCT_ID'];
337 if ($fields[
'PRODUCT_ID'] <= 0)
343 if (array_key_exists(
'CATALOG_GROUP_ID', $fields))
345 $fields[
'CATALOG_GROUP_ID'] = (int)$fields[
'CATALOG_GROUP_ID'];
346 if (!isset(self::$priceTypes[$fields[
'CATALOG_GROUP_ID']]))
354 if ($fields[
'CATALOG_GROUP_ID'] == self::$basePriceType)
356 $fields[
'EXTRA_ID'] =
null;
357 if (isset($data[
'actions'][
'OLD_RECOUNT']))
359 if ($data[
'actions'][
'OLD_RECOUNT'] ===
true)
360 $data[
'actions'][
'PARENT_PRICE'] =
true;
366 if (isset($fields[
'TMP_ID']))
367 $fields[
'TMP_ID'] = mb_substr($fields[
'TMP_ID'], 0, 40);
369 $existQuantityFrom = array_key_exists(
'QUANTITY_FROM', $fields);
370 $existQuantityTo = array_key_exists(
'QUANTITY_TO', $fields);
371 if ($existQuantityFrom != $existQuantityTo)
373 if ($existQuantityFrom)
375 Loc::getMessage(
'BX_CATALOG_MODEL_PRICE_ERR_QUANTITY_RANGE_LEFT_BORDER_ONLY')
379 Loc::getMessage(
'BX_CATALOG_MODEL_PRICE_ERR_QUANTITY_RANGE_RIGHT_BORDER_ONLY')
384 if ($existQuantityFrom)
385 static::checkQuantityRange($result, $fields);
387 unset($existQuantityTo, $existQuantityFrom);
389 if (isset($fields[
'EXTRA_ID']))
391 $fields[
'EXTRA_ID'] = (int)$fields[
'EXTRA_ID'];
392 if (!isset(self::$extraList[$fields[
'EXTRA_ID']]))
401 (!isset($fields[
'PRICE']) && !isset($fields[
'CURRENCY']))
402 || (isset($data[
'actions'][
'OLD_RECOUNT']) && $data[
'actions'][
'OLD_RECOUNT'] ===
true)
404 self::calculatePriceFromBase($id, $fields);
408 if (array_key_exists(
'PRICE', $fields))
410 $fields[
'PRICE'] = self::checkPriceValue($fields[
'PRICE']);
411 if ($fields[
'PRICE'] ===
null || $fields[
'PRICE'] < 0)
419 if (array_key_exists(
'CURRENCY', $fields))
421 $fields[
'CURRENCY'] = (string)$fields[
'CURRENCY'];
422 if (!Currency\CurrencyManager::isCurrencyExist($fields[
'CURRENCY']))
430 if ($result->isSuccess())
432 if (isset($data[
'actions'][
'PARENT_PRICE']))
433 unset($data[
'actions'][
'PARENT_PRICE']);
435 $priceScale = !isset($fields[
'PRICE_SCALE']) && (isset($fields[
'PRICE']) || isset($fields[
'CURRENCY']));
436 $needCalculatePrice = (
437 !self::$separateSkuMode
439 isset($fields[
'PRODUCT_ID'])
440 || isset($fields[
'CATALOG_GROUP_ID'])
441 || isset($fields[
'PRICE'])
442 || isset($fields[
'CURRENCY'])
445 $recountPrices = isset($data[
'actions'][
'RECOUNT_PRICES']);
448 if ($priceScale || $needCalculatePrice || $recountPrices)
449 $copyFields = array_merge(static::getCacheItem($id,
true), $fields);
451 if (isset($fields[
'PRICE_SCALE']))
453 $fields[
'PRICE_SCALE'] = self::checkPriceValue($fields[
'PRICE_SCALE']);
454 if ($fields[
'PRICE_SCALE'] ===
null || $fields[
'PRICE_SCALE'] < 0)
455 unset($fields[
'PRICE_SCALE']);
457 if (!isset($fields[
'PRICE_SCALE']))
459 if (isset($fields[
'PRICE']) || isset($fields[
'CURRENCY']))
462 $currency = \CCurrency::GetByID($copyFields[
'CURRENCY']);
463 $fields[
'PRICE_SCALE'] = $copyFields[
'PRICE']*$currency[
'CURRENT_BASE_RATE'];
467 if ($needCalculatePrice)
471 $data[
'actions'][
'PARENT_PRICE'] =
true;
474 if (isset($data[
'actions'][
'RECOUNT_PRICES']))
476 if ($copyFields[
'CATALOG_GROUP_ID'] != self::$basePriceType)
477 unset($data[
'actions'][
'RECOUNT_PRICES']);
479 $data[
'actions'][
'RECOUNT_PRICES'] =
true;
484 $data[
'fields'] = $fields;
498 if ((
int)$data[
'fields'][
'CATALOG_GROUP_ID'] === self::$basePriceType)
500 if (isset(self::$productPrices[$data[
'fields'][
'PRODUCT_ID']]))
502 unset(self::$productPrices[$data[
'fields'][
'PRODUCT_ID']]);
505 if (isset($data[
'actions'][
'RECOUNT_PRICES']))
507 self::recountPricesFromBase($id);
509 if (isset($data[
'actions'][
'PARENT_PRICE']))
511 Catalog\Product\Sku::calculatePrice(
512 $data[
'fields'][
'PRODUCT_ID'],
515 [0 => $data[
'fields'][
'CATALOG_GROUP_ID']]
518 self::updateProductModificationTime($data[
'fields'][
'PRODUCT_ID']);
530 $price = self::getCacheItem($id);
531 if ((
int)$price[
'CATALOG_GROUP_ID'] === self::$basePriceType)
533 if (isset(self::$productPrices[$price[
'PRODUCT_ID']]))
535 unset(self::$productPrices[$price[
'PRODUCT_ID']]);
538 if (isset($data[
'actions'][
'RECOUNT_PRICES']))
540 self::recountPricesFromBase($id);
542 if (isset($data[
'actions'][
'PARENT_PRICE']))
544 $priceTypes = [0 => $price[
'CATALOG_GROUP_ID']];
546 isset($price[self::PREFIX_OLD.
'CATALOG_GROUP_ID'])
547 && $price[self::PREFIX_OLD.
'CATALOG_GROUP_ID'] != $price[
'CATALOG_GROUP_ID']
549 $priceTypes[] = $price[self::PREFIX_OLD.
'CATALOG_GROUP_ID'];
550 Catalog\Product\Sku::calculatePrice(
553 isset($price[self::PREFIX_OLD.
'PRODUCT_ID'])
554 && $price[self::PREFIX_OLD.
'PRODUCT_ID'] != $price[
'PRODUCT_ID']
556 Catalog\Product\Sku::calculatePrice($price[self::PREFIX_OLD.
'PRODUCT_ID'],
null,
null, $priceTypes);
559 self::updateProductModificationTime($price[
'PRODUCT_ID']);
561 isset($price[self::PREFIX_OLD.
'PRODUCT_ID'])
562 && $price[self::PREFIX_OLD.
'PRODUCT_ID'] != $price[
'PRODUCT_ID']
565 self::updateProductModificationTime($price[self::PREFIX_OLD.
'PRODUCT_ID']);
578 $price = self::getCacheItem($id);
582 Catalog\Product\Sku::calculatePrice(
583 $price[self::PREFIX_OLD.
'PRODUCT_ID'],
586 [0 => $price[self::PREFIX_OLD.
'CATALOG_GROUP_ID']]
589 if (!empty($product))
591 self::updateProductModificationTime($price[self::PREFIX_OLD.
'PRODUCT_ID']);
593 unset($product, $price);
604 private static function checkQuantityRange(ORM\Data\
Result $result, array &$fields)
606 if ($fields[
'QUANTITY_FROM'] !==
null)
608 $fields[
'QUANTITY_FROM'] = (int)$fields[
'QUANTITY_FROM'];
609 if ($fields[
'QUANTITY_FROM'] <= 0)
614 if ($fields[
'QUANTITY_TO'] !=
null)
616 $fields[
'QUANTITY_TO'] = (int)$fields[
'QUANTITY_TO'];
617 if ($fields[
'QUANTITY_TO'] <= 0)
622 if ($fields[
'QUANTITY_FROM'] !==
null && $fields[
'QUANTITY_TO'] !=
null)
624 if ($fields[
'QUANTITY_FROM'] == 0 && $fields[
'QUANTITY_TO'] == 0)
626 $result->addError(
new ORM\EntityError(
627 Loc::getMessage(
'BX_CATALOG_MODEL_PRICE_ERR_WRONG_QUANTITY_RANGE_ZERO')
630 elseif ($fields[
'QUANTITY_FROM'] > $fields[
'QUANTITY_TO'])
632 $result->addError(
new ORM\EntityError(
634 'BX_CATALOG_MODEL_PRICE_ERR_WRONG_QUANTITY_RANGE_INVERT',
635 [
'#LEFT#' => $fields[
'QUANTITY_FROM'],
'#RIGHT#' => $fields[
'QUANTITY_TO']]
649 private static function checkPriceValue($price)
655 if (is_string($price))
657 if ($price !==
'' && is_numeric($price))
659 $price = (float)$price;
660 if (is_finite($price))
666 || (is_float($price) && is_finite($price))
676 private static function loadSettings()
678 self::$separateSkuMode = Main\Config\Option::get(
'catalog',
'show_catalog_tab_with_offers') ===
'Y';
680 self::$extraList = [];
683 self::$extraList[$row[
'ID']] = (100 + (float)$row[
'PERCENTAGE']) / 100;
688 self::$priceTypes = Catalog\GroupTable::getTypeList();;
691 private static function calculatePriceFromBase($id, array &$fields)
694 $copyFields = $fields;
696 !isset($fields[
'PRODUCT_ID'])
697 || !isset($fields[
'CATALOG_GROUP_ID'])
698 || !array_key_exists(
'QUANTITY_FROM', $fields)
699 || !array_key_exists(
'QUANTITY_TO', $fields)
705 $iterator = self::getList([
706 'select' => [
'ID',
'PRODUCT_ID',
'CATALOG_GROUP_ID',
'QUANTITY_FROM',
'QUANTITY_TO'],
707 'filter' => [
'=ID' => $id]
709 $data = $iterator->fetch();
713 $copyFields = array_merge($data, $copyFields);
729 if (!isset(self::$productPrices[$productId]))
730 self::loadProductBasePrices($productId);
732 $index = self::getPriceIndex($copyFields);
733 if (!isset(self::$productPrices[$productId][$index]))
736 $fields[
'PRICE'] = self::$productPrices[
$productId][$index][
'PRICE']*self::$extraList[$copyFields[
'EXTRA_ID']];
737 $fields[
'CURRENCY'] = self::$productPrices[
$productId][$index][
'CURRENCY'];
740 private static function getPriceIndex(array $row): string
742 return ($row[
'QUANTITY_FROM'] ===
null ?
'ZERO' : $row[
'QUANTITY_FROM']).
743 '-'.($row[
'QUANTITY_TO'] === null ?
'INF' : $row[
'QUANTITY_TO']);
746 private static function loadProductBasePrices($productId)
748 self::$productPrices = [
751 $iterator = Catalog\PriceTable::getList([
752 'select' => [
'ID',
'PRICE',
'CURRENCY',
'QUANTITY_FROM',
'QUANTITY_TO'],
753 'filter' => [
'=PRODUCT_ID' => $productId,
'=CATALOG_GROUP_ID' => self::$basePriceType]
755 while ($row = $iterator->fetch())
756 self::$productPrices[
$productId][self::getPriceIndex($row)] = $row;
757 unset($row, $iterator);
762 parent::clearSettings();
764 self::$separateSkuMode =
null;
765 self::$basePriceType =
null;
766 self::$priceTypes =
null;
767 self::$extraList =
null;
770 private static function updateProductModificationTime(
int $productId): void
772 if (!isset(self::$productList[$productId]))
774 self::$productList[$productId] =
true;
775 $conn = Main\Application::getConnection();
776 if (self::$queryElementDate ===
null)
778 $helper = $conn->getSqlHelper();
780 .
' set '.$helper->quote(
'TIMESTAMP_X') .
' = '.$helper->getCurrentDateTimeFunction()
781 .
' where '.$helper->quote(
'ID') .
'=';
783 $conn->queryExecute(self::$queryElementDate . $productId);
static loadMessages($file)
static getMessage($code, $replace=null, $language=null)