19 private static $statisticIncluded =
null;
20 private static $saleIncluded =
null;
38 if (empty($product[
'PRODUCT_ID']))
40 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT')));
43 $productId = (int)$product[
'PRODUCT_ID'];
50 $product[
'MODULE'] =
'catalog';
51 $product[
'PRODUCT_PROVIDER_CLASS'] = self::getDefaultProviderName();
53 if (!empty($basketFields))
54 $product = array_merge($product, $basketFields);
56 if (self::$saleIncluded ===
null)
57 self::$saleIncluded = Loader::includeModule(
'sale');
59 if (!self::$saleIncluded)
61 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_SALE')));
66 if (!empty($basketFields[
'LID']))
76 $basketClass = $registry->getBasketClassName();
88 $saveResult = $basket->save();
89 if ($saveResult->isSuccess())
91 $resultData =
$result->getData();
92 if (!empty($resultData[
'BASKET_ITEM']))
94 $item = $resultData[
'BASKET_ITEM'];
97 if (self::$statisticIncluded ===
null)
100 if (self::$statisticIncluded)
102 \CStatistic::Set_Event(
103 'sale2basket',
'catalog', $item->getField(
'DETAIL_PAGE_URL')
107 'ID' => $item->getId()
112 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_UNKNOWN')));
118 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_UNKNOWN')));
124 $result->addErrors($saveResult->getErrors());
169 $options[
'CHECK_PERMISSIONS'] =
'Y';
192 if (!isset(
$options[
'CHECK_CRAWLERS']) ||
$options[
'CHECK_CRAWLERS'] ==
'Y')
194 $validBuyer = static::checkCurrentUser();
195 if (!$validBuyer->isSuccess())
197 $result->addErrors($validBuyer->getErrors());
203 if (empty(
$fields[
'PRODUCT_ID']))
205 $result->addError(
new Main\Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT')));
208 $productId = (int)
$fields[
'PRODUCT_ID'];
211 $result->addError(
new Main\Error(Main\Localization\Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT')));
216 if (empty(
$fields[
'QUANTITY']))
218 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_EMPTY_QUANTITY')));
221 $quantity = (float)
$fields[
'QUANTITY'];
224 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_EMPTY_QUANTITY')));
228 if (self::$saleIncluded ===
null)
229 self::$saleIncluded = Loader::includeModule(
'sale');
231 if (!self::$saleIncluded)
233 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_SALE')));
241 if (array_key_exists(
'MODULE',
$fields))
248 $module ===
'catalog'
249 && !isset(
$fields[
'PRODUCT_PROVIDER_CLASS'])
252 $fields[
'PRODUCT_PROVIDER_CLASS'] = self::getDefaultProviderName();
256 'PRODUCT_PROVIDER_CLASS' =>
true,
257 'CALLBACK_FUNC' =>
true,
258 'PAY_CALLBACK_FUNC' =>
true,
261 $presets = array_merge($presets, array_intersect_key(
$fields, $transferFields));
263 unset($transferFields);
266 if (array_key_exists(
'PROPS',
$fields))
269 if ($module ==
'catalog')
271 $elementFilter =
array(
274 'ACTIVE_DATE' =>
'Y',
275 'CHECK_PERMISSIONS' =>
'N'
278 if (!empty(
$options[
'CHECK_PERMISSIONS']) &&
$options[
'CHECK_PERMISSIONS'] ==
"Y")
280 $elementFilter[
'CHECK_PERMISSIONS'] =
'Y';
281 $elementFilter[
'MIN_PERMISSION'] =
'R';
283 $elementFilter[
'PERMISSIONS_BY'] =
$context[
'USER_ID'];
299 if (!($elementFields =
$iterator->GetNext()))
301 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_IBLOCK_ELEMENT')));
307 'ID',
'TYPE',
'AVAILABLE',
'CAN_BUY_ZERO',
'QUANTITY_TRACE',
'QUANTITY',
308 'WEIGHT',
'WIDTH',
'HEIGHT',
'LENGTH',
309 'MEASURE',
'BARCODE_MULTI'
311 'filter' =>
array(
'=ID' => $productId)
317 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT')));
323 && (
string)Main\Config\Option::get(
'catalog',
'show_catalog_tab_with_offers') !=
'Y'
326 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_CANNOT_ADD_SKU')));
329 if (
$productFields[
'AVAILABLE'] != Catalog\ProductTable::STATUS_YES)
331 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_PRODUCT_RUN_OUT')));
336 $skuInfo = \CCatalogSku::GetProductInfo($productId, $elementFields[
'IBLOCK_ID']);
339 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_PRODUCT_BAD_TYPE')));
344 $parentIterator = \CIBlockElement::GetList(
347 'ID' => $skuInfo[
'ID'],
348 'IBLOCK_ID' => $skuInfo[
'IBLOCK_ID'],
350 'ACTIVE_DATE' =>
'Y',
351 'CHECK_PERMISSIONS' =>
'N'
355 array(
'ID',
'IBLOCK_ID',
'XML_ID')
357 $parent = $parentIterator->Fetch();
360 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT')));
363 elseif (mb_strpos($elementFields[
"~XML_ID"],
'#') ===
false)
365 $elementFields[
"~XML_ID"] = $parent[
'XML_ID'].
'#'.$elementFields[
"~XML_ID"];
367 unset($parent, $parentIterator);
376 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT_SET')));
379 $set = current($allSets);
382 foreach ($set[
'ITEMS'] as $item)
384 if ($item[
'ITEM_ID'] != $item[
'OWNER_ID'])
385 $itemIds[$item[
'ITEM_ID']] = $item[
'ITEM_ID'];
389 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT_SET')));
396 'ACTIVE_DATE' =>
'Y',
397 'CHECK_PERMISSIONS' =>
'N'
399 if (!empty(
$options[
'CHECK_PERMISSIONS']) &&
$options[
'CHECK_PERMISSIONS'] ==
"Y")
401 $setFilter[
'CHECK_PERMISSIONS'] =
'Y';
402 $setFilter[
'MIN_PERMISSION'] =
'R';
404 $setFilter[
'PERMISSIONS_BY'] =
$context[
'USER_ID'];
412 array(
'ID',
'IBLOCK_ID')
416 if (isset($itemIds[$row[
'ID']]))
417 unset($itemIds[$row[
'ID']]);
420 if (!empty($itemIds))
422 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_NO_PRODUCT_SET_ITEMS')));
427 $propertyIndex = self::getPropertyIndex(
'CATALOG.XML_ID', $propertyList);
430 $iBlockXmlID = (string)\CIBlock::GetArrayByID($elementFields[
'IBLOCK_ID'],
'XML_ID');
431 if ($iBlockXmlID !==
'')
433 $fields[
'CATALOG_XML_ID'] = $iBlockXmlID;
434 $propertyData =
array(
435 'NAME' =>
'Catalog XML_ID',
436 'CODE' =>
'CATALOG.XML_ID',
437 'VALUE' => $iBlockXmlID
442 $propertyList[] = $propertyData;
443 unset($propertyData);
448 $propertyIndex = self::getPropertyIndex(
'PRODUCT.XML_ID', $propertyList);
451 $fields[
'PRODUCT_XML_ID'] = $elementFields[
'~XML_ID'];
452 $propertyData =
array(
453 'NAME' =>
'Product XML_ID',
454 'CODE' =>
'PRODUCT.XML_ID',
455 'VALUE' => $elementFields[
'~XML_ID']
460 $propertyList[] = $propertyData;
461 unset($propertyData);
471 $measure = \CCatalogMeasure::getDefaultMeasure(
true,
true);
483 [
'ID',
'SYMBOL_RUS',
'CODE']
487 if (!empty($measure))
495 if (isset(
$options[
'FILL_PRODUCT_PROPERTIES']) &&
$options[
'FILL_PRODUCT_PROPERTIES'] ===
'Y')
499 self::fillOfferProperties($propertyList, $productId, $elementFields[
'IBLOCK_ID']);
506 'DETAIL_PAGE_URL' => $elementFields[
'~DETAIL_PAGE_URL'],
522 if (static::isCompatibilityEventAvailable())
524 $eventFields = array_merge($presets,
$fields);
525 $eventFields[
'MODULE'] = $module;
526 $eventFields[
'PROPS'] = $propertyList;
528 $eventResult = static::runCompatibilityEvent($eventFields);
529 if ($eventResult ===
false)
534 foreach ($eventResult as
$key => $value)
536 if (isset($presets[
$key]))
538 if ($presets[
$key] !== $value)
550 $propertyList = $eventResult[
'PROPS'];
558 $basketItem = $basket->getExistsItem($module, $productId, $propertyList);
563 $fields[
'QUANTITY'] = $basketItem->isDelay() ? $quantity : $basketItem->getQuantity() + $quantity;
567 $fields[
'QUANTITY'] = $quantity;
569 $basketCode = !empty(
$fields[
'BASKET_CODE']) ?
$fields[
'BASKET_CODE'] :
null;
570 $basketItem = $basket->createItem($module, $productId, $basketCode);
575 throw new Main\ObjectNotFoundException(
'BasketItem');
579 $propertyCollection = $basketItem->getPropertyCollection();
580 if ($propertyCollection)
582 $propertyCollection->redefine($propertyList);
585 $r = $basketItem->setFields($presets);
586 if (!$r->isSuccess())
588 $result->addErrors($r->getErrors());
593 if(!empty($elementFields[
'~NAME']))
595 $basketItem->setField(
'NAME', $elementFields[
'~NAME']);
598 $r = $basketItem->setField(
'QUANTITY',
$fields[
'QUANTITY']);
599 if (!$r->isSuccess())
601 $result->addErrors($r->getErrors());
606 $settableFields = array_fill_keys($basketItem::getSettableFields(),
true);
607 $basketFields = array_intersect_key(
$fields, $settableFields);
609 if (!empty($basketFields))
611 $r = $basketItem->setFields($basketFields);
612 if (!$r->isSuccess())
614 $result->addErrors($r->getErrors());
619 $result->setData([
'BASKET_ITEM' => $basketItem]);
627 private static function isCompatibilityEventAvailable()
629 return Main\Config\Option::get(
'sale',
'expiration_processing_events',
'N') ===
'Y';
636 private static function runCompatibilityEvent(
array $fields)
653 private static function fillOfferProperties(
array &$propertyList, $id,
$iblockId)
655 static $properties = [];
657 $skuInfo = \CCatalogSku::GetInfoByOfferIBlock(
$iblockId);
660 $skuPropertyId = $skuInfo[
'SKU_PROPERTY_ID'];
661 $parentIblockId = $skuInfo[
'PRODUCT_IBLOCK_ID'];
667 $iterator = Iblock\PropertyTable::getList([
675 '@PROPERTY_TYPE' => [
688 $row[
'ID'] = (int)$row[
'ID'];
689 if ($row[
'ID'] == $skuPropertyId)
691 $properties[
$iblockId][] = $row[
'CODE'] ?? $row[
'ID'];
698 $offerProperties = \CIBlockPriceTools::GetOfferProperties(
703 unset($parentIblockId, $skuPropertyId);
705 if (empty($offerProperties))
709 if (!empty($propertyList))
711 foreach ($propertyList as $row)
713 if (!isset($row[
'CODE']))
715 $index = (string)$row[
'CODE'];
718 $codeMap[$index] =
true;
722 foreach ($offerProperties as $row)
724 $index = (string)$row[
'CODE'];
725 if (isset($codeMap[$index]))
727 $codeMap[$index] =
true;
728 $propertyList[] = $row;
730 unset($index, $row, $codeMap, $offerProperties);
740 private static function getPropertyIndex(
$code,
array $propertyList =
array())
743 if (empty($propertyList))
746 foreach ($propertyList as $index => $propertyData)
748 if (!empty($propertyData[
'CODE']) &&
$code == $propertyData[
'CODE'])
754 unset($index, $propertyData);
764 return "\Bitrix\Catalog\Product\CatalogProvider";
774 $result = static::checkCurrentUser();
784 private static function checkCurrentUser()
788 if (self::$statisticIncluded ===
null)
791 if (!self::$statisticIncluded)
794 if (isset($_SESSION[
'SESS_SEARCHER_ID']) && (
int)$_SESSION[
'SESS_SEARCHER_ID'] > 0)
795 $result->addError(
new Main\
Error(Loc::getMessage(
'BX_CATALOG_PRODUCT_BASKET_ERR_SEARCHER')));
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)