15if (Main\Loader::includeModule(
'sale'))
22 class CatalogProvider
extends Base
24 private static $userCache = array();
26 protected static $hitCache = array();
27 protected static $priceTitleCache = array();
28 protected static $clearAutoCache = array();
30 protected $enableCache =
true;
32 protected const CACHE_USER_GROUPS =
'USER_GROUPS';
33 protected const CACHE_ITEM_WITHOUT_RIGHTS =
'IBLOCK_ELEMENT_PERM_N';
34 protected const CACHE_ITEM_RIGHTS =
'IBLOCK_ELEMENT';
35 protected const CACHE_ITEM_WITH_RIGHTS =
'IBLOCK_ELEMENT_PERM_Y';
36 protected const CACHE_ELEMENT_RIGHTS_MODE =
'ELEMENT_RIGHTS_MODE';
37 protected const CACHE_ELEMENT_SHORT_DATA =
'IBLOCK_ELEMENT_SHORT';
38 protected const CACHE_PRODUCT =
'CATALOG_PRODUCT';
39 protected const CACHE_VAT =
'VAT_INFO';
40 protected const CACHE_IBLOCK_RIGHTS =
'IBLOCK_RIGHTS';
41 protected const CACHE_STORE =
'CATALOG_STORE';
42 protected const CACHE_STORE_PRODUCT =
'CATALOG_STORE_PRODUCT';
43 protected const CACHE_PARENT_PRODUCT_ACTIVE =
'PARENT_PRODUCT_ACTIVE';
44 protected const CACHE_CATALOG_IBLOCK_LIST =
'CATALOG_IBLOCK_LIST';
45 protected const CACHE_PRODUCT_STORE_LIST =
'CACHE_PRODUCT_STORE_LIST';
46 protected const CACHE_PRODUCT_AVAILABLE_LIST =
'CACHE_PRODUCT_AVAILABLE_LIST';
49 protected const BUNDLE_TYPE = 1;
53 protected const RESULT_CATALOG_LIST =
'CATALOG_DATA_LIST';
55 protected const USE_GATALOG_DATA =
'CATALOG_DATA';
57 protected const AMOUNT_SRC_QUANTITY =
'QUANTITY';
59 protected const AMOUNT_SRC_PRICE_LIST =
'PRICE_LIST';
64 private const QUANTITY_FORMAT_STORE = 1;
65 private const QUANTITY_FORMAT_SHIPMENT = 2;
72 public function getProductData(array $products)
74 return $this->getData($products);
82 public function getCatalogData(array $products)
84 return $this->getData(
86 [self::USE_GATALOG_DATA]
96 private function getData(array $products, array $options = array()):
Sale\Result
100 $resultProductList = array_fill_keys(array_keys($products),
false);
102 $result =
new Sale\Result();
104 $userId = (int)($context[
'USER_ID'] ?? 0);
109 $siteId = $context[
'SITE_ID'] ??
false;
110 $currency = $context[
'CURRENCY'] ??
false;
111 $currency = (is_string($currency) ? Currency\CurrencyManager::checkCurrencyID($context[
'CURRENCY']) : false);
112 if ($currency ===
false)
114 $currency = Sale\Internals\SiteCurrencyTable::getSiteCurrency($siteId ?: SITE_ID);
116 $adminSection = (defined(
'ADMIN_SECTION') && ADMIN_SECTION ===
true);
118 if (in_array(
'DISABLE_CACHE', $options))
120 $this->enableCache =
false;
123 $catalogDataEnabled = self::isCatalogDataEnabled($options);
125 $outputVariable = static::getOutputVariable($options);
127 $productGetIdList = array();
128 $correctProductIds = [];
130 $iblockElementSelect = array(
'ID',
'IBLOCK_ID',
'IBLOCK_SECTION_ID',
'ACTIVE',
'ACTIVE_DATE',
'XML_ID');
131 if (!$catalogDataEnabled)
133 $iblockElementSelect = array_merge($iblockElementSelect, array(
'NAME',
'DETAIL_PAGE_URL'));
136 $resultList = array();
137 foreach ($products as $productId => $itemData)
140 if (!isset($itemData[
'ITEM_CODE']))
146 if (!isset($itemData[
'BASKET_CODE']))
153 $productCachedData = static::getHitCache(self::CACHE_ITEM_RIGHTS, $hash, $iblockElementSelect);
154 if ($this->enableCache && !empty($productCachedData))
156 $products[
$productId][
'PRODUCT_DATA'] = $productCachedData;
165 if (!empty($productGetIdList))
167 $productDataList = $this->getElements(
169 $iblockElementSelect,
170 ($adminSection ? $userId : null)
173 foreach ($productDataList as $productId => $productData)
175 $products[
$productId][
'PRODUCT_DATA'] = $productData;
177 static::setHitCache(self::CACHE_ITEM_RIGHTS, $hash, $productData);
181 $products = array_intersect_key(
185 if (empty($products))
187 return static::getResultProvider($result, $outputVariable, $resultList);
190 unset($correctProductIds);
192 $iblockList = array();
193 $iblockDataList = array();
194 $iblockGetIdList = array();
195 foreach ($products as $productId => $productData)
197 $iblockId = $productData[
'PRODUCT_DATA'][
'IBLOCK_ID'];
201 foreach ($iblockList as $iblockId => $iblockProductIdList)
203 $iblockData = static::getHitCache(self::CACHE_CATALOG_IBLOCK_LIST, $iblockId);
204 if ($this->enableCache && !empty($iblockData))
206 $iblockDataList[$iblockId] = $iblockData;
210 $iblockGetIdList[] = $iblockId;
214 if (!empty($iblockGetIdList))
216 $iblockDataList = $this->getIblockData($iblockGetIdList) + $iblockDataList;
219 $iblockList = array_intersect_key(
224 $iblockProductMap = static::createIblockProductMap($iblockList, $iblockDataList);
226 $correctProductList = static::checkSkuPermission($iblockProductMap);
228 $products = array_intersect_key(
230 array_fill_keys($correctProductList,
true)
232 if (empty($products))
234 return static::getResultProvider($result, $outputVariable, $resultList);
237 $products = static::changeSubscribeProductQuantity($products, $iblockProductMap);
241 $catalogSelect = array(
251 if (!$catalogDataEnabled)
253 $catalogSelect = array_merge($catalogSelect, array(
261 $catalogSelect = array_merge($catalogSelect, Catalog\Product\SystemField::getProviderSelectFields());
263 $catalogProductDataList = static::getCatalogProducts(array_keys($products), $catalogSelect);
265 $products = array_intersect_key($products, $catalogProductDataList);
266 if (empty($products))
268 return static::getResultProvider($result, $outputVariable, $resultList);
272 $products = self::fillCatalogXmlId($products, $iblockProductMap);
274 $products = self::fillOfferXmlId($products, $catalogProductDataList);
277 $priceDataList = self::getPriceDataList(
280 'IS_ADMIN_SECTION' => $adminSection,
281 'USER_ID' => $userId,
282 'SITE_ID' => $siteId,
283 'CURRENCY' => $currency,
286 $discountList = self::getDiscountList($priceDataList);
288 $productQuantityList = array();
289 $productPriceList = array();
291 $fullQuantityMode = in_array(
'FULL_QUANTITY', $options);
293 foreach ($products as $productId => $productData)
295 $catalogProductData = $catalogProductDataList[
$productId];
297 $quantityList = array();
299 if (array_key_exists(
'QUANTITY', $productData))
301 $quantityList = array($productData[
'BASKET_CODE'] => $productData[
'QUANTITY']);
309 $productQuantityList[$productData[
'BASKET_CODE']][
'QUANTITY_RESERVED'] = $catalogProductData[
'QUANTITY_RESERVED'];
311 $baseCatalogQuantity = (float)$catalogProductData[
'QUANTITY'];
313 $allCount = count($quantityList);
315 foreach ($quantityList as $quantity)
317 $sumQuantity += (float)abs($quantity);
320 $catalogQuantityForAvaialable = $baseCatalogQuantity;
321 $checkCatalogQuantity = $baseCatalogQuantity;
323 $isEnough = !($catalogProductData[
'CHECK_QUANTITY'] && $catalogQuantityForAvaialable < $sumQuantity);
324 $setQuantity = $baseCatalogQuantity;
325 foreach ($quantityList as $basketCode => $quantity)
327 $quantity = (float)abs($quantity);
331 if ($catalogQuantityForAvaialable - $quantity < 0)
333 $quantity = $catalogQuantityForAvaialable;
336 $catalogQuantityForAvaialable -= $quantity;
339 $productQuantityList[$basketCode][
'AVAILABLE_QUANTITY'] = (
340 $baseCatalogQuantity >= $quantity || !$catalogProductData[
'CHECK_QUANTITY']
342 : $baseCatalogQuantity
345 if ($fullQuantityMode)
347 $checkCatalogQuantity -= $quantity;
348 $setQuantity = $quantity;
353 $setQuantity = $checkCatalogQuantity + $quantity;
358 if ($baseCatalogQuantity - $quantity > 0 || !$catalogProductData[
'CHECK_QUANTITY'])
360 $setQuantity = $quantity;
364 $productQuantityList[$basketCode][
'QUANTITY'] = $setQuantity;
366 unset($basketCode, $quantity);
368 foreach (array_keys($quantityList) as $basketCode)
370 if (isset($priceDataList[$productId][$basketCode]))
372 $productPriceList[$basketCode] = $priceDataList[
$productId][$basketCode];
377 $measure = isset($catalogProductData[
'MEASURE']) ? (int)$catalogProductData[
'MEASURE'] : null;
378 $measureFields = static::getMeasure($measure);
379 if (!empty($measureFields))
385 unset($fullQuantityMode);
387 $resultData = static::setCatalogDataToProducts($products, $catalogProductDataList, $options);
389 $priceResultList = static::createProductPriceList($products, $productPriceList, $discountList);
391 $resultList = static::createProductResult($products, $resultData, $priceResultList, $productQuantityList);
393 $resultList = $resultList + $resultProductList;
395 return static::getResultProvider($result, $outputVariable, $resultList);
398 private static function getOutputVariable(array $options = array()): string
400 return (self::isCatalogDataEnabled($options)
401 ? static::RESULT_CATALOG_LIST
402 : Base::SUMMMARY_PRODUCT_LIST
406 private static function getResultProvider(
Sale\Result $result, $outputVariable, array $resultList = array()):
Sale\Result
410 $outputVariable => $resultList,
424 private function getElements(array $list, array $select, ?
int $userId =
null): array
428 'ACTIVE_DATE' =>
'Y',
429 'CHECK_PERMISSIONS' =>
'Y',
430 'MIN_PERMISSION' =>
'R',
432 if ($userId !==
null)
434 $filter[
'PERMISSIONS_BY'] =
$userId;
437 $resultList = array();
438 $dbIBlockElement = \CIBlockElement::GetList(
445 while ($productData = $dbIBlockElement->GetNext())
447 $resultList[$productData[
'ID']] = $productData;
449 unset($dbIBlockElement);
459 public function getBundleItems(array $products)
461 $result =
new Sale\Result();
463 $resultList = array();
465 $productIdList = array();
466 static $proxyCatalogProductSet = array();
467 static $proxyCatalogSkuData = array();
468 $bundleItemList = array();
470 $bundleIndex = array();
472 foreach ($products as $productId => $productData)
474 $proxyCatalogProductSetKey =
$productId.
"|".static::BUNDLE_TYPE;
475 if (!empty($proxyCatalogProductSet[$proxyCatalogProductSetKey]) && is_array($proxyCatalogProductSet[$proxyCatalogProductSetKey]))
477 $childItemList = $proxyCatalogProductSet[$proxyCatalogProductSetKey];
481 $childItemList = \CCatalogProductSet::getAllSetsByProduct($productId, static::BUNDLE_TYPE);
482 if (!empty($childItemList) && is_array($childItemList))
484 $proxyCatalogProductSet[$proxyCatalogProductSetKey] = $childItemList;
488 if (!empty($childItemList))
490 $bundleItemList = $childItemList + $bundleItemList;
491 $bundleItemListIds = array_keys($childItemList);
492 $bundleItemId = reset($bundleItemListIds);
493 unset($bundleItemListIds);
498 $childIdList = array();
500 if (empty($bundleItemList))
503 $bundleChildList = array();
504 $childProducts = array();
505 $productIndexList = array();
506 foreach ($bundleItemList as $parentItemid => $bundleItemData)
509 foreach ($bundleItemData[
"ITEMS"] as $childItemid => $item)
511 if (!isset($childIdList[$item[
'ITEM_ID']]))
512 $childIdList[$item[
'ITEM_ID']] =
true;
514 $bundleChildList[$item[
'ITEM_ID']] = $item;
515 $childProducts[$item[
'ITEM_ID']] = array(
516 'ITEM_CODE' => $item[
'ITEM_ID'],
517 'PRODUCT_ID' => $item[
'ITEM_ID'],
519 'BUNDLE_CHILD' =>
true,
522 $productIndexList[$item[
'ITEM_ID']] = array(
523 'PRODUCT_ID' => $productId,
524 'PARENT_ID' => $parentItemid,
525 'CHILD_ID' => $childItemid,
530 $r = $this->getProductData($childProducts);
533 $resultData = $r->getData();
540 foreach ($resultDataList as $itemCode => $itemData)
542 $item = $bundleChildList[$itemCode];
543 if (array_key_exists(
'QUANTITY_TRACE', $itemData))
544 unset($itemData[
'QUANTITY_TRACE']);
546 $itemData[
"PRODUCT_ID"] = $item[
"ITEM_ID"];
547 $itemData[
"MODULE"] =
'catalog';
548 $itemData[
"PRODUCT_PROVIDER_CLASS"] = Basket::getDefaultProviderName();
550 $productIdList[] = $item[
"ITEM_ID"];
552 $itemData[
"PROPS"] = array();
554 if (!empty($proxyCatalogSkuData[$item[
"ITEM_ID"]]) && is_array($proxyCatalogSkuData[$item[
"ITEM_ID"]]))
556 $parentSkuData = $proxyCatalogSkuData[$item[
"ITEM_ID"]];
560 $parentSkuData = \CCatalogSku::GetProductInfo($item[
"ITEM_ID"]);
563 $proxyCatalogSkuData[$item[
"ITEM_ID"]] = $parentSkuData;
567 if (!empty($parentSkuData))
569 $childDataList = array();
570 $childIdGetList = array();
572 $iblockPropertyDataList = array();
573 $iblockPropertyIdList = array();
577 foreach ($childIdList as $childId => $parentValue)
579 $productData = static::getHitCache(self::CACHE_ELEMENT_SHORT_DATA, $item[
"ITEM_ID"]);
580 if (!empty($productData))
582 $childDataList[$childId] = $productData;
583 if (!isset($iblockPropertyIdList[$productData[
'IBLOCK_ID']]))
585 $iblockPropertyIdList[$productData[
'IBLOCK_ID']] =
true;
590 $childIdGetList[] = $childId;
594 if (!empty($childIdGetList))
596 $iterator = Iblock\ElementTable::getList([
603 'filter' => \CIBlockElement::getPublicElementsOrmFilter([
'@ID' => $childIdGetList]),
605 while ($productData = $iterator->fetch())
607 static::setHitCache(self::CACHE_ELEMENT_SHORT_DATA, $productData[
"ID"], $productData);
608 $childDataList[$productData[
"ID"]] = $productData;
610 if (!isset($iblockPropertyIdList[$productData[
'IBLOCK_ID']]))
612 $iblockPropertyIdList[$productData[
'IBLOCK_ID']] =
true;
617 foreach ($iblockPropertyIdList as $iblockPropertyId => $iblockPropertyValue)
619 if ($propsSku = static::getHitCache(
'IBLOCK_PROPERTY', $iblockPropertyId))
621 $iblockPropertyDataList[$iblockPropertyId] = $propsSku;
625 $dbOfferProperties = \CIBlock::GetProperties($iblockPropertyId, array(), array(
"!XML_ID" =>
"CML2_LINK"));
626 while($offerProperties = $dbOfferProperties->Fetch())
628 $propsSku[] = $offerProperties[
"CODE"];
630 static::setHitCache(
'IBLOCK_PROPERTY', $iblockPropertyId, $propsSku);
634 $propSkuHash = (!empty($propsSku)) ? md5(join(
'|', $propsSku)): md5($item[
"ITEM_ID"]);
636 $proxyProductPropertyKey = $item[
"ITEM_ID"].
"_".$parentSkuData[
"IBLOCK_ID"].
"_".$propSkuHash;
638 $productProperties = static::getHitCache(
'PRODUCT_PROPERTY', $proxyProductPropertyKey);
639 if (empty($productProperties))
641 $productProperties = \CIBlockPriceTools::GetOfferProperties(
643 $parentSkuData[
"IBLOCK_ID"],
647 static::setHitCache(
'PRODUCT_PROPERTY', $proxyProductPropertyKey, $productProperties);
650 if (!empty($productProperties))
652 foreach ($productProperties as $propData)
654 $itemData[
"PROPS"][] = array(
655 "NAME" => $propData[
"NAME"],
656 "CODE" => $propData[
"CODE"],
657 "VALUE" => $propData[
"VALUE"],
658 "SORT" => $propData[
"SORT"],
665 $parentProductIndexData = $productIndexList[$itemCode];
667 $priceData = array();
668 if (!empty($itemData[
'PRICE_LIST']))
670 $priceData = reset($itemData[
'PRICE_LIST']);
671 unset($itemData[
'PRICE_LIST']);
674 if (array_key_exists(
'PRODUCT', $itemData))
676 unset($itemData[
'PRODUCT']);
679 $bundleItemList[$parentProductIndexData[
'PARENT_ID']][
"ITEMS"][$parentProductIndexData[
'CHILD_ID']] = array_merge($item, $itemData, $priceData);
684 $elementList = static::getHitCache(
'IBLOCK_ELEMENT_LIST', $productId);
685 if (empty($elementList))
687 $productRes = \CIBlockElement::GetList(
689 array(
'ID' => $productIdList),
692 array(
"ID",
"IBLOCK_ID",
"IBLOCK_SECTION_ID",
"PREVIEW_PICTURE",
"DETAIL_PICTURE",
"IBLOCK_TYPE_ID",
"XML_ID")
694 while ($productData = $productRes->GetNext())
696 $elementList[$productData[
'ID']] = $productData;
699 if (!empty($elementList) && is_array($elementList))
701 static::setHitCache(
'IBLOCK_ELEMENT_LIST', $productId, $elementList);
705 if (!empty($elementList) && is_array($elementList))
707 foreach ($bundleItemList as $bundleParentId => $bundleItemData)
709 foreach ($bundleItemData[
"ITEMS"] as $bundleChildId => $item)
711 if (!$elementList[$item[
"ITEM_ID"]])
714 $elementData = $elementList[$item[
"ITEM_ID"]];
716 $properties = array();
717 $strIBlockXmlID = (string)\CIBlock::GetArrayByID($elementData[
'IBLOCK_ID'],
'XML_ID');
718 if ($strIBlockXmlID !=
"")
720 $properties[] = array(
721 "NAME" =>
"Catalog XML_ID",
722 "CODE" =>
"CATALOG.XML_ID",
723 "VALUE" => $strIBlockXmlID,
726 $elementData[
'CATALOG_XML_ID'] = $strIBlockXmlID;
730 if (!empty($proxyCatalogSkuData[$item[
"ITEM_ID"]]) && strpos($elementData[
"XML_ID"],
'#') ===
false)
732 $parentSkuData = $proxyCatalogSkuData[$item[
"ITEM_ID"]];
733 if (!empty($proxyParentData[$parentSkuData[
'ID']]) && is_array($proxyParentData[$parentSkuData[
'ID']]))
735 $parentData = $proxyParentData[$parentSkuData[
'ID']];
739 $parentIterator = Iblock\ElementTable::getList(
741 'select' => array(
'ID',
'XML_ID'),
742 'filter' => array(
'ID' => $parentSkuData[
'ID']),
746 $parentData = $parentIterator->fetch();
747 if (!empty($parentData))
749 $proxyParentData[$parentSkuData[
'ID']] = $parentData;
752 unset($parentIterator);
755 $elementData[
"XML_ID"] = $parentData[
'XML_ID'].
'#'.$elementData[
"XML_ID"];
759 $properties[] = array(
760 "NAME" =>
"Product XML_ID",
761 "CODE" =>
"PRODUCT.XML_ID",
762 "VALUE" => $elementData[
"XML_ID"],
765 $bundleItemData = $bundleItemList[$bundleParentId][
"ITEMS"][$bundleChildId];
767 $bundleItemProps = array();
768 if (is_array($elementData[
"PROPS"]) && !empty($elementData[
"PROPS"]))
770 $bundleItemProps = $elementData[
"PROPS"];
773 if (!empty($properties))
775 $bundleItemProps = $bundleItemProps + $properties;
778 $bundleItemList[$bundleParentId][
"ITEMS"][$bundleChildId] = $bundleItemData + array(
779 'IBLOCK_ID' => $elementData[
"IBLOCK_ID"],
780 'IBLOCK_SECTION_ID' => $elementData[
"IBLOCK_SECTION_ID"],
781 'PREVIEW_PICTURE' => $elementData[
"PREVIEW_PICTURE"],
782 'DETAIL_PICTURE' => $elementData[
"DETAIL_PICTURE"],
784 'CATALOG_XML_ID' => $elementData[
"CATALOG_XML_ID"],
785 'PRODUCT_XML_ID' => $elementData[
"XML_ID"],
788 $bundleItemList[$bundleParentId][
"ITEMS"][$bundleChildId][
'PROPS'] = $bundleItemProps;
794 foreach(GetModuleEvents(
"sale",
"OnGetSetItems",
true) as $eventData)
796 ExecuteModuleEventEx($eventData, array(&$bundleItemList));
799 if (!empty($bundleItemList))
801 foreach ($bundleItemList as $bundleParentId => $bundleData)
803 if (empty($bundleIndex[$bundleParentId]))
813 'BUNDLE_LIST' => $resultList,
826 protected static function getUserGroups($userId)
832 if (!isset(self::$userCache[$userId]))
833 self::$userCache[$userId] = Main\UserTable::getUserGroupIds($userId);
835 return self::$userCache[
$userId];
843 public function ship(array $products)
845 return $this->shipProducts($products);
853 public function unship(array $products)
855 $result =
new Sale\Result();
857 $r = $this->tryUnship($products);
858 if (!$r->isSuccess())
860 $result->addErrors($r->getErrors());
864 $data = $r->getData();
866 if (!empty($data[
'PRODUCTS_LIST_SHIPPED']))
868 $productsList = array();
869 foreach ($data[
'PRODUCTS_LIST_SHIPPED'] as $productId => $value)
871 if ($value && !empty($products[$productId]))
877 if (!empty($productsList))
879 $this->shipProducts($productsList);
892 public function deliver(array $products)
894 $result =
new Sale\Result();
896 $resultList = array();
898 $productOrderList = static::createOrderListFromProducts($products);
900 $deliverProductList = array();
901 foreach ($products as $productId => $productData)
907 if (isset($productData[
'USER_ID']))
909 $userId = $productData[
'USER_ID'];
912 if (isset($productData[
'ORDER_ID']))
914 $orderId = $productData[
'ORDER_ID'];
917 if (isset($productData[
'PAID']))
919 $orderPaid = $productData[
'PAID'];
927 if (isset($productOrderList[$productId]))
929 foreach ($productOrderList[$productId] as $orderId => $order)
931 if (!isset($resultList[$productId]))
933 $deliverProductList[] = array(
934 'PRODUCT_ID' => $productId,
935 'USER_ID' => $order->getUserId(),
936 'PAID' => $order->isPaid(),
937 'ORDER_ID' => $orderId,
944 if (isset($productData[
'USER_ID']))
946 $userId = $productData[
'USER_ID'];
949 if (isset($productData[
'ORDER_ID']))
951 $orderId = $productData[
'ORDER_ID'];
954 if (isset($productData[
'PAID']))
956 $orderPaid = $productData[
'PAID'];
959 $deliverProductList[] = array(
960 'PRODUCT_ID' => $productId,
961 'USER_ID' => $userId,
962 'PAID' => $orderPaid,
963 'ORDER_ID' => $orderId,
968 if (!empty($deliverProductList))
970 foreach ($deliverProductList as $productData)
973 $resultList[
$productId] = \CatalogPayOrderCallback(
975 $productData[
'USER_ID'],
976 $productData[
'PAID'],
977 $productData[
'ORDER_ID']
982 if (!empty($resultList))
986 'DELIVER_PRODUCTS_LIST' => $resultList,
999 public function viewProduct(array $products)
1001 $result =
new Sale\Result();
1003 $resultList = array();
1005 foreach ($products as $productId => $itemData)
1007 if (!isset($resultList[$productId]))
1011 $resultList[
$productId] = \CatalogViewedProductCallback(
1013 $context[
'USER_ID'],
1020 if (!empty($resultList))
1024 'VIEW_PRODUCTS_LIST' => $resultList,
1037 public function recurring(array $items)
1039 $result =
new Sale\Result();
1041 $resultList = array();
1043 foreach ($items as $productId => $itemData)
1045 if (!isset($resultList[$productId]))
1049 $resultList[
$productId] = \CatalogRecurringCallback(
1057 if (!empty($resultList))
1061 'RECURRING_PRODUCTS_LIST' => $resultList,
1074 public function checkBarcode(array $items)
1076 $result =
new Sale\Result();
1078 $resultList = array();
1080 foreach ($items as $barcodeParams)
1082 $resultList[$barcodeParams[
'BARCODE']] =
false;
1083 $dbres = \CCatalogStoreBarcode::GetList(
1087 $resultList[$barcodeParams[
'BARCODE']] = (bool)($dbres->GetNext());
1091 if (!empty($resultList))
1095 'BARCODE_CHECK_LIST' => $resultList,
1108 protected function shipProducts(array $products)
1110 $result =
new Sale\Result();
1112 $resultList = array_fill_keys(array_keys($products),
false);
1114 $availableItems = $this->createProductsListWithCatalogData($products);
1116 $productStoreDataList = [];
1117 if (Catalog\
Config\State::isUsedInventoryManagement())
1119 $r = $this->getProductListStores($products);
1120 if ($r->isSuccess())
1122 $data = $r->getData();
1123 if (!empty($data[
'PRODUCT_STORES_LIST']))
1125 $productStoreDataList = $data[
'PRODUCT_STORES_LIST'];
1132 foreach ($availableItems as $productId => $productData)
1134 $r = static::shipProduct(
1136 (!empty($productStoreDataList[$productId])
1137 ? $productStoreDataList[$productId]
1141 if (!$r->isSuccess())
1143 $result->addErrors($r->getErrors());
1144 $result->addWarnings($r->getErrors());
1151 'SHIPPED_PRODUCTS_LIST' => $resultList,
1164 private static function updateCatalogStoreAmount(array $quantityList):
Sale\Result
1166 $result =
new Sale\Result();
1167 $resultList = array();
1169 if (empty($quantityList))
1174 foreach ($quantityList as $catalogStoreId => $amount)
1177 'AMOUNT' =>
$amount[
'AMOUNT'],
1179 if (isset($amount[
'QUANTITY_RESERVED']))
1181 $fields[
'QUANTITY_RESERVED'] =
$amount[
'QUANTITY_RESERVED'];
1184 $internalResult = Catalog\StoreProductTable::update($catalogStoreId, $fields);
1186 $resultList[$catalogStoreId] = $internalResult->isSuccess();
1191 'AMOUNT_UPDATED_LIST' => $resultList,
1204 private static function shipProduct(array $productData, array $productStoreDataList = array()):
Sale\Result
1206 $result =
new Sale\Result();
1210 $productQuantity = self::getTotalAmountFromQuantityList($productData);
1212 $needShip = ($productQuantity < 0);
1216 $productData[
'PRODUCT'][
'USED_STORE_INVENTORY']
1219 if (empty($productStoreDataList) && $needShip)
1222 new Sale\ResultError(
1224 "DDCT_DEDUCTION_STORE_ERROR",
1226 self::getProductCatalogInfo($productId),
1227 array(
"#PRODUCT_ID#" => $productId)
1229 ),
"DDCT_DEDUCTION_STORE_ERROR"
1235 $setQuantityList = array();
1236 $r = static::getSetableStoreQuantityProduct($productData, $productStoreDataList);
1237 if ($r->isSuccess())
1239 $resultData = $r->getData();
1255 $r = static::updateCatalogStoreAmount($setQuantityList);
1256 if ($r->isSuccess())
1258 $resultData = $r->getData();
1259 if (!empty($resultData[
'AMOUNT_UPDATED_LIST']))
1261 foreach($resultData[
'AMOUNT_UPDATED_LIST'] as $catalogStoreIsUpdated)
1263 if ($catalogStoreIsUpdated ===
true)
1265 static::clearHitCache(self::CACHE_STORE_PRODUCT);
1268 $r = static::deleteBarcodes($productData);
1272 $r = static::addBarcodes($productData);
1275 if (!$r->isSuccess())
1277 $result->addErrors($r->getErrors());
1288 return static::shipQuantityWithStoreControl($productData);
1290 elseif (isset($productData[
"CATALOG"]))
1292 if ($productData[
"CATALOG"][
"QUANTITY_TRACE"] ==
"N")
1298 return static::shipQuantityWithoutStoreControl($productData);
1307 private static function shipQuantityWithStoreControl(array $productData):
Sale\Result
1309 $result =
new Sale\Result();
1311 $productId = (int)$productData[
'PRODUCT_ID'];
1313 $productQuantity = self::getTotalAmountFromQuantityList($productData);
1315 $catalogData = $productData[
'CATALOG'];
1317 $isExistsReserve = static::isExistsCommonStoreReserve($productData) && static::isReservationEnabled();
1318 $isNeedShip = ($productQuantity < 0);
1320 $productQuantity = abs($productQuantity);
1324 $catalogReservedQuantity = (float)$catalogData[
'QUANTITY_RESERVED'];
1325 $catalogQuantity = self::getTotalAmountFromPriceList($catalogData);
1327 $sumCatalogQuantity = $catalogReservedQuantity + $catalogQuantity;
1331 if ($isExistsReserve)
1333 if ($catalogReservedQuantity >= $productQuantity)
1335 $fields[
"QUANTITY_RESERVED"] = $catalogReservedQuantity - $productQuantity;
1337 elseif ($sumCatalogQuantity >= $productQuantity)
1339 $fields[
"QUANTITY_RESERVED"] = 0;
1340 $fields[
"QUANTITY"] = $catalogQuantity - ($productQuantity - $catalogReservedQuantity);
1345 new Sale\ResultError(
1347 "DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT",
1349 self::getProductCatalogInfo($productId),
1350 array(
"#PRODUCT_ID#" => $productId)
1352 ),
"DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT"
1360 if ($productQuantity <= $catalogQuantity)
1362 $fields[
"QUANTITY"] = $catalogQuantity - $productQuantity;
1364 elseif ($productQuantity <= $sumCatalogQuantity)
1366 $fields[
"QUANTITY"] = 0;
1367 $fields[
"QUANTITY_RESERVED"] = $catalogReservedQuantity - ($productQuantity - $catalogQuantity);
1372 new Sale\ResultError(
1374 "DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT",
1376 self::getProductCatalogInfo($productId),
1377 array(
"#PRODUCT_ID#" => $productId)
1379 ),
"DDCT_DEDUCTION_NOT_ENOUGHT_QUANTITY_PRODUCT"
1388 if ($isExistsReserve)
1390 $fields[
"QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
1394 $fields[
"QUANTITY"] = $catalogQuantity + $productQuantity;
1398 if (!$productData[
'PRODUCT'][
'USED_RESERVATION'])
1400 if (isset($fields[
'QUANTITY_RESERVED']))
1402 unset($fields[
'QUANTITY_RESERVED']);
1407 if (!empty($fields))
1409 $internalResult = Catalog\Model\Product::update($productId, $fields);
1411 if ($internalResult->isSuccess())
1414 $quantityValues = array();
1416 if (isset($fields[
'QUANTITY']))
1418 $quantityValues[QuantityControl::QUANTITY] = $fields[
'QUANTITY'];
1419 QuantityControl::resetAvailableQuantity($productId);
1422 if (isset($fields[
'QUANTITY_RESERVED']))
1424 $quantityValues[QuantityControl::RESERVED_QUANTITY] = $fields[
'QUANTITY_RESERVED'];
1427 if (!empty($quantityValues))
1429 QuantityControl::setValues($productId, $quantityValues);
1434 self::convertErrors($internalResult);
1436 unset($internalResult);
1441 'IS_UPDATED' => $isUpdated,
1453 private static function shipQuantityWithoutStoreControl(array $productData):
Sale\Result
1455 $result =
new Sale\Result();
1456 $productId = (int)$productData[
'PRODUCT_ID'];
1458 $catalogData = $productData[
'CATALOG'];
1460 $productQuantity = self::getTotalAmountFromQuantityList($productData);
1462 $catalogReservedQuantity = (float)$catalogData[
'QUANTITY_RESERVED'];
1463 $catalogQuantity = self::getTotalAmountFromPriceList($catalogData);
1467 $isExistsReserve = static::isExistsCommonStoreReserve($productData) && static::isReservationEnabled();
1468 $isNeedShip = ($productQuantity < 0);
1472 $productQuantity = abs($productQuantity);
1473 if (($productQuantity <= $catalogReservedQuantity + $catalogQuantity) || $catalogData[
"CAN_BUY_ZERO"] ==
"Y")
1475 if ($isExistsReserve)
1477 if ($productQuantity <= $catalogReservedQuantity)
1479 $needReservedQuantity = $catalogReservedQuantity - $productQuantity;
1480 $fields[
"QUANTITY_RESERVED"] = $needReservedQuantity;
1484 $fields[
"QUANTITY_RESERVED"] = 0;
1485 $fields[
"QUANTITY"] = $catalogQuantity - ($productQuantity - $catalogReservedQuantity);
1490 $fields[
"QUANTITY"] = $catalogQuantity - $productQuantity;
1497 new Sale\ResultError(
1499 "DDCT_DEDUCTION_QUANTITY_ERROR",
1501 self::getProductCatalogInfo($productId),
1502 array(
"#PRODUCT_ID#" => $productId)
1504 ),
"DDCT_DEDUCTION_QUANTITY_ERROR"
1511 if ($isExistsReserve)
1513 $fields[
"QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
1517 $fields[
"QUANTITY"] = $catalogQuantity + $productQuantity;
1521 if (!$productData[
'PRODUCT'][
'USED_RESERVATION'])
1523 if (isset($fields[
'QUANTITY_RESERVED']))
1525 unset($fields[
'QUANTITY_RESERVED']);
1529 if (!empty($fields))
1531 $internalResult = Catalog\Model\Product::update($productId, $fields);
1533 if ($internalResult-> isSuccess())
1535 $quantityValues = array();
1537 if (isset($fields[
'QUANTITY']))
1539 $quantityValues[QuantityControl::QUANTITY] = $fields[
'QUANTITY'];
1540 QuantityControl::resetAvailableQuantity($productId);
1543 if (isset($fields[
'QUANTITY_RESERVED']))
1545 $quantityValues[QuantityControl::RESERVED_QUANTITY] = $fields[
'QUANTITY_RESERVED'];
1548 if (!empty($quantityValues))
1550 QuantityControl::setValues($productId, $quantityValues);
1555 self::convertErrors($internalResult);
1557 unset($internalResult);
1563 private static function isExistsCommonStoreReserve(array $productData): bool
1566 empty($productData[
'NEED_RESERVE_BY_STORE_LIST'])
1567 || !is_array($productData[
'NEED_RESERVE_BY_STORE_LIST'])
1573 foreach ($productData[
'NEED_RESERVE_BY_STORE_LIST'] as $block)
1575 if (empty($block) || !is_array($block))
1579 if (in_array(
true, $block,
true))
1594 private static function getSetableStoreQuantityProduct(array $productData, array $productStoreDataList):
Sale\Result
1596 $result =
new Sale\Result();
1598 $setQuantityList = array();
1599 $productQuantity = self::getTotalAmountFromQuantityList($productData);
1600 $isNeedShip = ($productQuantity < 0);
1602 $quantityByStore = self::getQuantityDataFromStore($productData);
1603 $needQuantityList = $quantityByStore[
'AMOUNT'];
1605 if (empty($needQuantityList))
1607 $autoShipStore = static::getAutoShipStoreData($productData, $productStoreDataList);
1609 if (!empty($autoShipStore))
1611 $needQuantityList[$autoShipStore[
'STORE_ID']] = ($productQuantity > $autoShipStore[
'AMOUNT'] ? $autoShipStore[
'AMOUNT'] : abs($productQuantity));
1613 $shipmentItemList = $productData[
'SHIPMENT_ITEM_LIST'];
1615 foreach ($shipmentItemList as $index => $shipmentItem)
1617 $shipmentItemStoreCollection = $shipmentItem->getShipmentItemStoreCollection();
1618 if ($shipmentItemStoreCollection && $shipmentItemStoreCollection->count() === 0)
1620 $item = $shipmentItemStoreCollection->createItem($shipmentItem->getBasketItem());
1621 $item->setField(
'STORE_ID', $autoShipStore[
'STORE_ID']);
1622 $item->setField(
'QUANTITY', abs($productData[
'SHIPMENT_ITEM_QUANTITY_LIST'][$index]));
1628 if (!empty($productStoreDataList))
1630 $isReservationEnabled = Main\Config\Option::get(
"sale",
"product_reserve_condition") !=
"S";
1631 $compileReserve = self::getCompileReserve($productData);
1632 foreach ($productStoreDataList as $storeId => $productStoreData)
1634 $productId = $productStoreData[
'PRODUCT_ID'];
1636 if ($isNeedShip && (isset($needQuantityList[$storeId]) && $productStoreData[
'AMOUNT'] < $needQuantityList[$storeId]))
1639 new Sale\ResultError(
1641 'DDCT_DEDUCTION_QUANTITY_STORE_ERROR_2',
1643 self::getProductCatalogInfo($productId),
1645 '#STORE_NAME#' => \CCatalogStoreControlUtil::getStoreName($storeId),
1646 '#STORE_ID#' => $storeId,
1647 '#PRODUCT_ID#' => $productId,
1650 ),
'DDCT_DEDUCTION_QUANTITY_STORE_ERROR'
1656 $storeConfig = self::getUpdateStoreConfig(
1661 'RESERVATION_ENABLED' => $isReservationEnabled,
1664 if (!$storeConfig[
'AMOUNT'] && !$storeConfig[
'QUANTITY_RESERVED'])
1670 if ($storeConfig[
'AMOUNT'])
1672 $setQuantity = $productQuantity;
1674 if (isset($needQuantityList[$storeId]))
1676 $setQuantity = ($isNeedShip ? -1 : 1) * $needQuantityList[$storeId];
1679 $storeUpdate[
'AMOUNT'] = $productStoreData[
'AMOUNT'] + $setQuantity;
1680 $storeUpdate[
'DELTA'] = $setQuantity;
1681 $storeUpdate[
'OLD_AMOUNT'] = $productStoreData[
'AMOUNT'];
1682 unset($setQuantity);
1684 if ($storeConfig[
'QUANTITY_RESERVED'])
1686 $setReserveQuantity = 0;
1687 if (isset($needQuantityList[$storeId]))
1689 $setReserveQuantity = ($isNeedShip ? -1 : 1) * $needQuantityList[$storeId];
1691 if (isset($quantityByStore[
'QUANTITY_RESERVED'][$storeId]))
1693 $setReserveQuantity = ($isNeedShip ? -1 : 1) * $quantityByStore[
'QUANTITY_RESERVED'][$storeId];
1695 if ($setReserveQuantity != 0)
1697 $storeUpdate[
'QUANTITY_RESERVED'] = $productStoreData[
'QUANTITY_RESERVED']
1698 + $setReserveQuantity;
1699 $storeUpdate[
'OLD_QUANTITY_RESERVED'] = $productStoreData[
'QUANTITY_RESERVED'];
1700 $storeUpdate[
'QUANTITY_RESERVED_DELTA'] = $setReserveQuantity;
1702 unset($setReserveQuantity);
1704 if (!empty($storeUpdate))
1706 $setQuantityList[$productStoreData[
'ID']] = $storeUpdate;
1708 unset($storeUpdate, $storeConfig);
1713 if (!empty($setQuantityList))
1725 private static function getUpdateStoreConfig(
int $storeId, array $quantityList, array $reserveList, array $config): array
1728 'AMOUNT' => isset($quantityList[$storeId]),
1729 'QUANTITY_RESERVED' =>
false,
1732 if ($config[
'RESERVATION_ENABLED'])
1734 $result[
'QUANTITY_RESERVED'] = isset($reserveList[$storeId]);
1740 private static function getCompileReserve(array $product): array
1742 if (empty($product[
'NEED_RESERVE_BY_STORE_LIST']) || !is_array($product[
'NEED_RESERVE_BY_STORE_LIST']))
1748 foreach ($product[
'NEED_RESERVE_BY_STORE_LIST'] as $shipment)
1750 if (empty($shipment) || !is_array($shipment))
1754 foreach ($shipment as $storeId => $flag)
1766 private static function getQuantityDataFromStore(array $product): array
1770 'QUANTITY_RESERVED' => [],
1773 $storeDataExists = (
1774 !empty($product[
'STORE_DATA_LIST'])
1775 && is_array($product[
'STORE_DATA_LIST'])
1777 $reserveDataExists = (
1778 !empty($product[self::AMOUNT_SRC_STORE_RESERVED_LIST])
1779 && is_array($product[self::AMOUNT_SRC_STORE_RESERVED_LIST])
1781 if (!$storeDataExists && !$reserveDataExists)
1787 if ($storeDataExists)
1789 foreach ($product[
'STORE_DATA_LIST'] as $storeList)
1791 if (!is_array($storeList))
1796 foreach ($storeList as $storeId => $store)
1798 if (!isset($result[
'AMOUNT'][$storeId]))
1802 $result[
'AMOUNT'][
$storeId] += (float)$store[
'QUANTITY'];
1803 if (isset($store[
'RESERVED_QUANTITY']))
1805 if (!isset($result[
'QUANTITY_RESERVED'][$storeId]))
1807 $result[
'QUANTITY_RESERVED'][
$storeId] = 0;
1809 $result[
'QUANTITY_RESERVED'][
$storeId] += (float)$store[
'RESERVED_QUANTITY'];
1815 if (!$found && $reserveDataExists)
1817 switch (self::getQuantityFormat($product[self::AMOUNT_SRC_STORE_RESERVED_LIST]))
1819 case self::QUANTITY_FORMAT_STORE:
1820 $internalResult = self::calculateQuantityFromStores($product[self::AMOUNT_SRC_STORE_RESERVED_LIST]);
1822 case self::QUANTITY_FORMAT_SHIPMENT:
1823 $internalResult = self::calculateQuantityFromShipments($product[self::AMOUNT_SRC_STORE_RESERVED_LIST]);
1826 $internalResult =
null;
1829 if ($internalResult !==
null)
1831 $result[
'QUANTITY_RESERVED'] = $internalResult;
1833 unset($internalResult);
1844 private static function deleteBarcodes(array $productData):
Sale\Result
1846 $result =
new Sale\Result();
1848 $storeData = $productData[
'STORE_DATA_LIST'];
1849 if (!empty($storeData))
1851 foreach ($storeData as $storeDataList)
1853 foreach($storeDataList as $storeDataValue)
1855 $r = static::deleteBarcode($storeDataValue);
1856 if (!$r->isSuccess())
1858 $result->addErrors($r->getErrors());
1872 private static function deleteBarcode(array $storeData):
Sale\Result
1874 $result =
new Sale\Result();
1878 $barcodeMulti = $storeData[
'IS_BARCODE_MULTI'];
1880 $barcodeList = $storeData[
'BARCODE'];
1882 foreach ($barcodeList as $barcodeValue)
1884 if (trim($barcodeValue) ==
"" || !$barcodeMulti)
1889 $result =
new Sale\Result();
1890 $barcodeFields = array(
1891 "STORE_ID" => $storeId,
1892 "BARCODE" => $barcodeValue,
1893 "PRODUCT_ID" => $productId,
1896 $dbres = \CCatalogStoreBarcode::GetList(
1901 array(
"ID",
"STORE_ID",
"BARCODE",
"PRODUCT_ID")
1904 $catalogStoreBarcodeRes = $dbres->Fetch();
1905 if ($catalogStoreBarcodeRes)
1907 \CCatalogStoreBarcode::Delete($catalogStoreBarcodeRes[
"ID"]);
1912 new Sale\ResultError(
1914 "DDCT_DEDUCTION_BARCODE_ERROR",
1916 self::getProductCatalogInfo($productId),
1917 array(
"#BARCODE#" => $barcodeValue)
1919 ),
"DDCT_DEDUCTION_BARCODE_ERROR"
1933 private static function addBarcodes(array $productData):
Sale\Result
1935 $result =
new Sale\Result();
1936 $storeData = $productData[
'STORE_DATA_LIST'];
1937 if (!empty($storeData))
1939 foreach ($storeData as $storeDataList)
1941 foreach($storeDataList as $storeDataValue)
1943 $r = static::addBarcode($storeDataValue);
1944 if (!$r->isSuccess())
1946 $result->addErrors($r->getErrors());
1960 private static function addBarcode(array $storeData):
Sale\Result
1962 $result =
new Sale\Result();
1966 $barcodeMulti = $storeData[
'IS_BARCODE_MULTI'];
1968 $barcodeList = $storeData[
'BARCODE'];
1970 foreach ($barcodeList as $barcodeValue)
1972 if (trim($barcodeValue) ==
"" || !$barcodeMulti)
1977 $result =
new Sale\Result();
1978 $barcodeFields = array(
1979 "STORE_ID" => $storeId,
1980 "BARCODE" => $barcodeValue,
1981 "PRODUCT_ID" => $productId,
1983 \CCatalogStoreBarcode::Add($barcodeFields);
1994 public function reserve(array $products)
1996 $result =
new Sale\Result();
1998 $resultList = array();
2000 $availableItems = $this->createProductsListWithCatalogData($products);
2001 foreach ($availableItems as $productId => $productData)
2005 $r = static::reserveProduct($productData);
2006 if ($r->isSuccess())
2008 $resultData = $r->getData();
2009 if (!empty($resultData))
2016 $result->addErrors($r->getErrors());
2021 $result->setData(array(
2022 'RESERVED_PRODUCTS_LIST' => $resultList,
2033 private static function reserveProduct(array $productData):
Sale\Result
2036 !static::isReservationEnabled()
2037 || !$productData[
'PRODUCT'][
'USED_RESERVATION']
2040 return static::reserveQuantityWithDisabledReservation($productData);
2043 return self::reserveStoreQuantityWithEnabledReservation($productData);
2052 private static function reserveStoreQuantityWithEnabledReservation(array $productData):
Sale\Result
2054 $result =
new Sale\Result();
2056 $enableStoreControl = Catalog\Config\State::isUsedInventoryManagement();
2064 $storeProductQuantity = self::getStoreQuantityFromQuantityList($productData);
2071 $productQuantity = self::getTotalAmountFromQuantityList($productData);
2073 $isNeedReserve = ($productQuantity > 0);
2074 $catalogData = $productData[
'CATALOG'];
2076 $catalogReservedQuantity = (float)$catalogData[
'QUANTITY_RESERVED'];
2077 $catalogQuantity = self::getTotalAmountFromPriceList($catalogData);
2079 $sumCatalogQuantity = $catalogQuantity + $catalogReservedQuantity;
2081 if (isset($productData[
'NEED_SHIP']))
2083 $needShipList = $productData[
'NEED_SHIP'];
2086 $setQuantityReserved = $catalogReservedQuantity;
2088 if (!empty($needShipList) && !empty($productData[
'SHIPMENT_ITEM_DATA_LIST']))
2090 $shipmentItemList = $productData[
'SHIPMENT_ITEM_DATA_LIST'];
2091 foreach ($needShipList as $shipmentItemIndex => $isNeedShip)
2093 if ($setQuantityReserved <= 0)
2095 $setQuantityReserved = 0;
2099 if ($isNeedShip ===
true)
2101 $shipmentItemQuantity = $shipmentItemList[$shipmentItemIndex];
2103 $setQuantityReserved -= $shipmentItemQuantity;
2108 if ($catalogData[
"QUANTITY_TRACE"] ==
"N")
2110 $fields[
"QUANTITY_RESERVED"] = $setQuantityReserved;
2111 $resultFields[
'IS_UPDATED'] =
true;
2112 $resultFields[
'QUANTITY_RESERVED'] = 0;
2116 $resultFields[
'QUANTITY_RESERVED'] = $catalogReservedQuantity;
2119 $productData[
'PRODUCT'][
'TYPE'] === Catalog\ProductTable::TYPE_PRODUCT
2120 || $productData[
'PRODUCT'][
'TYPE'] === Catalog\ProductTable::TYPE_OFFER
2123 $storeFields = $enableStoreControl
2124 ? self::loadCurrentStoreReserve($productId, $storeProductQuantity)
2130 if ($catalogData[
"CAN_BUY_ZERO"] ==
"Y")
2132 $fields[
"QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
2133 $fields[
'QUANTITY'] = $catalogQuantity - $productQuantity;
2137 if ($catalogQuantity >= $productQuantity)
2139 $fields[
"QUANTITY"] = $catalogQuantity - $productQuantity;
2140 $fields[
"QUANTITY_RESERVED"] = $catalogReservedQuantity + $productQuantity;
2144 $resultFields[
"QUANTITY_NOT_RESERVED"] = $productQuantity - $catalogQuantity;
2146 $fields[
"QUANTITY"] = 0;
2147 $fields[
"QUANTITY_RESERVED"] = $sumCatalogQuantity;
2149 $result->addWarning(
2150 new Sale\ResultWarning(
2152 "RSRV_QUANTITY_NOT_ENOUGH_ERROR",
2153 self::getProductCatalogInfo($productId)
2154 ),
"ERROR_NOT_ENOUGH_QUANTITY"
2162 $correctReserve = 0;
2163 if ($enableStoreControl)
2165 foreach (array_keys($storeFields) as $storeId)
2167 if ($storeFields[$storeId][
'ID'] ===
null)
2171 $storeProductFields = $storeFields[
$storeId];
2172 $newReserve = $storeProductFields[
'QUANTITY_RESERVED'] + $storeProductFields[
'ADD_QUANTITY_RESERVED'];
2173 if ($newReserve < 0)
2175 $correctReserve -= $newReserve;
2176 $storeFields[
$storeId][
'ADD_QUANTITY_RESERVED'] -= $newReserve;
2181 $needQuantity = abs($productQuantity) - $correctReserve;
2183 $fields[
"QUANTITY"] = $catalogQuantity + $needQuantity;
2185 $needReservedQuantity = $catalogReservedQuantity - $needQuantity;
2186 if ($needQuantity > $catalogReservedQuantity)
2188 $needReservedQuantity = $catalogReservedQuantity;
2191 $fields[
"QUANTITY_RESERVED"] = $needReservedQuantity;
2193 if ($enableStoreControl)
2195 foreach (array_keys($storeFields) as $storeId)
2197 if ($storeFields[$storeId][
'ID'] ===
null)
2199 unset($storeFields[$storeId]);
2207 if (!$productData[
'PRODUCT'][
'USED_RESERVATION'])
2209 if (isset($fields[
'QUANTITY_RESERVED']))
2211 unset($fields[
'QUANTITY_RESERVED']);
2215 if (!empty($fields) && is_array($fields))
2217 $storeSuccess =
true;
2218 if ($enableStoreControl)
2220 foreach (array_keys($storeFields) as $index)
2224 $storeSuccess =
false;
2228 $storeProductFields = $storeFields[$index];
2229 $id = $storeProductFields[
'ID'];
2230 $storeProductFields[
'QUANTITY_RESERVED'] += $storeProductFields[
'ADD_QUANTITY_RESERVED'];
2231 unset($storeProductFields[
'ID'], $storeProductFields[
'ADD_QUANTITY_RESERVED']);
2234 $storeProductFields[
'AMOUNT'] = 0;
2235 $internalResult = Catalog\StoreProductTable::add($storeProductFields);
2239 unset($storeProductFields[
'STORE_ID'], $storeProductFields[
'PRODUCT_ID']);
2240 $internalResult = Catalog\StoreProductTable::update($id, $storeProductFields);
2242 if ($internalResult->isSuccess())
2244 $storeFields[$index][
'ID'] = (int)$internalResult->getId();
2248 $storeFields[$index][
'ERROR'] =
true;
2249 $storeFields[$index][
'ERROR_MESSAGES'] = $internalResult->getErrorMessages();
2250 $storeSuccess =
false;
2265 $resultFields[
'IS_UPDATED'] =
false;
2266 $internalResult = Catalog\Model\Product::update($productId, $fields);
2267 if ($internalResult->isSuccess())
2269 $resultFields[
'IS_UPDATED'] =
true;
2270 $quantityValues = array();
2271 if (isset($fields[
'QUANTITY']))
2273 $quantityValues[QuantityControl::QUANTITY] = $fields[
'QUANTITY'];
2274 QuantityControl::resetAvailableQuantity($productId);
2277 if (isset($fields[
'QUANTITY_RESERVED']))
2279 $quantityValues[QuantityControl::RESERVED_QUANTITY] = $fields[
'QUANTITY_RESERVED'];
2282 if (!empty($quantityValues))
2284 QuantityControl::setValues($productId, $quantityValues);
2289 self::convertErrors($internalResult);
2291 unset($internalResult);
2294 if (isset($resultFields[
'IS_UPDATED']))
2296 if (isset($fields[
'QUANTITY_RESERVED']))
2298 $needReserved = $fields[
"QUANTITY_RESERVED"] - $resultFields[
'QUANTITY_RESERVED'];
2299 if ($resultFields[
'QUANTITY_RESERVED'] > $fields[
"QUANTITY_RESERVED"])
2301 $needReserved = $fields[
"QUANTITY_RESERVED"];
2303 $resultFields[
"QUANTITY_RESERVED"] = $needReserved;
2306 if (!empty($resultFields))
2308 $result->setData($resultFields);
2320 private static function reserveQuantityWithDisabledReservation(array $productData):
Sale\Result
2322 $result =
new Sale\Result();
2324 $catalogData = $productData[
'CATALOG'];
2326 $isQuantityTrace = $catalogData[
"QUANTITY_TRACE"] ==
'Y';
2328 $productQuantity = self::getTotalAmountFromQuantityList($productData);
2329 $catalogQuantity = self::getTotalAmountFromPriceList($catalogData);
2334 'QUANTITY' => $catalogQuantity,
2337 if ($isQuantityTrace)
2340 $fields[
'QUANTITY'] -= $productQuantity;
2341 if ($catalogData[
"CAN_BUY_ZERO"] !=
"Y" && ($catalogQuantity < $productQuantity))
2343 $result->addWarning(
2344 new Sale\ResultWarning(
2346 "RESERVE_QUANTITY_NOT_ENOUGH_ERROR",
2348 self::getProductCatalogInfo($productId),
2349 array(
"#PRODUCT_ID#" => $productId)
2351 ),
"RESERVE_QUANTITY_NOT_ENOUGH_ERROR"
2355 $fields[
'QUANTITY'] = 0;
2358 $internalResult = Catalog\Model\Product::update($productId, $fields);
2359 if (!$internalResult->isSuccess())
2362 self::convertErrors($internalResult);
2364 unset($internalResult);
2369 $result->setData($fields);
2383 private static function checkParentActivity(array $productIds,
int $iblockId = 0): array
2385 $resultList = array();
2387 $productIdsToLoad = array();
2389 foreach ($productIds as $productId)
2393 if (static::isExistsHitCache(self::CACHE_PARENT_PRODUCT_ACTIVE, $cacheKey))
2395 if (static::getHitCache(self::CACHE_PARENT_PRODUCT_ACTIVE, $cacheKey) ===
'Y')
2406 if (!empty($productIdsToLoad))
2408 $productToOfferMap = array();
2409 $parentIds = array();
2411 $cacheResult = array_fill_keys($productIdsToLoad,
'N');
2413 $productList = \CCatalogSku::getProductList($productIdsToLoad);
2414 if (!empty($productList))
2416 foreach ($productList as $offerId => $productInfo)
2418 $productToOfferMap[$productInfo[
'ID']][] = $offerId;
2419 $parentIds[] = $productInfo[
'ID'];
2422 $itemList = \CIBlockElement::GetList(
2425 'ID' => array_unique($parentIds),
2426 'IBLOCK_ID' => $iblockId,
2428 'ACTIVE_DATE' =>
'Y',
2429 'CHECK_PERMISSIONS' =>
'N',
2435 while ($item = $itemList->Fetch())
2437 if (!empty($productToOfferMap[$item[
'ID']]))
2439 foreach ($productToOfferMap[$item[
'ID']] as $productId)
2448 foreach ($cacheResult as $productId => $value)
2450 static::setHitCache(self::CACHE_PARENT_PRODUCT_ACTIVE,
$productId.
'|'.$iblockId, $value);
2462 protected static function getPriceTitle($priceType)
2464 $priceType = (int)$priceType;
2465 if ($priceType <= 0)
2467 if (!isset(self::$priceTitleCache[$priceType]))
2469 self::$priceTitleCache[$priceType] =
'';
2470 $priceTypeList = Catalog\GroupTable::getTypeList();
2471 if (isset($priceTypeList[$priceType]))
2473 $groupName = (string)$priceTypeList[$priceType][
'NAME_LANG'];
2474 self::$priceTitleCache[$priceType] = ($groupName !=
'' ? $groupName : $priceTypeList[$priceType][
'NAME']);
2477 unset($priceTypeList);
2479 return self::$priceTitleCache[$priceType];
2487 public function tryShip(array $products)
2489 $result =
new Sale\Result();
2490 $resultList = array();
2492 $filteredProducts = $this->createQuantityFilteredProducts($products);
2494 if (empty($filteredProducts))
2498 'TRY_SHIP_PRODUCTS_LIST' => array_fill_keys(array_keys($products),
true),
2505 $availableItems = $this->createProductsListWithCatalogData($filteredProducts);
2506 if (empty($availableItems))
2508 $productIdList = array_keys($products);
2509 foreach($productIdList as $productId)
2512 new Sale\ResultError(
2514 "SALE_PROVIDER_PRODUCT_NOT_AVAILABLE",
2516 self::getProductCatalogInfo($productId),
2517 array(
"#PRODUCT_ID#" => $productId)
2519 ),
"SALE_PROVIDER_PRODUCT_NOT_AVAILABLE"
2526 'TRY_SHIP_PRODUCTS_LIST' => array_fill_keys($productIdList,
false),
2534 foreach ($availableItems as $productId => $productData)
2538 isset($productData[
'PRODUCT'][
'TYPE'])
2539 && $productData[
'PRODUCT'][
'TYPE'] === Catalog\ProductTable::TYPE_SERVICE
2543 (!isset($productData[
'CATALOG'][
'ACTIVE']) || $productData[
'CATALOG'][
'ACTIVE'] !==
'Y')
2544 || (!isset($productData[
'PRODUCT'][
'AVAILABLE']) || $productData[
'PRODUCT'][
'AVAILABLE'] !==
'Y')
2547 $messageId =
'SALE_PROVIDER_PRODUCT_SERVICE_NOT_AVAILABLE';
2552 if (!isset($productData[
'CATALOG'][
'ACTIVE']) || $productData[
'CATALOG'][
'ACTIVE'] !==
'Y')
2554 $messageId =
'SALE_PROVIDER_PRODUCT_NOT_AVAILABLE';
2557 if ($messageId !==
null)
2560 new Sale\ResultError(
2564 self::getProductCatalogInfo($productId),
2565 array(
"#PRODUCT_ID#" => $productId)
2567 ),
"SALE_PROVIDER_PRODUCT_NOT_AVAILABLE"
2572 unset($availableItems[$productId]);
2577 if (!empty($availableItems))
2579 if (Catalog\
Config\State::isUsedInventoryManagement())
2581 $r = $this->checkProductsInStore($availableItems);
2582 if ($r->isSuccess())
2584 $data = $r->getData();
2585 if (!empty($data[
'PRODUCTS_LIST_IN_STORE']))
2587 $resultList = $resultList + $data[
'PRODUCTS_LIST_IN_STORE'];
2592 $result->addErrors($r->getErrors());
2597 $r = $this->checkProductsQuantity($availableItems);
2598 if ($r->isSuccess())
2600 $data = $r->getData();
2601 if (!empty($data[
'PRODUCTS_LIST_REQUIRED_QUANTITY']))
2603 $resultList = $resultList + $data[
'PRODUCTS_LIST_REQUIRED_QUANTITY'];
2608 $result->addErrors($r->getErrors());
2614 if (!empty($resultList))
2618 'TRY_SHIP_PRODUCTS_LIST' => $resultList,
2631 public function isNeedShip(array $products)
2633 $result =
new Sale\Result();
2637 'IS_NEED_SHIP' => static::isReservationEnabled(),
2648 private function createQuantityFilteredProducts(array $products): array
2650 $resultList = array();
2651 foreach ($products as $productId => $productData)
2654 if (array_key_exists(
'QUANTITY', $productData))
2656 if ($productData[
'QUANTITY'] > 0)
2658 unset($resultList[$productId]);
2681 unset($resultList[$productId]);
2694 public function tryUnship(array $products)
2696 $result =
new Sale\Result();
2697 $resultList = array();
2698 $availableItems = $this->createProductsListWithCatalogData($products);
2700 if (Catalog\
Config\State::isUsedInventoryManagement())
2702 $r = $this->checkProductsInStore($availableItems);
2703 if ($r->isSuccess())
2705 $data = $r->getData();
2706 if (!empty($data[
'PRODUCTS_LIST_IN_STORE']))
2708 $resultList = $data[
'PRODUCTS_LIST_IN_STORE'];
2714 $r = $this->checkProductsQuantity($availableItems);
2715 if ($r->isSuccess())
2717 $data = $r->getData();
2718 if (!empty($data[
'PRODUCTS_LIST_REQUIRED_QUANTITY']))
2720 $resultList = $data[
'PRODUCTS_LIST_REQUIRED_QUANTITY'];
2730 if (!empty($resultList))
2732 $result->setData(array(
2733 'PRODUCTS_LIST_SHIPPED' => $resultList,
2745 public function checkProductsInStore(array $products)
2747 $result =
new Sale\Result();
2748 $resultList = array();
2750 $r = $this->checkProductInStores($products);
2751 if (!$r->isSuccess())
2756 $storeProductMap = $this->createStoreProductMap($products);
2758 $r = $this->checkExistsProductsInStore($products, $storeProductMap);
2759 if ($r->isSuccess())
2761 $data = $r->getData();
2762 if (!empty($data[
'PRODUCTS_LIST_EXISTS_IN_STORE']))
2764 $resultList = $data[
'PRODUCTS_LIST_EXISTS_IN_STORE'];
2772 $r = $this->checkProductQuantityInStore($products);
2773 if ($r->isSuccess())
2775 $data = $r->getData();
2776 if (!empty($data[
'PRODUCTS_LIST_REQUIRED_QUANTITY_IN_STORE']))
2778 $resultList = $data[
'PRODUCTS_LIST_REQUIRED_QUANTITY_IN_STORE'];
2783 $result->addErrors($r->getErrors());
2786 if (!empty($resultList))
2790 'PRODUCTS_LIST_IN_STORE' => $resultList,
2803 private function checkProductsQuantity(array $products):
Sale\Result
2805 $result =
new Sale\Result();
2807 $resultList = array();
2808 $availableQuantityList = array();
2809 $r = $this->getAvailableQuantity($products);
2810 if ($r->isSuccess())
2812 $resultData = $r->getData();
2813 if (!empty($resultData[
'AVAILABLE_QUANTITY_LIST']))
2815 $availableQuantityList = $resultData[
'AVAILABLE_QUANTITY_LIST'];
2824 $enabledReservation = static::isReservationEnabled();
2826 foreach ($products as $productId => $productData)
2828 if (empty($productData[
'CATALOG']))
2832 new Sale\ResultError(
2834 "SALE_PROVIDER_PRODUCT_NOT_AVAILABLE",
2836 self::getProductCatalogInfo($productId),
2837 array(
"#PRODUCT_ID#" => $productId)
2839 ),
"SALE_PROVIDER_PRODUCT_NOT_AVAILABLE"
2847 $catalogData = $productData[
'CATALOG'];
2850 if ($catalogData[
"CHECK_QUANTITY"])
2852 $productQuantity = self::getTotalAmountFromQuantityList($productData);
2854 $availableQuantity = 0;
2856 if (isset($availableQuantityList[$productId]))
2858 $availableQuantity = $availableQuantityList[
$productId];
2861 $availableQuantity += (float)$catalogData[
'QUANTITY_RESERVED'];
2863 if ($enabledReservation && $productQuantity > $availableQuantity)
2867 new Sale\ResultError(
2869 "DDCT_DEDUCTION_QUANTITY_ERROR",
2871 self::getProductCatalogInfo($productId),
2872 array(
"#PRODUCT_ID#" => $productId)
2874 ),
"DDCT_DEDUCTION_QUANTITY_ERROR"
2881 if (!empty($resultList))
2885 'PRODUCTS_LIST_REQUIRED_QUANTITY' => $resultList,
2898 private function createProductsListWithCatalogData(array $products): array
2900 $productDataList = array();
2901 $productIdList = array_fill_keys(array_keys($products),
true);
2902 $r = $this->getData($products, [self::USE_GATALOG_DATA,
'FULL_QUANTITY']);
2903 if ($r->isSuccess())
2905 $data = $r->getData();
2906 if (!empty($data[static::RESULT_CATALOG_LIST]))
2908 $productDataList = $data[static::RESULT_CATALOG_LIST];
2912 $resultList = array();
2913 $availableListId = array_intersect_key($productIdList, $productDataList);
2914 if (!empty($availableListId))
2916 foreach (array_keys($availableListId) as $productId)
2918 if (empty($productDataList[$productId]) || !is_array($productDataList[$productId]))
2924 unset($productDataList[$productId][
'PRODUCT']);
2937 protected function createStoreProductMap(array $products)
2939 $productStoreDataList = array();
2940 $r = $this->getProductListStores($products);
2941 if ($r->isSuccess())
2943 $data = $r->getData();
2944 if (!empty($data[
'PRODUCT_STORES_LIST']))
2946 $productStoreDataList = $data[
'PRODUCT_STORES_LIST'];
2950 $canAutoShipList = array();
2951 $r = $this->canProductListAutoShip($products);
2952 if ($r->isSuccess())
2954 $data = $r->getData();
2955 if (!empty($data[
'PRODUCT_CAN_AUTOSHIP_LIST']))
2957 $canAutoShipList = $data[
'PRODUCT_CAN_AUTOSHIP_LIST'];
2961 $storeProductList = array();
2962 foreach ($products as $productId => $productData)
2964 if (!empty($productData[
'STORE_DATA_LIST']) && static::isExistsBarcode($productData[
'STORE_DATA_LIST']))
2966 $storeProductList[
$productId] = $productData[
'STORE_DATA_LIST'];
2968 elseif (!empty($canAutoShipList[$productId]) && !empty($productStoreDataList[$productId]))
2970 $productQuantity = self::getTotalAmountFromQuantityList($productData);
2971 foreach ($productData[
'SHIPMENT_ITEM_DATA_LIST'] as $shipmentItemIndex => $shipmentItemQuantity)
2973 foreach ($productStoreDataList[$productId] as $productStoreData)
2975 $storeId = $productStoreData[
'STORE_ID'];
2977 'PRODUCT_ID' => $productId,
2978 'STORE_ID' => $storeId,
2979 'IS_BARCODE_MULTI' =>
false,
2980 'QUANTITY' => abs($productQuantity),
2987 return $storeProductList;
2990 private function checkProductInStores($products):
Sale\Result
2992 $result =
new Sale\Result();
2993 $productStoreDataList = array();
2994 $canAutoShipList = array();
2995 $r = $this->canProductListAutoShip($products);
2996 if ($r->isSuccess())
2998 $data = $r->getData();
2999 if (!empty($data[
'PRODUCT_CAN_AUTOSHIP_LIST']))
3001 $canAutoShipList = $data[
'PRODUCT_CAN_AUTOSHIP_LIST'];
3005 $r = $this->getProductListStores($products);
3006 if ($r->isSuccess())
3008 $data = $r->getData();
3009 if (!empty($data[
'PRODUCT_STORES_LIST']))
3011 $productStoreDataList = $data[
'PRODUCT_STORES_LIST'];
3015 foreach ($products as $productId => $productData)
3017 if (!empty($productData[
'STORE_DATA_LIST']))
3019 if (!static::isExistsBarcode($productData[
'STORE_DATA_LIST']))
3022 new Sale\ResultError(
3024 "DDCT_DEDUCTION_MULTI_BARCODE_EMPTY", self::getProductCatalogInfo($productId)
3025 ),
"DDCT_DEDUCTION_MULTI_BARCODE_EMPTY"
3030 elseif ($canAutoShipList[$productId] ===
false)
3032 if (!isset($productStoreDataList[$productId]))
3035 new Sale\ResultError(
3037 "DDCT_DEDUCTION_STORE_EMPTY_ERROR",
3038 self::getProductCatalogInfo($productId)
3039 ),
"DEDUCTION_STORE_ERROR1"
3043 elseif (count($productStoreDataList[$productId]) > 1)
3046 new Sale\ResultError(
3048 "DDCT_DEDUCTION_STORE_ERROR",
3049 self::getProductCatalogInfo($productId)
3050 ),
"DEDUCTION_STORE_ERROR1"
3061 private static function isExistsBarcode(array $list): bool
3063 $resultValue =
false;
3064 foreach ($list as $storeDataList)
3066 foreach ($storeDataList as $storeValue)
3068 if (is_array($storeValue[
'BARCODE']) && $storeValue[
'IS_BARCODE_MULTI'] ===
true)
3070 foreach ($storeValue[
"BARCODE"] as $barcodeValue)
3072 if (trim($barcodeValue) ==
"")
3074 return $resultValue;
3078 $resultValue =
true;
3083 return (!empty($storeValue[
'BARCODE']));
3089 return $resultValue;
3097 protected function checkProductQuantityInStore(array $products)
3099 $result =
new Sale\Result();
3101 $resultList = array();
3102 $productQuantityList = array();
3103 $usedProductStoreQuantity = [];
3105 $productStoreDataList = self::loadCurrentProductStores(array_keys($products));
3107 foreach ($products as $productId => $productData)
3109 if (empty($productData[
'CATALOG']))
3112 isset($productData[
'PRODUCT'])
3113 && !$productData[
'PRODUCT'][
'USED_STORE_INVENTORY']
3119 $productStoreData = $productStoreDataList[
$productId] ?? [];
3121 $storeDataList = $productData[
'STORE_DATA_LIST'];
3123 if (!empty($storeDataList))
3125 foreach ($storeDataList as $barcodeList)
3127 foreach($barcodeList as $storeId => $storeDataValue)
3129 if (!empty($storeDataValue))
3132 !isset($productStoreData[$storeId])
3133 || ($productStoreData[$storeId][
"AMOUNT"] < $storeDataValue[
"QUANTITY"])
3137 new Sale\ResultError(
3139 'DDCT_DEDUCTION_QUANTITY_STORE_ERROR_2',
3141 self::getProductCatalogInfo($productId),
3143 '#STORE_NAME#' => \CCatalogStoreControlUtil::getStoreName($storeId),
3144 '#STORE_ID#' => $storeId,
3147 ),
'DDCT_DEDUCTION_QUANTITY_STORE_ERROR'
3153 if (!isset($productQuantityList[$productId]))
3158 $productQuantityList[
$productId] += $storeDataValue[
"QUANTITY"];
3160 if (!isset($usedProductStoreQuantity[$productId]))
3166 $r = static::checkProductBarcodes($productData, $productStoreData[$storeId], $storeDataValue);
3167 if ($r->isSuccess())
3169 if (!array_key_exists($productId, $resultList))
3176 $result->addErrors($r->getErrors());
3182 if (!array_key_exists($productId, $resultList))
3194 if (!isset($productQuantityList[$productId]))
3204 $productQuantityList[
$productId] = array_sum(
3212 if (!empty($productQuantityList))
3214 foreach ($productQuantityList as $amountProductId => $amountValue)
3216 $product = $products[$amountProductId];
3217 $catalogData = $product[
'CATALOG'];
3219 $catalogQuantity = self::getTotalAmountFromPriceList($catalogData);
3220 $catalogReservedQuantity = (float)$catalogData[
'QUANTITY_RESERVED'];
3224 $catalogQuantity += $catalogReservedQuantity;
3228 $unusedReserve = 0.0;
3229 if (isset($usedProductStoreQuantity[$amountProductId]))
3231 $usedProductStores = $usedProductStoreQuantity[$amountProductId];
3232 $productStores = $productStoreDataList[$amountProductId];
3233 foreach (array_keys($productStores) as $storeId)
3235 if (isset($usedProductStores[$storeId]))
3239 $unusedReserve += $productStores[
$storeId][
'QUANTITY_RESERVED'];
3242 unset($productStores, $usedProductStores);
3244 $catalogQuantity += $unusedReserve;
3245 unset($unusedReserve);
3248 if ($amountValue > $catalogQuantity)
3251 new Sale\ResultError(
3253 "DDCT_DEDUCTION_SHIPMENT_QUANTITY_NOT_ENOUGH",
3254 self::getProductCatalogInfo($amountProductId)
3255 ),
"SALE_PROVIDER_SHIPMENT_QUANTITY_NOT_ENOUGH"
3262 if (!empty($resultList))
3266 'PRODUCTS_LIST_REQUIRED_QUANTITY_IN_STORE' => $resultList,
3280 protected function checkExistsProductItemInStore(array $productData, array $storeDataList = array())
3282 $result =
new Sale\Result();
3284 if (!empty($storeDataList))
3286 foreach ($storeDataList as $storeData)
3288 foreach ($storeData as $storeDataValue)
3290 $storeId = $storeDataValue[
'STORE_ID'];
3292 if ((
int)$storeId < -1 || (
int)$storeId == 0
3293 || !isset($storeDataValue[
"QUANTITY"]) || (
int)$storeDataValue[
"QUANTITY"] < 0)
3296 new Sale\ResultError(
3298 "DDCT_DEDUCTION_STORE_ERROR",
3299 self::getProductCatalogInfo($productData[
'PRODUCT_ID'])
3300 ),
"DDCT_DEDUCTION_STORE_ERROR"
3310 $result->addError(
new Sale\ResultError(
3311 Main\Localization\
Loc::getMessage(
"DDCT_DEDUCTION_STORE_ERROR", self::getProductCatalogInfo($productData[
'PRODUCT_ID'])),
3312 "DEDUCTION_STORE_ERROR1"
3325 protected function checkExistsProductsInStore(array $products, array $storeData = array())
3327 $result =
new Sale\Result();
3329 $resultList = array();
3330 if (!empty($storeData))
3332 foreach ($products as $productId => $productData)
3334 $productStoreData = array();
3335 if (!empty($storeData[$productId]))
3344 isset($productData[
'BUNDLE_PARENT'])
3345 && $productData[
'BUNDLE_PARENT'] ===
true
3348 isset($productData[
'PRODUCT'][
'USED_STORE_INVENTORY'])
3349 && !$productData[
'PRODUCT'][
'USED_STORE_INVENTORY']
3356 $r = $this->checkExistsProductItemInStore($productData, $productStoreData);
3357 if (!$r->isSuccess())
3359 $result->addErrors($r->getErrors());
3365 if (!empty($resultList))
3369 'PRODUCTS_LIST_EXISTS_IN_STORE' => $resultList,
3384 protected static function checkProductBarcodes(array $productData, array $productStoreData, array $storeData = array())
3386 $result =
new Sale\Result();
3389 $storeId = $productStoreData[
'STORE_ID'];
3391 if (isset($storeData[
'BARCODE']) && count($storeData[
'BARCODE']) > 0)
3393 foreach ($storeData[
'BARCODE'] as $barcodeValue)
3395 if (trim($barcodeValue) ==
"" && $storeData[
'IS_BARCODE_MULTI'] ===
true)
3398 new Sale\ResultError(
3400 "DDCT_DEDUCTION_MULTI_BARCODE_EMPTY",
3402 self::getProductCatalogInfo($productId),
3403 array(
"#STORE_ID#" => $storeId)
3405 ),
"DDCT_DEDUCTION_MULTI_BARCODE_EMPTY"
3410 if (!empty($barcodeValue))
3413 '=STORE_ID' => static::CATALOG_PROVIDER_EMPTY_STORE_ID,
3414 '=BARCODE' => $barcodeValue,
3418 if ($storeData[
'IS_BARCODE_MULTI'] ===
true)
3422 $iterator = Catalog\StoreBarcodeTable::getList([
3424 'filter' => $fields,
3427 $row = $iterator->fetch();
3432 $result->addError(
new Sale\ResultError(
3434 "DDCT_DEDUCTION_BARCODE_ERROR",
3435 array_merge(self::getProductCatalogInfo($productId), array(
"#BARCODE#" => $barcodeValue))
3437 "DDCT_DEDUCTION_BARCODE_ERROR"
3445 $result->addError(
new Sale\ResultError(
3447 "DDCT_DEDUCTION_MULTI_BARCODE_EMPTY",
3448 array_merge(self::getProductCatalogInfo($productId), array(
"#STORE_ID#" => $storeId))
3450 "DDCT_DEDUCTION_MULTI_BARCODE_EMPTY"
3462 private function canProductListAutoShip(array $products):
Sale\Result
3465 if (empty($context[
'SITE_ID']))
3467 throw new Main\ArgumentNullException(
'SITE_ID');
3470 static $canAutoList = array();
3472 $resultList = array();
3477 $countStoresResult = $this->getStoresCount();
3478 if ($countStoresResult->isSuccess())
3480 $countStores = $countStoresResult->get(
'STORES_COUNT');
3483 $countStoresResult->getData();
3484 $defaultDeductionStore = (int)Main\
Config\Option::get(
"sale",
"deduct_store_id",
"", $context[
'SITE_ID']);
3485 $isDefaultStore = ($defaultDeductionStore > 0);
3486 foreach ($products as $productId => $productData)
3488 if (isset($canAutoList[$productId]))
3494 if (!$productData[
'PRODUCT'][
'USED_STORE_INVENTORY'])
3501 $isOneStore = ($countStores == 1 || $countStores == -1);
3503 $isOnlyOneStore = ($isOneStore || $isDefaultStore);
3505 if (isset($productData[
'STORE_DATA_LIST']))
3507 $storeData = array();
3508 $shipmentItemStoreData = reset($productData[
'STORE_DATA_LIST']);
3509 if (!empty($shipmentItemStoreData))
3511 $storeData = reset($shipmentItemStoreData);
3514 if (!empty($storeData))
3516 $isMulti = isset($storeData[
'IS_BARCODE_MULTI']) && $storeData[
'IS_BARCODE_MULTI'] ===
true;
3519 elseif (isset($productData[
'IS_BARCODE_MULTI']))
3521 $isMulti = $productData[
'IS_BARCODE_MULTI'] ===
true;
3524 $resultList[
$productId] = ($isOnlyOneStore && !$isMulti);
3535 $productStoreList = [];
3536 $r = $this->getProductListStores($products);
3537 if ($r->isSuccess())
3539 $productStoreData = $r->getData();
3541 !empty($productStoreData[
'PRODUCT_STORES_LIST'])
3542 && is_array($productStoreData[
'PRODUCT_STORES_LIST'])
3545 $productStoreList = $productStoreData[
'PRODUCT_STORES_LIST'];
3549 if (!empty($productStoreList))
3551 foreach ($products as $productId => $productData)
3553 if (!empty($productStoreList[$productId]))
3555 $countProductInStore = 0;
3556 foreach ($productStoreList[$productId] as $storeData)
3558 if ((
float)$storeData[
'AMOUNT'] > 0)
3560 $countProductInStore++;
3563 $resultList[
$productId] = ($countProductInStore == 1);
3570 $result =
new Sale\Result();
3571 if (!empty($resultList))
3575 'PRODUCT_CAN_AUTOSHIP_LIST' => $resultList,
3589 private static function getAutoShipStoreData(array $product, array $productStoreDataList)
3592 if (isset($product[
'STORE_DATA_LIST']))
3595 $shipmentItemStoreData = reset($product[
'STORE_DATA_LIST']);
3596 if (!empty($shipmentItemStoreData))
3598 $storeData = reset($shipmentItemStoreData);
3601 if (!empty($storeData))
3603 $isMulti = isset($storeData[
'IS_BARCODE_MULTI']) && $storeData[
'IS_BARCODE_MULTI'] ===
true;
3606 elseif (isset($product[
'IS_BARCODE_MULTI']))
3608 $isMulti = $product[
'IS_BARCODE_MULTI'] ===
true;
3616 $outputStoreData =
false;
3618 if (!empty($productStoreDataList))
3620 $countProductInStore = 0;
3622 $storeProductData =
false;
3623 foreach ($productStoreDataList as $storeData)
3625 if ((
float)$storeData[
'AMOUNT'] > 0)
3627 $countProductInStore++;
3628 if (!$storeProductData)
3630 $storeProductData = $storeData;
3635 if ($countProductInStore == 1 && !empty($storeProductData))
3637 $outputStoreData = $storeProductData;
3641 return $outputStoreData;
3649 protected function getCountProductsInStore(array $products)
3651 $result =
new Sale\Result();
3653 $productStoreList = array();
3654 $productStoreResult = $this->getProductListStores($products);
3655 if ($productStoreResult->isSuccess())
3657 $productStoreData = $productStoreResult->getData();
3659 if (array_key_exists(
'PRODUCT_STORES_LIST', $productStoreData))
3661 $productStoreList = $productStoreData[
'PRODUCT_STORES_LIST'];
3665 if (empty($productStoreList))
3670 $resultList = array();
3671 foreach ($productStoreList as $productStoreDataList)
3673 foreach ($productStoreDataList as $storeId =>$productStoreData)
3675 $productId = $productStoreData[
'PRODUCT_ID'];
3676 if ($productStoreData[
'AMOUNT'] > 0)
3678 if (!isset($resultList[$productId]))
3688 if (!empty($resultList))
3692 'RESULT_LIST' => $resultList,
3704 public function getStoresCount()
3706 $result =
new Sale\Result();
3710 if (Catalog\
Config\State::isUsedInventoryManagement())
3712 $count = count($this->getStoreIds());
3717 'STORES_COUNT' => $count,
3727 private function getStoreIds(): array
3734 if (isset($context[
'SITE_ID']) && $context[
'SITE_ID'] !==
'')
3736 $filterId[
'+SITE_ID'] = $context[
'SITE_ID'];
3739 $cacheId = md5(serialize($filterId));
3740 $storeIds = static::getHitCache(self::CACHE_STORE, $cacheId);
3741 if (empty($storeIds))
3745 $filter = Main\Entity\Query::filter();
3746 $filter->where(
'ACTIVE',
'=',
'Y');
3747 if (isset($context[
'SITE_ID']) && $context[
'SITE_ID'] !=
'')
3749 $subFilter = Main\Entity\Query::filter();
3750 $subFilter->logic(
'or')->where(
'SITE_ID',
'=', $context[
'SITE_ID'])->where(
'SITE_ID',
'=',
'')->whereNull(
'SITE_ID');
3751 $filter->where($subFilter);
3755 $iterator = Catalog\StoreTable::getList([
3756 'select' => [
'ID',
'SORT'],
3757 'filter' => $filter,
3758 'order' => [
'SORT' =>
'ASC',
'ID' =>
'ASC'],
3760 while ($row = $iterator->fetch())
3762 $storeIds[] = (int)$row[
'ID'];
3764 unset($row, $iterator, $filter);
3765 if (!empty($storeIds))
3767 static::setHitCache(self::CACHE_STORE, $cacheId, $storeIds);
3770 unset($cacheId, $filterId);
3780 public function getProductListStores(array $products)
3782 $result =
new Sale\Result();
3785 if (!Catalog\
Config\State::isUsedInventoryManagement())
3790 $storeIds = $this->getStoreIds();
3791 if (empty($storeIds))
3797 $productGetIdList = [];
3798 foreach (array_keys($products) as $productId)
3813 isset($products[$productId][
'PRODUCT'][
'USED_STORE_INVENTORY'])
3814 && !$products[$productId][
'PRODUCT'][
'USED_STORE_INVENTORY']
3822 if (!empty($productGetIdList))
3824 $emptyProductStores = [];
3825 $iterator = Catalog\StoreTable::getList([
3837 while ($row = $iterator->fetch())
3839 $id = (int)$row[
'ID'];
3840 $emptyProductStores[$id] = [
3843 'STORE_ID' => $row[
'ID'],
3845 'QUANTITY_RESERVED' => 0,
3846 'STORE_NAME' => $row[
'TITLE'],
3849 unset($row, $iterator);
3851 foreach (array_chunk($productGetIdList, 500) as $pageIds)
3853 foreach ($pageIds as $productId)
3855 $rows = $emptyProductStores;
3856 foreach (array_keys($rows) as $storeId)
3864 $iterator = Catalog\StoreProductTable::getList([
3870 'QUANTITY_RESERVED',
3873 '=PRODUCT_ID' => $pageIds,
3874 '@STORE_ID' => $storeIds,
3877 'PRODUCT_ID' =>
'ASC',
3878 'STORE_ID' =>
'ASC',
3881 while ($row = $iterator->fetch())
3883 $row[
'ID'] = (int)$row[
'ID'];
3884 $row[
'PRODUCT_ID'] = (int)$row[
'PRODUCT_ID'];
3885 $row[
'STORE_ID'] = (int)$row[
'STORE_ID'];
3886 if (!isset($resultList[$row[
'PRODUCT_ID']]))
3888 $resultList[$row[
'PRODUCT_ID']] = [];
3890 $resultList[$row[
'PRODUCT_ID']][$row[
'STORE_ID']][
'ID'] = $row[
'ID'];
3891 $resultList[$row[
'PRODUCT_ID']][$row[
'STORE_ID']][
'AMOUNT'] = (float)$row[
'AMOUNT'];
3892 $resultList[$row[
'PRODUCT_ID']][$row[
'STORE_ID']][
'QUANTITY_RESERVED'] = (float)$row[
'QUANTITY_RESERVED'];
3894 unset($iterator, $row);
3908 if (!empty($resultList))
3911 'PRODUCT_STORES_LIST' => $resultList,
3925 protected static function getHitCache($type, $key, array $fields = array())
3927 if (!empty(self::$hitCache[$type]) && !empty(self::$hitCache[$type][$key]))
3929 if (static::isExistsHitCache($type, $key, $fields))
3931 return self::$hitCache[$type][$key];
3945 protected static function isExistsHitCache($type, $key, array $fields = []): bool
3948 if (!empty(self::$hitCache[$type]) && !empty(self::$hitCache[$type][$key]))
3951 if (!empty($fields) && is_array($fields) && is_array(self::$hitCache[$type][$key]))
3953 foreach ($fields as $name)
3955 if (!array_key_exists($name, self::$hitCache[$type][$key]))
3972 protected static function setHitCache(
string $type, $key, $value): void
3974 if (!isset(self::$hitCache[$type]))
3976 self::$hitCache[$type] = [];
3979 if (!isset(self::$hitCache[$type][$key]))
3981 self::$hitCache[$type][$key] = [];
3984 self::$hitCache[$type][$key] = $value;
3990 protected static function clearHitCache(?
string $type =
null): void
3994 self::$hitCache = [];
3996 elseif (isset(self::$hitCache[$type]))
3998 unset(self::$hitCache[$type]);
4007 protected static function clearNotCacheFields($fields)
4009 $resultFields = array();
4010 $clearFields = static::getNotCacheFields();
4011 foreach ($fields as $name => $value)
4014 if (mb_substr($clearName, 0, 1) ==
'~')
4016 $clearName = mb_substr($clearName, 1, mb_strlen($clearName));
4019 if (!in_array($clearName, $clearFields))
4021 $resultFields[$name] = $value;
4025 return $resultFields;
4031 protected static function getNotCacheFields()
4041 protected static function checkNeedFields(array $fields, array $need)
4043 foreach ($need as $name => $value)
4045 if (!array_key_exists($name, $fields))
4065 protected static function isNeedClearPublicCache($currentQuantity, $newQuantity, $quantityTrace, $canBuyZero, $ratio = 1): bool
4077 protected static function clearPublicCache($productID, $productInfo = array()): void {}
4084 public function getAvailableQuantity(array $products)
4086 $result = $this->getAvailableQuantityByStore($products);
4087 if (!$result->isSuccess())
4091 $data = $result->getData();
4099 foreach ($reservedList as $productId => $rows)
4103 unset($productId, $rows);
4104 unset($reservedList, $data);
4113 public function getAvailableQuantityByStore(array $products):
Sale\Result
4115 $result =
new Sale\Result();
4118 $isGotQuantityDataList = [];
4120 foreach ($products as $productId => $productData)
4122 $catalogAvailableQuantity = QuantityControl::getAvailableQuantity($productId);
4123 $catalogQuantity = QuantityControl::getQuantity($productId);
4125 if ($catalogQuantity ===
null || $catalogAvailableQuantity ===
null)
4130 $productQuantity = self::getStoreAmountFromQuantityList($productData);
4131 if ($productQuantity ===
null)
4135 if ($catalogAvailableQuantity < array_sum($productQuantity))
4145 if (count($resultList) != count($products))
4147 if ($this->isExistsCatalogData($products))
4153 $items = $this->createProductsListWithCatalogData($products);
4156 foreach ($items as $productId => $productData)
4158 if (isset($isGotQuantityDataList[$productId]))
4163 if (empty($productData[
'CATALOG']) || !is_array($productData[
'CATALOG']))
4168 $catalogData = $productData[
'CATALOG'];
4170 $productQuantity = self::getStoreAmountFromQuantityList($productData);
4171 if ($productQuantity ===
null)
4178 $catalogQuantity = self::getTotalAmountFromPriceList($catalogData,
false);
4180 QuantityControl::setQuantity($productId, $catalogQuantity);
4182 if ($catalogData[
'CHECK_QUANTITY'])
4184 $totalReservedQuantity = 0;
4185 $reservedQuantity = self::getStoreReservedQuantityFromProduct($productData);
4186 if ($reservedQuantity !==
null)
4188 $totalReservedQuantity = array_sum($reservedQuantity);
4191 $needQuantity = (array_sum($productQuantity) - $totalReservedQuantity);
4192 if ($catalogQuantity < $needQuantity)
4194 $limitQuantity = $catalogQuantity;
4196 arsort($availableList, SORT_NUMERIC);
4197 foreach (array_keys($availableList) as $storeId)
4200 if ($limitQuantity > $storeQuantity)
4202 $limitQuantity -= $storeQuantity;
4206 $storeQuantity = $limitQuantity;
4207 if ($limitQuantity > 0)
4219 if (!empty($resultList))
4234 public function getAvailableQuantityAndPrice(array $products)
4236 $result =
new Sale\Result();
4237 $availableQuantityListResult = $this->getAvailableQuantity($products);
4239 if ($this->isExistsCatalogData($products))
4245 $items = $this->createProductsListWithCatalogData($products);
4248 $priceDataList = array();
4250 foreach ($items as $productId => $productData)
4252 $catalogData = $productData[
'CATALOG'];
4254 if (!empty($catalogData[
'PRICE_LIST']))
4256 $priceDataList[
$productId] = $catalogData[
'PRICE_LIST'];
4261 $availableQuantityData = array();
4263 if ($availableQuantityListResult->isSuccess())
4265 $availableQuantityList = $availableQuantityListResult->getData();
4283 public function writeOffProductBatches(array $products):
Sale\Result
4285 $result =
new Sale\Result();
4287 if (!Catalog\
Config\State::isUsedInventoryManagement() || !State::isProductBatchMethodSelected())
4292 foreach ($products as $productId => $productData)
4294 if (empty($productData[
'SHIPMENT_ITEM_LIST']) || !is_array($productData[
'SHIPMENT_ITEM_LIST']))
4299 $productBatch =
new BatchManager($productId);
4301 foreach ($productData[
'SHIPMENT_ITEM_LIST'] as $item)
4304 foreach ($item->getShipmentItemStoreCollection() as $storeItem)
4306 $quantity = $storeItem->getQuantity();
4312 $distributor =
new DistributionStrategy\ShipmentStore($productBatch, $storeItem);
4313 $r = $distributor->writeOff($quantity);
4314 if (!$r->isSuccess())
4316 $result->addErrors($r->getErrors());
4325 public function returnProductBatches(array $products):
Sale\Result
4327 $result =
new Sale\Result();
4329 if (!Catalog\
Config\State::isUsedInventoryManagement() || !State::isProductBatchMethodSelected())
4334 foreach ($products as $productId => $productData)
4336 if (empty($productData[
'SHIPMENT_ITEM_LIST']) || !is_array($productData[
'SHIPMENT_ITEM_LIST']))
4341 $productBatch =
new BatchManager($productId);
4343 foreach ($productData[
'SHIPMENT_ITEM_LIST'] as $item)
4345 foreach ($item->getShipmentItemStoreCollection() as $storeItem)
4347 $distributor =
new DistributionStrategy\ShipmentStore($productBatch, $storeItem);
4348 $r = $distributor->return();
4349 if (!$r->isSuccess())
4351 $result->addErrors($r->getErrors());
4365 private function isExistsCatalogData($products): bool
4367 foreach ($products as $productData)
4369 if (empty($productData[
'CATALOG']))
4382 private function getIblockData(array $list): array
4385 $res = Catalog\CatalogIblockTable::getList([
4389 'PRODUCT_IBLOCK_ID',
4390 'CATALOG_XML_ID' =>
'IBLOCK.XML_ID',
4392 'filter' => [
'@IBLOCK_ID' => $list],
4394 while($iblockData = $res->fetch())
4396 $resultList[$iblockData[
'IBLOCK_ID']] = $iblockData;
4397 if ($this->enableCache)
4399 static::setHitCache(self::CACHE_CATALOG_IBLOCK_LIST, $iblockData[
'IBLOCK_ID'], $iblockData);
4402 unset($res, $iblockData);
4412 private static function checkSkuPermission(array $iblockProductMap): array
4414 $resultList = array();
4416 foreach ($iblockProductMap as $iblockData)
4418 if ($iblockData[
'PRODUCT_IBLOCK_ID'] > 0 && !empty($iblockData[
'PRODUCT_LIST']))
4420 $resultList = array_merge(
4422 static::checkParentActivity($iblockData[
'PRODUCT_LIST'], (
int)$iblockData[
'PRODUCT_IBLOCK_ID'])
4427 foreach ($iblockData[
'PRODUCT_LIST'] as $productId)
4443 private static function createIblockProductMap(array $iblockList, array $iblockDataList): array
4445 $resultList = $iblockDataList;
4446 foreach ($iblockList as $iblockId => $iblockProductList)
4448 if (isset($iblockDataList[$iblockId]))
4450 $resultList[$iblockId][
'PRODUCT_LIST'] = $iblockProductList;
4463 private static function changeSubscribeProductQuantity(array $products, array $iblockProductMap): array
4465 $resultList = $products;
4467 foreach ($iblockProductMap as $iblockData)
4469 if ($iblockData[
'SUBSCRIPTION'] !=
'Y')
4472 if (empty($iblockData[
'PRODUCT_LIST']))
4475 foreach($iblockData[
'PRODUCT_LIST'] as $productId)
4477 if (isset($resultList[$productId]))
4502 private static function getCatalogProducts(array $list, array $select): array
4504 $usedStoreInventory = Catalog\Config\State::isUsedInventoryManagement();
4506 $typesWithoutStores = [
4507 Catalog\ProductTable::TYPE_SET =>
true,
4508 Catalog\ProductTable::TYPE_SKU =>
true,
4509 Catalog\ProductTable::TYPE_SERVICE =>
true,
4511 $typesWithoutReservation = [
4512 Catalog\ProductTable::TYPE_SET =>
true,
4513 Catalog\ProductTable::TYPE_SKU =>
true,
4514 Catalog\ProductTable::TYPE_SERVICE =>
true,
4525 $select[] =
'AVAILABLE';
4527 $select = array_unique($select);
4529 Main\Type\Collection::normalizeArrayValuesByInt($list,
true);
4535 foreach (array_chunk($list, 500) as $pageIds)
4537 $iterator = Catalog\Model\Product::getList([
4538 'select' => $select,
4543 while ($row = $iterator->fetch())
4545 $row[
'ID'] = (int)$row[
'ID'];
4546 $row[
'TYPE'] = (int)$row[
'TYPE'];
4547 $row[
'QUANTITY'] = (float)$row[
'QUANTITY'];
4548 $row[
'QUANTITY_RESERVED'] = (float)$row[
'QUANTITY_RESERVED'];
4549 $row[
'CHECK_QUANTITY'] = (
4550 $row[
'TYPE'] !== Catalog\ProductTable::TYPE_SERVICE
4551 && $row[
'QUANTITY_TRACE'] === Catalog\ProductTable::STATUS_YES
4552 && $row[
'CAN_BUY_ZERO'] === Catalog\ProductTable::STATUS_NO
4554 Catalog\Product\SystemField::prepareRow($row, Catalog\Product\SystemField::OPERATION_PROVIDER);
4556 if (isset($typesWithoutStores[$row[
'TYPE']]))
4558 $row[
'USED_STORE_INVENTORY'] =
false;
4562 $row[
'USED_STORE_INVENTORY'] = $usedStoreInventory;
4564 if (isset($typesWithoutReservation[$row[
'TYPE']]))
4566 $row[
'USED_RESERVATION'] =
false;
4567 $row[
'QUANTITY_RESERVED'] = 0;
4571 $row[
'USED_RESERVATION'] =
true;
4574 $resultList[$row[
'ID']] = $row;
4576 unset($row, $iterator);
4588 private static function getMeasure($id =
null): array
4590 static $measureList = array();
4592 if (!empty($measureList[$id]))
4594 return $measureList[$id];
4599 'MEASURE_NAME' => $id,
4600 'MEASURE_CODE' => 0,
4605 $measure = \CCatalogMeasure::getDefaultMeasure(
true,
true);
4606 $fields[
'MEASURE_NAME'] = $measure[
'~SYMBOL_RUS'];
4607 $fields[
'MEASURE_CODE'] = $measure[
'CODE'];
4611 $resMeasures = \CCatalogMeasure::getList(
4616 array(
'ID',
'SYMBOL_RUS',
'CODE')
4618 $measure = $resMeasures->fetch();
4620 if (!empty($measure))
4622 $fields[
'MEASURE_NAME'] = $measure[
'SYMBOL_RUS'];
4623 $fields[
'MEASURE_CODE'] = $measure[
'CODE'];
4627 $measureList[$id] = $fields;
4639 private static function createProductPriceList(array $products, array $productPriceList, array $discountList = array()): array
4641 $priceResultList = array();
4643 foreach ($productPriceList as $basketCode => $priceData)
4647 $priceResultList[$basketCode][
'PRODUCT_PRICE_ID'] = $priceData[
'RESULT_PRICE'][
'ID'];
4648 $priceResultList[$basketCode][
'NOTES'] = $priceData[
'PRICE'][
'CATALOG_GROUP_NAME'];
4649 $priceResultList[$basketCode][
'DISCOUNT_NAME'] =
null;
4650 $priceResultList[$basketCode][
'DISCOUNT_COUPON'] =
null;
4651 $priceResultList[$basketCode][
'DISCOUNT_VALUE'] =
null;
4652 $priceResultList[$basketCode][
'DISCOUNT_LIST'] = array();
4654 $discount = array();
4655 if (!empty($discountList[$priceData[
'PRODUCT_ID']][$basketCode]))
4657 $discount = $discountList[$priceData[
'PRODUCT_ID']][$basketCode];
4660 $priceResultList[$basketCode][
'PRICE_TYPE_ID'] = $priceData[
'RESULT_PRICE'][
'PRICE_TYPE_ID'];
4661 $priceResultList[$basketCode][
'BASE_PRICE'] = $priceData[
'RESULT_PRICE'][
'BASE_PRICE'];
4662 $priceResultList[$basketCode][
'PRICE'] = $priceData[
'RESULT_PRICE'][
'DISCOUNT_PRICE'];
4663 $priceResultList[$basketCode][
'CURRENCY'] = $priceData[
'RESULT_PRICE'][
'CURRENCY'];
4664 $priceResultList[$basketCode][
'DISCOUNT_PRICE'] = $priceData[
'RESULT_PRICE'][
'DISCOUNT'];
4665 if (isset($priceData[
'RESULT_PRICE'][
'PERCENT']))
4667 $priceResultList[$basketCode][
'DISCOUNT_VALUE'] = ($priceData[
'RESULT_PRICE'][
'PERCENT'] > 0
4668 ? $priceData[
'RESULT_PRICE'][
'PERCENT'] .
'%' :
null);
4670 $priceResultList[$basketCode][
'VAT_RATE'] = $priceData[
'RESULT_PRICE'][
'VAT_RATE'];
4671 $priceResultList[$basketCode][
'VAT_INCLUDED'] = $priceData[
'RESULT_PRICE'][
'VAT_INCLUDED'];
4673 if (!empty($discount))
4675 $priceResultList[$basketCode][
'DISCOUNT_LIST'] = $discount;
4678 if (!empty($priceData[
'DISCOUNT']))
4680 $priceResultList[$basketCode][
'DISCOUNT_NAME'] =
'[' .
4681 $priceData[
'DISCOUNT'][
'ID'] .
4683 $priceData[
'DISCOUNT'][
'NAME'];
4684 if (!empty($priceData[
'DISCOUNT'][
'COUPON']))
4686 $priceResultList[$basketCode][
'DISCOUNT_COUPON'] = $priceData[
'DISCOUNT'][
'COUPON'];
4689 if (empty($priceResultList[$basketCode][
'DISCOUNT_LIST']))
4691 $priceResultList[$basketCode][
'DISCOUNT_LIST'] = array($priceData[
'DISCOUNT']);
4696 $resultList = array();
4697 if (!empty($priceResultList))
4699 foreach ($products as $productId => $productData)
4701 if (!empty($products[$productId]))
4705 $quantityList = array();
4707 if (array_key_exists(
'QUANTITY', $productData))
4709 $quantityList = array(
4710 $productData[
'BASKET_CODE'] => $productData[
'QUANTITY'],
4718 foreach($quantityList as $basketCode => $quantity)
4720 $resultList[$basketCode] = $priceResultList[$basketCode];
4737 private static function createProductResult(array $products, array $items, array $priceList, array $productQuantityList): array
4739 $resultList = array();
4740 foreach ($products as $productId => $productData)
4742 $itemCode = $productData[
'ITEM_CODE'];
4743 $basketCode = $productData[
'BASKET_CODE'];
4746 if (isset($productData[
'PRODUCT_DATA'][
'ACTIVE']))
4748 $resultList[
$productId][
'ACTIVE'] = $productData[
'PRODUCT_DATA'][
'ACTIVE'];
4751 $resultList[
$productId][
'ITEM_CODE'] = $itemCode;
4753 QuantityControl::resetAllQuantity($productId);
4754 QuantityControl::setReservedQuantity($productId, $productQuantityList[$basketCode][
'QUANTITY_RESERVED']);
4756 if (!isset($priceList[$basketCode]))
4758 $priceList[$basketCode] = array();
4765 QuantityControl::addQuantity($productId, $productQuantityList[$basketCode][
'QUANTITY']);
4766 QuantityControl::addAvailableQuantity($productId, $productQuantityList[$basketCode][
'AVAILABLE_QUANTITY']);
4768 if (empty($priceList[$basketCode]))
4773 $resultList[
$productId][
'PRICE_LIST'][$basketCode] = array_merge(
4775 'QUANTITY' => $productQuantityList[$basketCode][
'QUANTITY'],
4776 'AVAILABLE_QUANTITY' => $productQuantityList[$basketCode][
'AVAILABLE_QUANTITY'],
4777 "ITEM_CODE" => $itemCode,
4778 "BASKET_CODE" => $basketCode,
4780 $priceList[$basketCode]
4786 $resultList[
$productId][
'QUANTITY'] = $productQuantityList[$basketCode][
'QUANTITY'];
4788 QuantityControl::addQuantity($productId, $productQuantityList[$basketCode][
'QUANTITY']);
4789 QuantityControl::addAvailableQuantity($productId, $productQuantityList[$basketCode][
'AVAILABLE_QUANTITY']);
4790 if (!empty($resultList[$productId]))
4792 if (empty($priceList[$basketCode]))
4812 private static function setCatalogDataToProducts(array $products, array $catalogDataList, array $options = array()): array
4814 $catalogDataEnabled = self::isCatalogDataEnabled($options);
4815 $specialFields = [];
4816 foreach (Catalog\Product\SystemField::getProviderSelectFields() as $index => $value)
4818 $specialFields[] = is_string($index) ? $index : $value;
4822 foreach ($products as $productId => $productData)
4824 if (!isset($catalogDataList[$productId]))
4833 $productData[
'PRODUCT_DATA'][
'ACTIVE'] ===
'Y'
4834 && $row[
'AVAILABLE'] ===
'Y'
4838 'CAN_BUY_ZERO' => $row[
'CAN_BUY_ZERO'],
4839 'QUANTITY_TRACE' => $row[
'QUANTITY_TRACE'],
4840 'CHECK_QUANTITY' => $row[
'CHECK_QUANTITY'],
4841 'QUANTITY_RESERVED' => (
float)$row[
'QUANTITY_RESERVED'],
4842 'CATALOG_XML_ID' => $productData[
'PRODUCT_DATA'][
'CATALOG_XML_ID'],
4843 'PRODUCT_XML_ID' => $productData[
'PRODUCT_DATA'][
'~XML_ID'],
4847 if (!$catalogDataEnabled)
4850 'NAME' => $productData[
'PRODUCT_DATA'][
'~NAME'],
4851 'DETAIL_PAGE_URL' => $productData[
'PRODUCT_DATA'][
'~DETAIL_PAGE_URL'],
4852 'MEASURE_ID' => $row[
'MEASURE'],
4853 'MEASURE_NAME' => $row[
'MEASURE_NAME'],
4854 'MEASURE_CODE' => $row[
'MEASURE_CODE'],
4855 'BARCODE_MULTI' => $row[
'BARCODE_MULTI'],
4856 'WEIGHT' => (float)$row[
'WEIGHT'],
4857 'DIMENSIONS' => serialize(
4859 'WIDTH' => $row[
'WIDTH'],
4860 'HEIGHT' => $row[
'HEIGHT'],
4861 'LENGTH' => $row[
'LENGTH'],
4865 switch ($row[
'TYPE'])
4867 case Catalog\ProductTable::TYPE_SET:
4868 $basketRow[
'TYPE'] = Sale\BasketItem::TYPE_SET;
4870 case Catalog\ProductTable::TYPE_SERVICE:
4871 $basketRow[
'TYPE'] = Sale\BasketItem::TYPE_SERVICE;
4874 $basketRow[
'TYPE'] =
null;
4877 foreach ($specialFields as $index)
4879 $basketRow[$index] = $row[$index];
4883 $result[$productId],
4897 protected static function isReservationEnabled()
4899 return !(Main\Config\Option::get(
"catalog",
"enable_reservation") ==
"N"
4900 && Main\Config\Option::get(
"sale",
"product_reserve_condition") !=
"S"
4901 && !Catalog\Config\State::isUsedInventoryManagement());
4910 public static function createOrderListFromProducts(array $products)
4912 $productOrderList = array();
4913 foreach ($products as $productId => $productData)
4915 if (!empty($productData[
'SHIPMENT_ITEM_LIST']))
4921 foreach ($productData[
'SHIPMENT_ITEM_LIST'] as $shipmentItem)
4923 $shipmentItemCollection = $shipmentItem->getCollection();
4924 if (!$shipmentItemCollection)
4926 throw new Main\ObjectNotFoundException(
'Entity "ShipmentItemCollection" not found');
4929 $shipment = $shipmentItemCollection->getShipment();
4932 throw new Main\ObjectNotFoundException(
'Entity "Shipment" not found');
4936 $shipmentCollection = $shipment->getCollection();
4937 if (!$shipmentCollection)
4939 throw new Main\ObjectNotFoundException(
'Entity "ShipmentCollection" not found');
4942 $order = $shipmentCollection->getOrder();
4945 throw new Main\ObjectNotFoundException(
'Entity "Order" not found');
4948 if (empty($productOrderList[$productId][$order->getId()]))
4950 $productOrderList[
$productId][$order->getId()] = $order;
4956 return $productOrderList;
4964 private static function getProductCatalogInfo($productId): array
4967 if ($productId <= 0)
4972 $product = static::getHitCache(self::CACHE_ELEMENT_SHORT_DATA, $productId);
4973 if (empty($product))
4975 $iterator = Iblock\ElementTable::getList([
4980 'IBLOCK_SECTION_ID',
4982 'filter' => \CIBlockElement::getPublicElementsOrmFilter([
'=ID' => $productId]),
4984 $product = $iterator->fetch();
4987 static::setHitCache(self::CACHE_ELEMENT_SHORT_DATA, $productId, $product);
4991 return (empty($product)
4994 "#PRODUCT_ID#" => $product[
'ID'],
4995 "#PRODUCT_NAME#" => $product[
'NAME'],
5000 private static function getTotalAmountFromQuantityList(array $data): float
5002 return self::getAmountFromSource(
5005 self::AMOUNT_SRC_STORE_QUANTITY_LIST,
5006 self::AMOUNT_SRC_QUANTITY,
5007 self::AMOUNT_SRC_QUANTITY_LIST,
5012 private static function getTotalAmountFromPriceList(array $product,
bool $direction =
true): float
5017 self::AMOUNT_SRC_QUANTITY,
5018 self::AMOUNT_SRC_PRICE_LIST,
5024 self::AMOUNT_SRC_PRICE_LIST,
5025 self::AMOUNT_SRC_QUANTITY,
5029 return self::getAmountFromSource($product, $list);
5032 private static function isCatalogDataEnabled(array $options): bool
5034 return in_array(self::USE_GATALOG_DATA, $options);
5037 private static function fillCatalogXmlId(array $products, array $iblockProductMap): array
5039 foreach ($iblockProductMap as $entityData)
5041 if (empty($entityData[
'PRODUCT_LIST']) || !is_array($entityData[
'PRODUCT_LIST']))
5045 foreach ($entityData[
'PRODUCT_LIST'] as $index)
5047 if (!isset($products[$index]))
5051 $products[$index][
'PRODUCT_DATA'][
'CATALOG_XML_ID'] = $entityData[
'CATALOG_XML_ID'];
5060 private static function fillOfferXmlId(array $products, array $catalogProductDataList): array
5063 foreach ($catalogProductDataList as $entityData)
5065 if ($entityData[
'TYPE'] != Catalog\ProductTable::TYPE_OFFER)
5069 if (strpos($products[$entityData[
'ID']][
'PRODUCT_DATA'][
'~XML_ID'],
'#') !==
false)
5073 $offerList[] = $entityData[
'ID'];
5076 if (!empty($offerList))
5080 $parentList = \CCatalogSku::getProductList($offerList, 0);
5081 foreach ($parentList as $offerId => $offerData)
5083 $parentId = (int)$offerData[
'ID'];
5084 if (!isset($parentMap[$parentId]))
5086 $parentMap[$parentId] = [];
5088 $parentMap[$parentId][] = $offerId;
5089 $parentIdList[$parentId] = $parentId;
5091 unset($offerId, $offerData, $parentList);
5092 if (!empty($parentMap))
5094 sort($parentIdList);
5095 foreach (array_chunk($parentIdList, 500) as $pageIds)
5097 $iterator = Iblock\ElementTable::getList([
5102 'filter' => [
'@ID' => $pageIds],
5104 while ($row = $iterator->fetch())
5106 $parentId = (int)$row[
'ID'];
5107 if (empty($parentMap[$parentId]))
5111 foreach ($parentMap[$parentId] as $index)
5113 $products[$index][
'PRODUCT_DATA'][
'~XML_ID'] = $row[
'XML_ID'] .
'#'
5114 . $products[$index][
'PRODUCT_DATA'][
'~XML_ID']
5118 unset($parentId, $index);
5119 unset($row, $iterator);
5123 unset($parentIdList, $parentMap);
5130 private static function getPriceDataList(array $products, array $config): array
5138 $userGroups = self::getUserGroups($config[
'USER_ID']);
5140 \CCatalogProduct::GetVATDataByIDList(array_keys($products));
5142 if ($config[
'IS_ADMIN_SECTION'])
5144 if ($config[
'USER_ID'] > 0)
5146 \CCatalogDiscountSave::SetDiscountUserID($config[
'USER_ID']);
5150 \CCatalogDiscountSave::Disable();
5154 Price\Calculation::pushConfig();
5155 Price\Calculation::setConfig([
5156 'CURRENCY' => $config[
'CURRENCY'],
5157 'PRECISION' => (
int)Main\
Config\Option::get(
'sale',
'value_precision'),
5158 'RESULT_WITH_VAT' =>
true,
5159 'RESULT_MODE' => Catalog\Product\Price\Calculation::RESULT_MODE_RAW,
5162 $priceDataList = \CCatalogProduct::GetOptimalPriceList(
5167 ($config[
'IS_ADMIN_SECTION'] ? $config[
'SITE_ID'] : false)
5170 if (empty($priceDataList))
5172 $productsQuantityList = $products;
5173 $quantityCorrected =
false;
5175 foreach ($productsQuantityList as $productId => $productData)
5177 $quantityList = array($productData[
'BASKET_CODE'] => $productData[
'QUANTITY']);
5184 if (empty($quantityList))
5189 foreach ($quantityList as $basketCode => $quantity)
5191 $nearestQuantity = \CCatalogProduct::GetNearestQuantityPrice($productId, $quantity, $userGroups);
5192 if (!empty($nearestQuantity))
5200 $productsQuantityList[
$productId][
'QUANTITY'] = $nearestQuantity;
5203 $quantityCorrected =
true;
5208 if ($quantityCorrected)
5210 $priceDataList = \CCatalogProduct::GetOptimalPriceList(
5211 $productsQuantityList,
5215 ($config[
'IS_ADMIN_SECTION'] ? $config[
'SITE_ID'] : false)
5221 Price\Calculation::popConfig();
5223 if ($config[
'IS_ADMIN_SECTION'])
5225 if ($config[
'USER_ID'] > 0)
5227 \CCatalogDiscountSave::ClearDiscountUserID();
5231 \CCatalogDiscountSave::Enable();
5235 if (!empty($priceDataList))
5237 foreach ($priceDataList as $productId => $priceBasketDataList)
5239 foreach ($priceBasketDataList as $basketCode => $priceData)
5241 if ($priceData ===
false)
5246 if (empty($priceData[
'DISCOUNT_LIST']) && !empty($priceData[
'DISCOUNT']) && is_array($priceData[
'DISCOUNT']))
5248 $priceDataList[
$productId][$basketCode][
'DISCOUNT_LIST'] = [$priceData[
'DISCOUNT']];
5251 if (empty($priceData[
'PRICE'][
'CATALOG_GROUP_NAME']))
5253 if (!empty($priceData[
'PRICE'][
'CATALOG_GROUP_ID']))
5255 $priceName = self::getPriceTitle($priceData[
'PRICE'][
'CATALOG_GROUP_ID']);
5256 if ($priceName !==
'')
5258 $priceDataList[
$productId][$basketCode][
'PRICE'][
'CATALOG_GROUP_NAME'] = $priceName;
5267 return $priceDataList;
5270 private static function getDiscountList(array $priceDataList): array
5272 $discountList = array();
5273 if (!empty($priceDataList))
5275 foreach ($priceDataList as $productId => $priceBasketDataList)
5277 foreach ($priceBasketDataList as $basketCode => $priceData)
5279 if ($priceData ===
false)
5284 if (empty($priceData[
'DISCOUNT_LIST']) && !empty($priceData[
'DISCOUNT']) && is_array($priceData[
'DISCOUNT']))
5286 $priceDataList[
$productId][$basketCode][
'DISCOUNT_LIST'] = [$priceData[
'DISCOUNT']];
5289 if (!empty($priceData[
'DISCOUNT_LIST']))
5291 if (!isset($discountList[$productId]))
5295 if (!isset($discountList[$productId][$basketCode]))
5299 foreach ($priceData[
'DISCOUNT_LIST'] as $discountItem)
5301 $discountList[
$productId][$basketCode][] = \CCatalogDiscount::getDiscountDescription($discountItem);
5303 unset($discountItem);
5306 if (empty($priceData[
'PRICE'][
'CATALOG_GROUP_NAME']))
5308 if (!empty($priceData[
'PRICE'][
'CATALOG_GROUP_ID']))
5310 $priceName = self::getPriceTitle($priceData[
'PRICE'][
'CATALOG_GROUP_ID']);
5311 if ($priceName !=
'')
5313 $priceDataList[
$productId][$basketCode][
'PRICE'][
'CATALOG_GROUP_NAME'] = $priceName;
5322 return $discountList;
5325 public static function getDefaultStoreId(): int
5327 $result = parent::getDefaultStoreId();
5328 if (Catalog\
Config\State::isUsedInventoryManagement())
5330 $storeId = Catalog\StoreTable::getDefaultStoreId();
5331 if ($storeId !==
null)
5340 private static function getAmountFromSource(array $product, array $sourceList): float
5342 if (empty($product) || empty($sourceList))
5349 foreach ($sourceList as $source)
5353 case self::AMOUNT_SRC_QUANTITY:
5354 if (array_key_exists($source, $product))
5356 $result = $product[$source];
5360 case self::AMOUNT_SRC_QUANTITY_LIST:
5361 case self::AMOUNT_SRC_RESERVED_LIST:
5363 !empty($product[$source])
5364 && is_array($product[$source])
5367 $result = array_sum($product[$source]);
5371 case self::AMOUNT_SRC_PRICE_LIST:
5373 !empty($product[$source])
5374 && is_array($product[$source])
5377 foreach ($product[$source] as $row)
5379 if (!is_array($row) || !isset($row[
'QUANTITY']))
5383 $result += (float)$row[
'QUANTITY'];
5389 case self::AMOUNT_SRC_STORE_QUANTITY_LIST:
5390 case self::AMOUNT_SRC_STORE_RESERVED_LIST:
5392 !empty($product[$source])
5393 && is_array($product[$source])
5396 switch (self::getQuantityFormat($product[$source]))
5398 case self::QUANTITY_FORMAT_STORE:
5399 $internalResult = self::calculateQuantityFromStores($product[$source]);
5401 case self::QUANTITY_FORMAT_SHIPMENT:
5402 $internalResult = self::calculateQuantityFromShipments($product[$source]);
5405 $internalResult =
null;
5408 if ($internalResult !==
null)
5410 $result += array_sum($internalResult);
5413 unset($internalResult);
5423 return (
float)$result;
5426 private static function getStoreAmountFromQuantityList(array $data): ?array
5428 return self::getStoreAmountFromSource(
5431 self::AMOUNT_SRC_STORE_QUANTITY_LIST,
5432 self::AMOUNT_SRC_QUANTITY_LIST,
5433 self::AMOUNT_SRC_QUANTITY,
5438 private static function getStoreReservedQuantityFromProduct(array $product): ?array
5440 return self::getStoreAmountFromSource(
5443 self::AMOUNT_SRC_STORE_RESERVED_LIST,
5444 self::AMOUNT_SRC_RESERVED_LIST,
5449 private static function getStoreAmountFromPriceList(array $product,
bool $direction =
true): ?array
5454 self::AMOUNT_SRC_QUANTITY,
5455 self::AMOUNT_SRC_PRICE_LIST,
5461 self::AMOUNT_SRC_PRICE_LIST,
5462 self::AMOUNT_SRC_QUANTITY,
5466 return self::getStoreAmountFromSource($product, $list);
5469 private static function getStoreAmountFromSource(array $product, array $sourceList): ?array
5471 if (empty($product) || empty($sourceList))
5478 foreach ($sourceList as $source)
5482 case self::AMOUNT_SRC_STORE_QUANTITY_LIST:
5483 case self::AMOUNT_SRC_STORE_RESERVED_LIST:
5485 !empty($product[$source])
5486 && is_array($product[$source])
5489 switch (self::getQuantityFormat($product[$source]))
5491 case self::QUANTITY_FORMAT_STORE:
5492 $internalResult = self::calculateQuantityFromStores($product[$source]);
5494 case self::QUANTITY_FORMAT_SHIPMENT:
5495 $internalResult = self::calculateQuantityFromShipments($product[$source]);
5498 $internalResult =
null;
5501 if ($internalResult !==
null)
5503 $result = $internalResult;
5506 unset($internalResult);
5509 case self::AMOUNT_SRC_QUANTITY_LIST:
5510 case self::AMOUNT_SRC_RESERVED_LIST:
5520 !empty($product[$source])
5521 && is_array($product[$source])
5524 $result[static::getDefaultStoreId()] = array_sum($product[$source]);
5528 case self::AMOUNT_SRC_QUANTITY:
5529 if (array_key_exists($source, $product))
5531 $result[static::getDefaultStoreId()] = (float)$product[$source];
5542 return (!empty($result) ? $result :
null);
5545 private static function getQuantityFormat(array $list): ?int
5587 $basketRow = reset($list);
5590 || !is_array($basketRow)
5596 $row = reset($basketRow);
5599 return self::QUANTITY_FORMAT_SHIPMENT;
5602 return self::QUANTITY_FORMAT_STORE;
5605 private static function calculateQuantityFromStores(array $list): ?array
5609 foreach ($list as $basketItemStores)
5612 empty($basketItemStores)
5613 || !is_array($basketItemStores)
5618 foreach ($basketItemStores as $storeId => $quantity)
5620 if (!isset($result[$storeId]))
5624 $result[
$storeId] += (float)$quantity;
5627 unset($storeId, $quantity);
5629 unset($basketItemStores);
5631 return ($found ? $result : null);
5634 private static function calculateQuantityFromShipments(array $list): ?array
5638 foreach ($list as $basketItemShipments)
5641 empty($basketItemShipments)
5642 || !is_array($basketItemShipments)
5647 foreach ($basketItemShipments as $basketItemStores)
5649 foreach ($basketItemStores as $storeId => $quantity)
5651 if (!isset($result[$storeId]))
5655 $result[
$storeId] += (float)$quantity;
5661 return ($found ? $result : null);
5664 private static function getStoreQuantityFromQuantityList(array $product): array
5666 return self::getStoreQuantityFromSource(
5669 self::AMOUNT_SRC_STORE_QUANTITY_LIST,
5670 self::AMOUNT_SRC_QUANTITY_LIST,
5675 private static function getStoreQuantityFromSource(array $product, array $sourceList): array
5677 if (empty($product) || empty($sourceList))
5679 return [static::getDefaultStoreId() => 0.0];
5684 foreach ($sourceList as $source)
5688 case self::AMOUNT_SRC_QUANTITY_LIST:
5689 case self::AMOUNT_SRC_RESERVED_LIST:
5691 !empty($product[$source])
5692 && is_array($product[$source])
5696 static::getDefaultStoreId() => (float)array_sum($product[$source]),
5719 case self::AMOUNT_SRC_STORE_QUANTITY_LIST:
5720 case self::AMOUNT_SRC_STORE_RESERVED_LIST:
5722 !empty($product[$source])
5723 && is_array($product[$source])
5726 switch (self::getQuantityFormat($product[$source]))
5728 case self::QUANTITY_FORMAT_STORE:
5729 $internalResult = self::calculateQuantityFromStores($product[$source]);
5731 case self::QUANTITY_FORMAT_SHIPMENT:
5732 $internalResult = self::calculateQuantityFromShipments($product[$source]);
5735 $internalResult =
null;
5738 if ($internalResult !==
null)
5740 $result = $internalResult;
5752 return (!empty($result)
5754 : [static::getDefaultStoreId() => 0.0]
5758 private static function loadCurrentStoreReserve(
int $productId, array $reserve): array
5761 foreach ($reserve as $storeId => $quantity)
5767 'ADD_QUANTITY_RESERVED' => $quantity,
5768 'QUANTITY_RESERVED' => 0.0,
5772 $iterator = Catalog\StoreProductTable::getList([
5776 'QUANTITY_RESERVED',
5779 '=PRODUCT_ID' => $productId,
5780 '@STORE_ID' => array_keys($reserve),
5783 while ($row = $iterator->fetch())
5786 $result[
$storeId][
'ID'] = (int)$row[
'ID'];
5787 $result[
$storeId][
'QUANTITY_RESERVED'] = (float)$row[
'QUANTITY_RESERVED'];
5789 unset($row, $iterator);
5794 private static function loadCurrentProductStores(array $list): array
5796 Main\Type\Collection::normalizeArrayValuesByInt($list,
true);
5803 foreach (array_chunk($list, 500) as $pageIds)
5805 $iterator = Catalog\StoreProductTable::getList([
5811 'QUANTITY_RESERVED',
5814 '@PRODUCT_ID' => $pageIds,
5815 '=STORE.ACTIVE' =>
'Y',
5818 'PRODUCT_ID' =>
'ASC',
5819 'STORE_ID' =>
'ASC',
5822 while ($row = $iterator->fetch())
5824 $row[
'ID'] = (int)$row[
'ID'];
5825 $row[
'PRODUCT_ID'] = (int)$row[
'PRODUCT_ID'];
5826 $row[
'STORE_ID'] = (int)$row[
'STORE_ID'];
5827 $row[
'AMOUNT'] = (float)$row[
'AMOUNT'];
5828 $row[
'QUANTITY_RESERVED'] = (float)$row[
'QUANTITY_RESERVED'];
5832 if (!isset($result[$productId]))
5838 unset($productId, $storeId);
5839 unset($row, $iterator);
5846 private static function convertErrors(Main\Entity\Result $result): void
5848 global $APPLICATION;
5851 foreach ($result->getErrorMessages() as $errorText)
5854 'text' => $errorText,
5859 if (!empty($oldMessages))
5861 $error = new \CAdminException($oldMessages);
5862 $APPLICATION->ThrowException($error);
5865 unset($oldMessages);
static getMessage($code, $replace=null, $language=null)
const STORE_QUANTITY_LIST
const FLAT_AVAILABLE_QUANTITY_LIST
const STORE_AVAILABLE_QUANTITY_LIST
const FLAT_RESERVED_QUANTITY_LIST
const SUMMMARY_PRODUCT_LIST
const STORE_RESERVED_QUANTITY_LIST