52 public static function prepareData(array $discount, $params = [])
54 if (empty($discount) || empty($discount[
'ID']))
57 $discountId = (int)$discount[
'ID'];
60 if (!isset(self::$discountCache[$discountId]))
62 self::$discountCache[$discountId] =
false;
65 if (!empty($loadData))
67 $loadData[
'LAST_LEVEL_DISCOUNT'] =
'N';
68 if ($loadData[
'CURRENCY'] != $params[
'CURRENCY'])
69 Catalog\DiscountTable::convertCurrency($loadData, $params[
'CURRENCY']);
72 'ID' => $discountId,
'TYPE' => $loadData[
'TYPE']
74 self::$discountCache[$discountId] = $loadData;
77 $result = self::$discountCache[$discountId];
80 if ($result[
'USE_COUPONS'] ==
'Y')
82 if (isset($discount[
'COUPON']))
83 $result[
'COUPON'] = $discount[
'COUPON'];
95 public static function getEditUrl(array $discount): string
97 if (empty(self::$editUrlTemplate))
99 self::$editUrlTemplate = [
100 Catalog\DiscountTable::TYPE_DISCOUNT =>
'/bitrix/admin/cat_discount_edit.php?lang='.LANGUAGE_ID.
'&ID=',
101 Catalog\DiscountTable::TYPE_DISCOUNT_SAVE =>
'/bitrix/admin/cat_discsave_edit.php?lang='.LANGUAGE_ID.
'&ID='
105 if (empty($discount[
'ID']) || (
int)$discount[
'ID'] <= 0)
108 $id = (int)$discount[
'ID'];
110 if (isset($discount[
'TYPE']))
111 $type = (
int)$discount[
'TYPE'];
115 if (isset(self::$typeCache[$id]))
117 $type = self::$typeCache[$id];
121 $discountIterator = Catalog\DiscountTable::getList([
122 'select' => [
'ID',
'TYPE'],
123 'filter' => [
'=ID' => $id]
125 $data = $discountIterator->fetch();
128 $type = (int)$data[
'TYPE'];
129 self::$typeCache[$id] = $type;
131 unset($data, $discountIterator);
134 if (isset(self::$editUrlTemplate[$type]))
135 $result = self::$editUrlTemplate[$type].$id;
153 if (empty($couponsList))
157 $filteredBasket = array_filter($basket,
'\Bitrix\Catalog\Discount\DiscountManager::basketFilter');
158 if (empty($filteredBasket))
160 $filteredBasket = array_filter($filteredBasket,
'\Bitrix\Catalog\Discount\DiscountManager::lastDiscountFilter');
161 if (empty($filteredBasket))
164 $filteredCoupons = [];
165 foreach ($couponsList as $coupon)
167 if (!isset($coupon[
'COUPON']) || $coupon[
'COUPON'] ==
'')
169 if (!isset($coupon[
'DISCOUNT_ID']) || (
int)$coupon[
'DISCOUNT_ID'] <= 0)
171 $filteredCoupons[] = $coupon[
'COUPON'];
174 if (empty($filteredCoupons))
178 $discountCoupons = [];
180 $couponsIterator = Catalog\DiscountCouponTable::getList([
181 'select' => [
'ID',
'COUPON',
'DISCOUNT_ID',
'TYPE'],
182 'filter' => [
'@COUPON' => $filteredCoupons,
'ACTIVE' =>
'Y']
184 while ($coupon = $couponsIterator->fetch())
186 $discountIds[$coupon[
'DISCOUNT_ID']] =
true;
187 $discountCoupons[$coupon[
'COUPON']] = $coupon[
'COUPON'];
189 $oneRowCoupons[$coupon[
'COUPON']] =
true;
191 unset($coupon, $couponsIterator);
192 if (empty($discountCoupons))
195 $userId = (isset($params[
'USER_ID']) ? (int)$params[
'USER_ID'] : 0);
198 $userGroups = Main\UserTable::getUserGroupIds($userId);
202 $product2Iblock = [];
204 foreach ($filteredBasket as $basketItem)
206 $productId = (int)$basketItem[
'PRODUCT_ID'];
207 $itemIds[$productId] = $productId;
211 $itemIterator = Iblock\ElementTable::getList([
212 'select' => [
'ID',
'IBLOCK_ID'],
213 'filter' => [
'@ID' => $itemIds,
'=ACTIVE' =>
'Y']
215 while ($item = $itemIterator->fetch())
217 $id = (int)$item[
'ID'];
218 $iblockId = (int)$item[
'IBLOCK_ID'];
219 if (!isset($iblockList[$iblockId]))
220 $iblockList[$iblockId] = [];
221 $iblockList[$iblockId][$id] = $id;
222 $product2Iblock[$id] = $iblockId;
223 unset($iblockId, $id);
225 unset($item, $itemIterator);
228 if (empty($iblockList))
231 foreach($iblockList as $iblockId => $elements)
234 \CCatalogDiscount::setProductSectionsCache($elements);
236 \CCatalogDiscount::setDiscountProductCache($elements, [
'IBLOCK_ID' => $iblockId,
'GET_BY_ID' =>
'Y']);
238 unset($iblockId, $elements);
240 $discountPercentMode = \CCatalogDiscount::getUseBasePrice();
241 if (isset($params[
'USE_BASE_PRICE']))
242 \CCatalogDiscount::setUseBasePrice($params[
'USE_BASE_PRICE'] ==
'Y');
244 Main\Type\Collection::sortByColumn($filteredBasket, [
'PRICE' => SORT_DESC],
'',
null,
true);
245 foreach ($filteredBasket as $basketCode => $basketItem)
247 $productId = (int)$basketItem[
'PRODUCT_ID'];
248 if (!isset($product2Iblock[$productId]))
250 if (empty($discountCoupons))
254 $discountList = \CCatalogDiscount::getDiscount(
256 $product2Iblock[$productId],
264 if (empty($discountList))
268 foreach ($discountList as $discount)
270 if (!isset($discountIds[$discount[
'ID']]))
272 $itemDiscounts[] = $discount;
274 unset($discount, $discountList);
275 if (empty($itemDiscounts))
278 $itemsDiscountResult = \CCatalogDiscount::applyDiscountList($basketItem[
'PRICE'], $basketItem[
'CURRENCY'], $itemDiscounts);
279 unset($itemDiscounts);
280 if (!empty($itemsDiscountResult[
'DISCOUNT_LIST']))
282 $result[$basketCode] = [];
283 foreach ($itemsDiscountResult[
'DISCOUNT_LIST'] as $discount)
285 $result[$basketCode][] = \CCatalogDiscount::getDiscountDescription($discount);
286 if (!empty($discount[
'COUPON']) && isset($oneRowCoupons[$discount[
'COUPON']]))
287 unset($discountCoupons[$discount[
'COUPON']]);
291 unset($itemsDiscountResult);
293 unset($basketCode, $basketItem, $basketItem);
295 \CCatalogDiscount::setUseBasePrice($discountPercentMode);
296 unset($discountPercentMode);
328 public static function roundBasket(array $basket, array $basketRoundData = [], array $order = []): array
334 $basket = array_filter($basket,
'\Bitrix\Catalog\Discount\DiscountManager::basketFilter');
339 $loadBasketCodes = [];
340 foreach ($basket as $basketCode => $basketItem)
342 if (!empty($basketRoundData[$basketCode]))
345 if (isset($basketItem[
'PRICE_TYPE_ID']))
346 $priceTypeId = (int)$basketItem[
'PRICE_TYPE_ID'];
347 if ($priceTypeId <= 0 && isset($basketItem[
'CATALOG_GROUP_ID']))
348 $priceTypeId = (
int)$basketItem[
'CATALOG_GROUP_ID'];
349 if ($priceTypeId <= 0 && isset($basketItem[
'PRODUCT_PRICE_ID']))
351 $priceId = (int)$basketItem[
'PRODUCT_PRICE_ID'];
354 $cachedPrice = self::getPriceDataByPriceId($priceId);
355 if (!empty($cachedPrice))
356 $priceTypeId = (int)$cachedPrice[
'CATALOG_GROUP_ID'];
357 if ($priceTypeId <= 0)
359 $loadPriceId[] = $priceId;
360 $loadBasketCodes[$priceId] = $basketCode;
365 $basket[$basketCode][
'PRICE_TYPE_ID'] = $priceTypeId;
366 if ($priceTypeId > 0)
367 $priceTypes[$priceTypeId] = $priceTypeId;
370 unset($priceId, $priceTypeId, $basketCode, $basketItem);
372 if (!empty($loadPriceId))
375 foreach (array_chunk($loadPriceId, 500) as $pageIds)
377 $iterator = Catalog\PriceTable::getList([
378 'select' => [
'ID',
'CATALOG_GROUP_ID'],
379 'filter' => [
'@ID' => $pageIds]
381 while ($row = $iterator->fetch())
383 $id = (int)$row[
'ID'];
384 $priceTypeId = (int)$row[
'CATALOG_GROUP_ID'];
385 if (!isset($loadBasketCodes[$id]))
387 $basket[$loadBasketCodes[$id]][
'PRICE_TYPE_ID'] = $priceTypeId;
388 $priceTypes[$priceTypeId] = $priceTypeId;
390 unset($priceTypeId, $id, $row, $iterator);
393 unset($loadBasketCodes, $loadPriceId);
395 if (!empty($priceTypes))
396 Catalog\Product\Price::loadRoundRules($priceTypes);
399 foreach ($basket as $basketCode => $basketItem)
401 if (!empty($basketRoundData[$basketCode]))
403 $roundData = $basketRoundData[$basketCode];
407 $roundData = Catalog\Product\Price::searchRoundRule(
408 $basketItem[
'PRICE_TYPE_ID'],
409 $basketItem[
'PRICE'],
410 $basketItem[
'CURRENCY']
414 if (empty($roundData))
419 $result[$basketCode] = self::getRoundResult($basketItem, $roundData);
421 unset($roundData, $basketCode, $basketItem, $basketRoundData);
438 if (empty($product) || !is_array($product))
440 if (empty($discount) || empty($discount[
'TYPE']))
442 if (isset($discount[
'CURRENCY']) && $discount[
'CURRENCY'] != $product[
'CURRENCY'])
444 if (!isset($product[
'DISCOUNT_PRICE']))
445 $product[
'DISCOUNT_PRICE'] = 0;
446 $getPercentFromBasePrice = (isset($discount[
'USE_BASE_PRICE']) && $discount[
'USE_BASE_PRICE'] ==
'Y');
447 $basePrice = (float)(
448 isset($product[
'BASE_PRICE'])
449 ? $product[
'BASE_PRICE']
450 : $product[
'PRICE'] + $product[
'DISCOUNT_PRICE']
453 switch ($discount[
'TYPE'])
455 case Catalog\DiscountTable::VALUE_TYPE_PERCENT:
456 $discount[
'VALUE'] = -$discount[
'VALUE'];
459 $getPercentFromBasePrice
462 )*$discount[
'VALUE'])/100,
465 if (isset($discount[
'MAX_VALUE']) && $discount[
'MAX_VALUE'] > 0)
467 if ($discountValue + $discount[
'MAX_VALUE'] <= 0)
468 $discountValue = -$discount[
'MAX_VALUE'];
470 $product[
'PRICE'] += $discountValue;
471 $product[
'DISCOUNT_PRICE'] -= $discountValue;
472 if (!empty($product[
'DISCOUNT_RESULT']))
474 $product[
'DISCOUNT_RESULT'][
'BASKET'][0][
'RESULT_VALUE'] = (string)abs($discountValue);
475 $product[
'DISCOUNT_RESULT'][
'BASKET'][0][
'RESULT_UNIT'] = $product[
'CURRENCY'];
477 unset($discountValue);
479 case Catalog\DiscountTable::VALUE_TYPE_FIX:
480 $discount[
'VALUE'] =
self::roundValue($discount[
'VALUE'], $product[
'CURRENCY']);
481 $product[
'PRICE'] -= $discount[
'VALUE'];
482 $product[
'DISCOUNT_PRICE'] += $discount[
'VALUE'];
484 case Catalog\DiscountTable::VALUE_TYPE_SALE:
485 $discount[
'VALUE'] =
self::roundValue($discount[
'VALUE'], $product[
'CURRENCY']);
486 $product[
'DISCOUNT_PRICE'] += ($product[
'PRICE'] - $discount[
'VALUE']);
487 $product[
'PRICE'] = $discount[
'VALUE'];
564 if (empty($productIds) || empty($catalogGroups))
566 Collection::normalizeArrayValuesByInt($productIds);
567 if (empty($productIds))
569 Collection::normalizeArrayValuesByInt($catalogGroups);
570 if (empty($catalogGroups))
575 foreach($productIds as $i => $productId)
577 if(isset(self::$preloadedPriceData[$productId]))
579 unset($productIds[$i]);
583 if(empty($productIds))
588 $dbPrice = Catalog\PriceTable::getList([
590 'filter' => [
'@PRODUCT_ID' => $productIds,
'@CATALOG_GROUP_ID' => $catalogGroups]
592 while($priceRow = $dbPrice->fetch())
594 self::$preloadedPriceData[$priceRow[
'PRODUCT_ID'].
'-'.$priceRow[
'CATALOG_GROUP_ID']] = $priceRow;
628 if (empty($productIds) || empty($userGroups))
630 Collection::normalizeArrayValuesByInt($productIds,
true);
631 if (empty($productIds))
633 Collection::normalizeArrayValuesByInt($userGroups,
true);
634 if (empty($userGroups))
637 if(self::$saleIncluded ===
null)
638 self::$saleIncluded = Loader::includeModule(
'sale');
640 if(!self::$saleIncluded)
643 $discountCache = Sale\Discount\RuntimeCache\DiscountCache::getInstance();
651 Collection::normalizeArrayValuesByInt($discountIds,
true);
654 if(!$entityList || empty($entityList[
'catalog']))
670 $productData = array_fill_keys($productIds, []);
671 if(empty($iblockData[
'iblockElement']))
679 if(!isset(self::$preloadedProductsData[$cacheKeyForEntityList]))
681 self::$preloadedProductsData[$cacheKeyForEntityList] = [];
684 foreach($productData as $productId => $data)
686 self::$preloadedProductsData[$cacheKeyForEntityList][$productId] = $data;
700 $orderData = $event->getParameter(
'ORDER');
701 $entityList = $event->getParameter(
'ENTITY');
704 if (empty($orderData) || !is_array($orderData))
710 if (!isset($orderData[
'BASKET_ITEMS']) || !is_array($orderData[
'BASKET_ITEMS']))
718 && !empty($orderData[
'BASKET_ITEMS'])
722 if (empty($entityData))
732 $basket = array_filter($orderData[
'BASKET_ITEMS'],
'\Bitrix\Catalog\Discount\DiscountManager::basketFilter');
735 foreach ($basket as $basketCode => $basketItem)
737 $basketItem[
'PRODUCT_ID'] = (int)$basketItem[
'PRODUCT_ID'];
738 $productList[] = $basketItem[
'PRODUCT_ID'];
739 if (!isset($productMap[$basketItem[
'PRODUCT_ID']]))
741 $productMap[$basketItem[
'PRODUCT_ID']] = [];
743 $productMap[$basketItem[
'PRODUCT_ID']][] = &$basket[$basketCode];
745 if (isset($basketItem[
'PRODUCT_PRICE_ID']))
747 $priceList[] = $basketItem[
'PRODUCT_PRICE_ID'];
750 unset($basketItem, $basketCode);
752 if(isset(self::$preloadedProductsData[$cacheKeyForEntityList]))
754 $preloadedProductIds = array_keys(self::$preloadedProductsData[$cacheKeyForEntityList]);
755 $loadedProductIds = array_intersect($productList, $preloadedProductIds);
757 $productList = array_diff($productList, $preloadedProductIds);
760 $productData = array_fill_keys($productList, []);
770 if (!empty($iblockData[
'iblockElement']))
775 if(!empty($loadedProductIds))
777 foreach($loadedProductIds as $loadedProductId)
779 $productData[$loadedProductId] = self::$preloadedProductsData[$cacheKeyForEntityList][$loadedProductId];
782 if(!empty($entityData[
'priceFields']))
784 self::fillByPreloadedPrices($productData, $priceList);
790 foreach ($productData as $product => $data)
792 if (empty($productMap[$product]))
794 foreach ($productMap[$product] as &$basketItem)
795 $basketItem[
'CATALOG'] = $data;
798 unset($product, $data);
800 $resultData[
'BASKET_ITEMS'] = $basket;
802 unset($basket, $productData, $productMap, $productList);
806 $result =
new Main\EventResult(Main\EventResult::SUCCESS, $resultData,
'catalog');
809 unset($process, $resultData);
823 Collection::normalizeArrayValuesByInt($productIds);
824 if (empty($productIds))
826 $key = md5(implode(
'|', $productIds));
828 if(!isset($cache[$key]))
830 $extendedList = array_combine($productIds, $productIds);
831 foreach(\CCatalogSku::getOffersList($productIds) as $mainProduct)
833 foreach(array_keys($mainProduct) as $offerId)
835 if(!isset($extendedList[$offerId]))
837 $extendedList[$offerId] = $offerId;
842 $cache[$key] = $extendedList;
888 if (!isset($discount[
'NAME']))
889 $select[
'NAME'] =
true;
890 if (empty($discount[
'CONDITIONS']))
891 $select[
'CONDITIONS_LIST'] =
true;
892 if (empty($discount[
'UNPACK']))
893 $select[
'UNPACK'] =
true;
894 if (empty($discount[
'USE_COUPONS']))
895 $discount[
'USE_COUPONS'] = (!empty($discount[
'COUPON']) ?
'Y' :
'N');
896 if (!isset($discount[
'SORT']))
897 $select[
'SORT'] =
true;
898 if (!isset($discount[
'PRIORITY']))
899 $select[
'PRIORITY'] =
true;
900 if (!isset($discount[
'LAST_DISCOUNT']))
901 $select[
'LAST_DISCOUNT'] =
true;
904 !isset($discount[
'TYPE'])
905 || ($discount[
'TYPE'] != Catalog\DiscountTable::TYPE_DISCOUNT && $discount[
'TYPE'] != Catalog\DiscountTable::TYPE_DISCOUNT_SAVE)
907 $select[
'TYPE'] =
true;
908 if (!isset($discount[
'VALUE_TYPE']))
910 $select[
'VALUE_TYPE'] =
true;
911 $select[
'VALUE'] =
true;
912 $select[
'MAX_DISCOUNT'] =
true;
913 $select[
'CURRENCY'] =
true;
917 if (!isset($discount[
'VALUE']))
918 $select[
'VALUE'] =
true;
919 if (!isset($discount[
'CURRENCY']))
920 $select[
'CURRENCY'] =
true;
922 $select[
'MAX_DISCOUNT'] =
true;
924 $selectKeys = array_keys($select);
928 $discountIterator = Catalog\DiscountTable::getList([
929 'select' => $selectKeys,
930 'filter' => [
'=ID' => $id]
932 $loadData = $discountIterator->fetch();
933 if (empty($loadData))
935 $discount = array_merge($loadData, $discount);
936 if (isset($discount[
'CONDITIONS_LIST']))
938 $discount[
'CONDITIONS'] = $discount[
'CONDITIONS_LIST'];
939 unset($discount[
'CONDITIONS_LIST']);
941 if (isset($discount[
'MAX_DISCOUNT']))
943 $discount[
'MAX_VALUE'] = $discount[
'MAX_DISCOUNT'];
944 unset($discount[
'MAX_DISCOUNT']);
946 unset($loadData, $discountIterator);
948 $discount[
'DISCOUNT_ID'] = $id;
949 if (empty($discount[
'MODULE_ID']))
950 $discount[
'MODULE_ID'] =
'catalog';
951 if (array_key_exists(
'HANDLERS', $discount))
953 if (!empty($discount[
'HANDLERS'][
'MODULES']) && empty($discount[
'MODULES']))
954 $discount[
'MODULES'] = $discount[
'HANDLERS'][
'MODULES'];
955 unset($discount[
'HANDLERS']);
957 if (empty($discount[
'MODULES']))
959 $discount[
'MODULES'] = [];
961 $conn = Main\Application::getConnection();
962 $helper = $conn->getSqlHelper();
964 $moduleIterator = $conn->query(
965 'select MODULE_ID from '.$helper->quote(
'b_catalog_discount_module').
' where '.$helper->quote(
'DISCOUNT_ID').
' = '.$id
967 while ($module = $moduleIterator->fetch())
968 $discount[
'MODULES'][] = $module[
'MODULE_ID'];
969 unset($module, $moduleIterator, $helper, $conn);
970 if (!in_array(
'catalog', $discount[
'MODULES']))
971 $discount[
'MODULES'][] =
'catalog';
973 self::$typeCache[$id] = $discount[
'TYPE'];
988 'iblockFields' => [],
990 'iblockProperties' => [],
991 'iblockPropertiesMap' => [],
992 'catalogFields' => [],
996 if (!is_array($entityList))
999 if (empty($entityList[
'catalog']))
1002 if (!empty($entityList[
'catalog']))
1004 if (!empty($entityList[
'catalog'][
'ELEMENT']) && is_array($entityList[
'catalog'][
'ELEMENT']))
1006 foreach ($entityList[
'catalog'][
'ELEMENT'] as $entity)
1008 if ($entity[
'FIELD_ENTITY'] ==
'SECTION_ID')
1010 $result[
'sections'] =
true;
1013 $result[
'iblockFields'][$entity[
'FIELD_TABLE']] = $entity[
'FIELD_ENTITY'];
1017 if (!empty($entityList[
'catalog'][
'ELEMENT_PROPERTY']) && is_array($entityList[
'catalog'][
'ELEMENT_PROPERTY']))
1019 foreach ($entityList[
'catalog'][
'ELEMENT_PROPERTY'] as $entity)
1021 $propertyData = explode(
':', $entity[
'FIELD_TABLE']);
1022 if (!is_array($propertyData) || count($propertyData) != 2)
1024 $iblock = (int)$propertyData[0];
1025 $property = (int)$propertyData[1];
1026 unset($propertyData);
1027 if (!isset($result[
'iblockProperties'][$iblock]))
1028 $result[
'iblockProperties'][$iblock] = [];
1029 $result[
'iblockProperties'][$iblock][] = $property;
1030 if (!isset($result[
'iblockPropertiesMap'][$iblock]))
1031 $result[
'iblockPropertiesMap'][$iblock] = [];
1032 $result[
'iblockPropertiesMap'][$iblock][$property] = $entity[
'FIELD_ENTITY'];
1034 unset($iblock, $property, $entity);
1037 if (!empty($entityList[
'catalog'][
'PRODUCT']) && is_array($entityList[
'catalog'][
'PRODUCT']))
1039 foreach ($entityList[
'catalog'][
'PRODUCT'] as $entity)
1040 $result[
'catalogFields'][$entity[
'FIELD_TABLE']] = $entity[
'FIELD_ENTITY'];
1044 if (!empty($entityList[
'catalog'][
'PRICE']) && is_array($entityList[
'catalog'][
'PRICE']))
1046 foreach ($entityList[
'catalog'][
'PRICE'] as $entity)
1047 $result[
'priceFields'][$entity[
'FIELD_TABLE']] = $entity[
'FIELD_ENTITY'];
1064 'iblockElement' => [],
1066 'skuIblockList' => []
1069 if (empty($productList))
1072 $elementIterator = Iblock\ElementTable::getList([
1073 'select' => [
'ID',
'IBLOCK_ID'],
1074 'filter' => [
'@ID' => $productList]
1076 while ($element = $elementIterator->fetch())
1078 $element[
'ID'] = (int)$element[
'ID'];
1079 $element[
'IBLOCK_ID'] = (int)$element[
'IBLOCK_ID'];
1080 if (!isset($result[
'iblockElement'][$element[
'IBLOCK_ID']]))
1081 $result[
'iblockElement'][$element[
'IBLOCK_ID']] = [];
1082 $result[
'iblockElement'][$element[
'IBLOCK_ID']][] = $element[
'ID'];
1084 unset($element, $elementIterator);
1085 if (!empty($result[
'iblockElement']))
1087 $result[
'iblockList'] = array_keys($result[
'iblockElement']);
1089 $skuIterator = Catalog\CatalogIblockTable::getList([
1090 'select' => [
'IBLOCK_ID',
'PRODUCT_IBLOCK_ID',
'SKU_PROPERTY_ID'],
1091 'filter' => [
'@IBLOCK_ID' => $result[
'iblockList'],
'!=PRODUCT_IBLOCK_ID' => 0]
1093 while ($sku = $skuIterator->fetch())
1095 $sku[
'IBLOCK_ID'] = (int)$sku[
'IBLOCK_ID'];
1096 $sku[
'PRODUCT_IBLOCK_ID'] = (int)$sku[
'PRODUCT_IBLOCK_ID'];
1097 $sku[
'SKU_PROPERTY_ID'] = (int)$sku[
'SKU_PROPERTY_ID'];
1098 $result[
'skuIblockList'][$sku[
'IBLOCK_ID']] = $sku;
1100 unset($sku, $skuIterator);
1150 protected static function convertProperties(&$productData, $propertyValues, $entityData, $iblockData): void
1152 if (empty($productData) || !is_array($productData))
1154 if (empty($propertyValues) || !is_array($propertyValues))
1156 if (empty($entityData) || !is_array($entityData))
1158 if (empty($iblockData) || !is_array($iblockData))
1161 if (empty($entityData[
'needProperties']) || !is_array($entityData[
'needProperties']))
1163 $propertyIblocks = array_keys($entityData[
'needProperties']);
1164 foreach ($propertyIblocks as $iblock)
1166 if (empty($iblockData[
'iblockElement'][$iblock]))
1168 $propertyMap = $entityData[
'iblockPropertiesMap'][$iblock];
1169 foreach ($iblockData[
'iblockElement'][$iblock] as $element)
1171 if (empty($propertyValues[$element]))
1173 foreach ($propertyValues[$element] as $property)
1175 if (empty($property) || empty($property[
'ID']))
1177 if ($property[
'PROPERTY_TYPE'] ==
Iblock\PropertyTable::TYPE_FILE)
1179 $property[
'ID'] = (int)$property[
'ID'];
1180 if (empty($propertyMap[$property[
'ID']]))
1182 $propertyKey = $propertyMap[$property[
'ID']];
1186 if ($property[
'MULTIPLE'] ==
'N')
1188 if (!empty($property[
'USER_TYPE']))
1190 switch($property[
'USER_TYPE'])
1194 $property[
'VALUE'] = (string)$property[
'VALUE'];
1195 if ($property[
'VALUE'] !=
'')
1197 $propertyFormat =
false;
1198 if ($property[
'USER_TYPE'] ==
'DateTime')
1200 if (defined(
'FORMAT_DATETIME'))
1201 $propertyFormat = FORMAT_DATETIME;
1205 if (defined(
'FORMAT_DATE'))
1206 $propertyFormat = FORMAT_DATE;
1208 $intStackTimestamp = (int)$property[
'VALUE'];
1209 $property[
'VALUE'] = (
1210 $intStackTimestamp.
'!' != $property[
'VALUE'].
'!'
1211 ? (int)MakeTimeStamp($property[
'VALUE'], $propertyFormat)
1212 : $intStackTimestamp
1215 $value = $property[
'VALUE'];
1222 switch ($property[
'PROPERTY_TYPE'])
1224 case Iblock\PropertyTable::TYPE_LIST:
1225 $property[
'VALUE_ENUM_ID'] = (int)$property[
'VALUE_ENUM_ID'];
1226 $value = ($property[
'VALUE_ENUM_ID'] > 0 ? $property[
'VALUE_ENUM_ID'] : -1);
1228 case Iblock\PropertyTable::TYPE_ELEMENT:
1229 case Iblock\PropertyTable::TYPE_SECTION:
1230 $property[
'VALUE'] = (int)$property[
'VALUE'];
1231 $value = ($property[
'VALUE'] > 0 ? $property[
'VALUE'] : -1);
1234 $value = $property[
'VALUE'];
1242 if (!empty($property[
'USER_TYPE']))
1244 switch($property[
'USER_TYPE'])
1248 if (!empty($property[
'VALUE']) && is_array($property[
'VALUE']))
1250 $propertyFormat =
false;
1251 if ($property[
'USER_TYPE'] ==
'DateTime')
1253 if (defined(
'FORMAT_DATETIME'))
1254 $propertyFormat = FORMAT_DATETIME;
1258 if (defined(
'FORMAT_DATE'))
1259 $propertyFormat = FORMAT_DATE;
1261 foreach ($property[
'VALUE'] as &$oneValue)
1263 $oneValue = (string)$oneValue;
1264 if (
'' != $oneValue)
1266 $intStackTimestamp = (int)$oneValue;
1267 if ($intStackTimestamp.
'!' != $oneValue.
'!')
1268 $oneValue = (int)MakeTimeStamp($oneValue, $propertyFormat);
1270 $oneValue = $intStackTimestamp;
1272 $value[] = $oneValue;
1274 unset($oneValue, $propertyFormat);
1282 switch ($property[
'PROPERTY_TYPE'])
1284 case Iblock\PropertyTable::TYPE_LIST:
1285 if (!empty($property[
'VALUE_ENUM_ID']) && is_array($property[
'VALUE_ENUM_ID']))
1287 foreach ($property[
'VALUE_ENUM_ID'] as &$oneValue)
1289 $oneValue = (int)$oneValue;
1291 $value[] = $oneValue;
1298 case Iblock\PropertyTable::TYPE_ELEMENT:
1299 case Iblock\PropertyTable::TYPE_SECTION:
1300 if (!empty($property[
'VALUE']) && is_array($property[
'VALUE']))
1302 foreach ($property[
'VALUE'] as &$oneValue)
1304 $oneValue = (int)$oneValue;
1306 $value[] = $oneValue;
1314 $value = $property[
'VALUE'];
1319 $productData[$element][$propertyKey] = (is_array($value) ? $value : [$value]);
1336 protected static function fillEmptyProperties(array &$propertyValues,
int $iblockId, array $itemIds, array $propertyIds): void
1338 if ($iblockId <= 0 || empty($itemIds) || empty($propertyIds))
1343 $iterator = Iblock\PropertyTable::getList([
1344 'select' => [
'ID',
'PROPERTY_TYPE',
'MULTIPLE',
'USER_TYPE'],
1345 'filter' => [
'=IBLOCK_ID' => $iblockId,
'@ID' => $propertyIds]
1347 while ($row = $iterator->fetch())
1349 $id = (int)$row[
'ID'];
1350 $multiple = ($row[
'MULTIPLE'] ==
'Y');
1355 'VALUE_ENUM' =>
null,
1356 'VALUE_XML_ID' =>
null,
1357 'VALUE_SORT' =>
null,
1359 'PROPERTY_VALUE_ID' =>
false,
1360 'DESCRIPTION' =>
false,
1361 '~DESCRIPTION' =>
false,
1369 'VALUE_ENUM' =>
null,
1370 'VALUE_XML_ID' =>
null,
1371 'VALUE_SORT' =>
null,
1373 'PROPERTY_VALUE_ID' =>
null,
1374 'DESCRIPTION' =>
'',
1375 '~DESCRIPTION' =>
'',
1379 if ($row[
'PROPERTY_TYPE'] ==
Iblock\PropertyTable::TYPE_LIST)
1381 $row[
'VALUE_ENUM_ID'] = ($multiple ? false :
null);
1384 $propertyList[$id] = $row;
1386 unset($row, $iterator);
1388 foreach ($itemIds as $id)
1390 if (!empty($propertyValues[$id]))
1394 $propertyValues[$id] = $propertyList;
1396 unset($propertyList);
1410 if (empty($iblockData[
'skuIblockList']))
1412 if (empty($productData) || !is_array($productData))
1416 $parentIblockData = [
1417 'iblockElement' => [],
1420 if (!empty($entityData[
'iblockFields']))
1422 foreach ($entityData[
'iblockFields'] as &$value)
1423 $value =
'PARENT_'.$value;
1425 if (array_key_exists(
'catalogFields', $entityData))
1426 unset($entityData[
'catalogFields']);
1427 foreach ($iblockData[
'skuIblockList'] as $skuData)
1429 if (empty($iblockData[
'iblockElement'][$skuData[
'IBLOCK_ID']]))
1431 foreach ($iblockData[
'iblockElement'][$skuData[
'IBLOCK_ID']] as $element)
1433 if (empty($productData[$element][
'PARENT_ID']))
1436 is_array($productData[$element][
'PARENT_ID'])
1437 ? current($productData[$element][
'PARENT_ID'])
1438 : $productData[$element][
'PARENT_ID']
1442 if (!isset($parentMap[$parentId]))
1443 $parentMap[$parentId] = [];
1444 $parentMap[$parentId][] = $element;
1445 $parentData[$parentId] = [];
1446 if (!isset($parentIblockData[
'iblockElement'][$skuData[
'PRODUCT_IBLOCK_ID']]))
1447 $parentIblockData[
'iblockElement'][$skuData[
'PRODUCT_IBLOCK_ID']] = [];
1448 $parentIblockData[
'iblockElement'][$skuData[
'PRODUCT_IBLOCK_ID']][] = $parentId;
1450 unset($parentId, $element);
1453 if (empty($parentIblockData[
'iblockElement']))
1455 $parentIblockData[
'iblockList'] = array_keys($parentIblockData[
'iblockElement']);
1459 foreach ($parentData as $parentId => $data)
1461 $parentSections = [];
1462 if ($entityData[
'sections'])
1464 $parentSections = $data[
'SECTION_ID'];
1465 unset($data[
'SECTION_ID']);
1467 if(!isset($parentMap[$parentId]))
1471 foreach ($parentMap[$parentId] as $element)
1473 $productData[$element] = array_merge($productData[$element], $data);
1474 if ($entityData[
'sections'])
1476 $productData[$element][
'SECTION_ID'] = (
1477 empty($productData[
'SECTION_ID'])
1479 : array_merge($productData[$element][
'SECTION_ID'], $parentSections)
1483 unset($element, $parentSections);
1485 unset($parentId, $data);
1526 $productSection = array_fill_keys($productIds, []);
1527 $elementSectionIterator = Iblock\SectionElementTable::getList([
1529 'filter' => [
'@IBLOCK_ELEMENT_ID' => $productIds]
1531 while ($elementSection = $elementSectionIterator->fetch())
1533 $elementSection[
'IBLOCK_ELEMENT_ID'] = (int)$elementSection[
'IBLOCK_ELEMENT_ID'];
1534 $elementSection[
'IBLOCK_SECTION_ID'] = (int)$elementSection[
'IBLOCK_SECTION_ID'];
1535 $elementSection[
'ADDITIONAL_PROPERTY_ID'] = (int)$elementSection[
'ADDITIONAL_PROPERTY_ID'];
1536 if ($elementSection[
'ADDITIONAL_PROPERTY_ID'] > 0)
1538 $productSection[$elementSection[
'IBLOCK_ELEMENT_ID']][$elementSection[
'IBLOCK_SECTION_ID']] =
true;
1539 $parentSectionIterator = \CIBlockSection::GetNavChain(0, $elementSection[
'IBLOCK_SECTION_ID'], [
'ID']);
1540 while ($parentSection = $parentSectionIterator->fetch())
1542 $parentSection[
'ID'] = (int)$parentSection[
'ID'];
1543 $productSection[$elementSection[
'IBLOCK_ELEMENT_ID']][$parentSection[
'ID']] =
true;
1545 unset($parentSection, $parentSectionIterator);
1547 unset($elementSection, $elementSectionIterator);
1549 return $productSection;
1572 protected static function fillProperties(array &$productData, array $productIds, array $iblockData, array $entityData)
1574 $propertyValues = array_fill_keys($productIds, []);
1575 foreach ($entityData[
'needProperties'] as $iblock => $propertyList)
1577 if (empty($iblockData[
'iblockElement'][$iblock]))
1582 $needToLoad = array_fill_keys($iblockData[
'iblockElement'][$iblock],
true);
1583 if(self::$productProperties)
1585 foreach ($iblockData[
'iblockElement'][$iblock] as $productId)
1588 foreach ($propertyList as $prop)
1590 $propData = self::getCachedProductProperty($productId, $prop);
1591 if (!empty($propData))
1593 $propertyValues[$productId][$propData[
'ID']] = $propData;
1605 $propertyValues[$productId] = [];
1609 unset($needToLoad[$productId]);
1615 if(!empty($needToLoad))
1617 $needProductIds = array_keys($needToLoad);
1618 sort($needProductIds);
1619 $iblockPropertyValues = array_fill_keys($needProductIds, []);
1621 \CTimeZone::Disable();
1622 foreach (array_chunk($needProductIds, 500) as $pageIds)
1626 'IBLOCK_ID' => $iblock
1629 \CIBlockElement::GetPropertyValuesArray(
1630 $iblockPropertyValues,
1633 [
'ID' => $propertyList],
1635 'USE_PROPERTY_ID' =>
'Y',
1636 'PROPERTY_FIELDS' => [
'ID',
'PROPERTY_TYPE',
'MULTIPLE',
'USER_TYPE']
1639 foreach ($iblockPropertyValues as $productId => $data)
1643 $propertyValues[$productId] = $data;
1644 unset($needToLoad[$productId]);
1647 unset($productId, $data);
1650 \CTimeZone::Enable();
1651 unset($iblockPropertyValues, $needProductIds);
1653 if (!empty($needToLoad))
1672 protected static function getProductData(&$productData, $entityData, $iblockData): void
1674 if (!empty($iblockData[
'iblockElement']))
1676 $productList = array_keys($productData);
1677 if (!empty($entityData[
'iblockFields']))
1679 foreach(self::loadIblockFields($productList, $entityData[
'iblockFields']) as $productId => $fields)
1681 $productData[$productId] = (
1682 empty($productData[$productId])
1684 : array_merge($productData[$productId], $fields)
1689 if ($entityData[
'sections'])
1691 foreach(self::loadSections($productList) as $element => $sections)
1693 $productData[$element][
'SECTION_ID'] = array_keys($sections);
1696 if (!empty($entityData[
'needProperties']))
1700 if (!empty($entityData[
'catalogFields']))
1702 foreach(self::loadCatalogFields($productList, $entityData[
'catalogFields']) as $productId => $fields)
1704 $productData[$productId] = (
1705 empty($productData[$productId])
1707 : array_merge($productData[$productId], $fields)
1712 if (!empty($entityData[
'priceFields']) && !empty($entityData[
'priceData']))
1714 foreach($entityData[
'priceData'] as $productId => $priceId)
1716 $productData[$productId][
'CATALOG_GROUP_ID'] = $priceId;
1718 unset($product, $productIterator);
1721 if (!empty($iblockData[
'skuIblockList']))
1737 'TYPE' => $discount[
'VALUE_TYPE'],
1738 'VALUE' => $discount[
'VALUE'],
1739 'CURRENCY' => $discount[
'CURRENCY'],
1740 'USE_BASE_PRICE' => $params[
'USE_BASE_PRICE']
1743 $data[
'MAX_VALUE'] = $discount[
'MAX_VALUE'];
1745 $action =
'\Bitrix\Catalog\Discount\DiscountManager::applyDiscount('.$params[
'BASKET_ITEM'].
', '.var_export($data,
true).
');';
1746 $discount[
'APPLICATION'] =
'function (&'.$params[
'BASKET_ITEM'].
'){'.$action.
'};';
1747 $discount[
'ACTIONS'] = $data;
1748 unset($action, $data);
1750 if (self::$saleIncluded ===
null)
1751 self::$saleIncluded = Loader::includeModule(
'sale');
1752 if (!self::$saleIncluded)
1758 $discount[
'TYPE'] == Catalog\DiscountTable::TYPE_DISCOUNT_SAVE
1759 ? Sale\Discount\Formatter::VALUE_ACTION_CUMULATIVE
1760 : Sale\Discount\Formatter::VALUE_ACTION_DISCOUNT
1762 'VALUE' => $discount[
'VALUE']
1764 switch ($discount[
'VALUE_TYPE'])
1766 case Catalog\DiscountTable::VALUE_TYPE_PERCENT:
1768 $discount[
'MAX_VALUE'] > 0
1769 ? Sale\Discount\Formatter::TYPE_LIMIT_VALUE
1770 : Sale\Discount\Formatter::TYPE_VALUE
1772 $descr[
'VALUE_TYPE'] = Sale\Discount\Formatter::VALUE_TYPE_PERCENT;
1773 if ($discount[
'MAX_VALUE'] > 0)
1775 $descr[
'LIMIT_TYPE'] = Sale\Discount\Formatter::LIMIT_MAX;
1776 $descr[
'LIMIT_UNIT'] = $discount[
'CURRENCY'];
1777 $descr[
'LIMIT_VALUE'] = $discount[
'MAX_VALUE'];
1780 case Catalog\DiscountTable::VALUE_TYPE_FIX:
1781 $type = Sale\Discount\Formatter::TYPE_VALUE;
1782 $descr[
'VALUE_TYPE'] = Sale\Discount\Formatter::VALUE_TYPE_CURRENCY;
1783 $descr[
'VALUE_UNIT'] = $discount[
'CURRENCY'];
1785 case Catalog\DiscountTable::VALUE_TYPE_SALE:
1786 $type = Sale\Discount\Formatter::TYPE_FIXED;
1787 $descr[
'VALUE_UNIT'] = $discount[
'CURRENCY'];
1790 $descrResult = Sale\Discount\Formatter::prepareRow($type, $descr);
1791 if ($descrResult !==
null)
1793 $discount[
'ACTIONS_DESCR'] = [
1799 unset($descrResult, $descr, $type);