Пример #1
0
 /**
  * <p>Метод добавляет товар в корзину, если его ещё нет, и обновляет параметры товара с увеличением количества, если он уже находится в корзине. В массиве <b>arFields</b> перечисляются все параметры товара, которые нужны для работы модуля Интернет-магазина (т.е. этот модуль не зависит от других модулей и работает полностью самостоятельно). Метод динамичный.</p> <p>Интернет-магазин не зависит от других модулей, поэтому товары в корзину модуля продаж могут добавляться из любого места (например, из торгового каталога или со статической страницы). Для некоторых модулей существуют функции - оболочки, облегчающие добавление товара в корзину (например, для модуля <b>catalog</b> существуют функции <b>Add2Basket</b> и <b>Add2BasketByProductID</b>). </p>
  *
  *
  * @param array $arFields  Ассоциативный массив параметров элемента корзины, содержащий
  * следующие ключи: <ul> <li> <b>PRODUCT_ID</b> - уникальный в рамках модуля код
  * товара (обязательное поле);</li> <li> <b>PRODUCT_PRICE_ID</b> - ID (идентификатор)
  * конкретного ценового предложения товара, пришедшего в корзину.
  * Может быть использован в классе <a
  * href="http://dev.1c-bitrix.ru/api_help/catalog/classes/cprice/index.php">CPrice</a> модуля Catalog для
  * получения детальной информации о цене.</li> <li> <b> PRICE</b> - стоимость
  * единицы товара (обязательное поле);</li> <li> <b>CURRENCY</b> - валюта
  * стоимости единицы товара (обязательное поле), если валюта
  * отличается от базовой валюты для данного сайта, то стоимость
  * будет автоматически сконвертирована по текущему курсу;</li> <li>
  * <b>WEIGHT</b> - вес единицы товара;</li> <li> <b>QUANTITY</b> - количество единиц
  * товара;</li> <li> <b>LID</b> - сайт, на котором сделана покупка
  * (обязательное поле);</li> <li> <b>DELAY</b> - флаг "товар отложен" (Y/N);</li> <li>
  * <b>CAN_BUY</b> - флаг "товар можно купить" (Y/N) - может устанавливаться
  * автоматически про наличии функции обратного вызова для
  * поддержки актуальности корзины;</li> <li> <b>NAME</b> - название товара
  * (обязательное поле);</li> <li> <b>PRODUCT_XML_ID</b> - внешний код товара
  * (необходим при обмене заказами с 1С);</li> <li> <b>CATALOG_XML_ID</b> - внешний
  * код каталога (необходим при обмене заказами с 1С);</li> <li> <b>ORDER_ID</b> -
  * идентификатор заказа. Ключ будет пустым, если товар еще не
  * добавлен в заказ;</li> <li> <b>CALLBACK_FUNC<font color="#FF0000">*</font></b> - название
  * функции обратного вызова для поддержки актуальности корзины
  * (описание ниже);</li> <li> <b>MODULE</b> - модуль, добавляющий товар в
  * корзину;</li> <li> <b>NOTES</b> - особые заметки, например, тип цены;</li> <li>
  * <b>ORDER_CALLBACK_FUNC<font color="#FF0000">*</font></b> - название функции обратного
  * вызова для оформления заказа (описание ниже);</li> <li> <b>DETAIL_PAGE_URL</b> -
  * ссылка на страницу детального просмотра товара;</li> <li>
  * <b>CANCEL_CALLBACK_FUNC<font color="#FF0000">*</font></b> - название функции обратного
  * вызова для отмены заказа (описание ниже);</li> <li> <b>PAY_CALLBACK_FUNC<font
  * color="#FF0000">*</font></b> - название функции обратного вызова, которая
  * вызывается при установке флага "Доставка разрешена" заказа;</li> <li>
  * <b>FUSER_ID</b> - идентификатор пользователя интернет-магазина,
  * необязательный параметр, по умолчанию CSaleBasket::GetBasketUserID() (текущий
  * пользователь);</li> <li> <b>DISCOUNT_PRICE</b> - величина скидки;</li> <li>
  * <b>DISCOUNT_NAME</b> - название скидки;</li> <li> <b>DISCOUNT_VALUE</b> - размер скидки (в
  * процентах);</li> <li> <b>DISCOUNT_COUPON</b> - купон скидки;</li> <li> <b>PROPS</b> - массив
  * свойств товара, который сохраняется в корзине. Каждый элемент
  * этого массива является массивом следующего формата: <pre
  * class="syntax"><code>array("NAME" =&gt; "Название свойства", "CODE" =&gt; "Код свойства",
  * "VALUE" =&gt; "Значение свойства", "SORT" =&gt; "Индекс сортировки")</code></pre> </li>
  * <li> <b>PRODUCT_PROVIDER_CLASS<font color="#0000FF">**</font></b> - содержит имя класса,
  * реализующего интерфейс <b> IBXSaleProductProvider</b>. Торговый каталог
  * записывает в это поле имя класса <b>CCatalogProductProvider</b>. Если поле
  * пусто, то возникает попытка использовать старые поля:<b>CALLBACK_FUNC</b>,
  * <b>ORDER_CALLBACK_FUNC</b>, <b>CANCEL_CALLBACK_FUNC</b> и <b>PAY_CALLBACK_FUNC</b>.</li> </ul>
  *
  * @return int <p>Метод возвращает код элемента корзины, в который попал данный
  * товар.</p> <a name="examples"></a>
  *
  * <h4>Example</h4> 
  * <pre>
  * &lt;?<br>if (CModule::IncludeModule("sale"))<br>{<br>  $arFields = array(<br>    "PRODUCT_ID" =&gt; 51,<br>    "PRODUCT_PRICE_ID" =&gt; 0,<br>    "PRICE" =&gt; 138.54,<br>    "CURRENCY" =&gt; "RUB",<br>    "WEIGHT" =&gt; 530,<br>    "QUANTITY" =&gt; 1,<br>    "LID" =&gt; LANG,<br>    "DELAY" =&gt; "N",<br>    "CAN_BUY" =&gt; "Y",<br>    "NAME" =&gt; "Чемодан кожаный",<br>    "CALLBACK_FUNC" =&gt; "MyBasketCallback",<br>    "MODULE" =&gt; "my_module",<br>    "NOTES" =&gt; "",<br>    "ORDER_CALLBACK_FUNC" =&gt; "MyBasketOrderCallback",<br>    "DETAIL_PAGE_URL" =&gt; "/".LANG."/detail.php?ID=51"<br>  );<br><br>  $arProps = array();<br><br>  $arProps[] = array(<br>    "NAME" =&gt; "Цвет",<br>    "CODE" =&gt; "color",<br>    "VALUE" =&gt; "черный"<br>  );<br><br>  $arProps[] = array(<br>    "NAME" =&gt; "Размер",<br>    "VALUE" =&gt; "1.5 x 2.5"<br>  );<br><br>  $arFields["PROPS"] = $arProps;<br><br>  CSaleBasket::Add($arFields);<br>}<br>?&gt;<br>
  * 
  * 
  * 
  * //пример на проверку создания покупателя
  * 
  * $userId=XXX;//id пользователя
  * //получаем FUSER_ID, если покупатель для данного пользователя существует
  * $FUSER_ID=CSaleUser::GetList(array('USER_ID' =&gt; $userId));
  * //если покупателя нет - создаем его
  * if(!$FUSER_ID['ID'])                  
  *        $FUSER_ID['ID']=CSaleUser::_Add(array("USER_ID" =&gt; $userId)); //обратите внимание на нижнее подчеркивание перед Add
  * //если не получается создать покупателя - то тут уж ничего не поделаешь
  * if(!$FUSER_ID['ID']){         
  *  echo "Error while creating SaleUser";      
  *  die();      
  * }
  * $FUSER_ID=$FUSER_ID['ID'];
  * //теперь переменную $FUSER_ID можно использовать для добавления товаров в корзину пользователя с $userId.
  * 
  * 
  * Смотрите также:
  * 
  * <li><a href="/api_help/catalog/interface.php">Взаимодействие торгового каталога и магазина</a></li>
  * </pre>
  *
  *
  * @static
  * @link http://dev.1c-bitrix.ru/api_help/sale/classes/csalebasket/csalebasket__add.php
  * @author Bitrix
  */
 public static function Add($arFields)
 {
     global $DB, $APPLICATION;
     if (isset($arFields["ID"])) {
         unset($arFields["ID"]);
     }
     $isOrderConverted = \Bitrix\Main\Config\Option::get("main", "~sale_converted_15", 'N');
     CSaleBasket::Init();
     if (!CSaleBasket::CheckFields("ADD", $arFields)) {
         return false;
     }
     if (!array_key_exists('IGNORE_CALLBACK_FUNC', $arFields) || 'Y' != $arFields['IGNORE_CALLBACK_FUNC']) {
         if (array_key_exists("CALLBACK_FUNC", $arFields) && !empty($arFields["CALLBACK_FUNC"]) || array_key_exists("PRODUCT_PROVIDER_CLASS", $arFields) && !empty($arFields["PRODUCT_PROVIDER_CLASS"])) {
             /** @var $productProvider IBXSaleProductProvider */
             if ($productProvider = CSaleBasket::GetProductProvider(array("MODULE" => $arFields["MODULE"], "PRODUCT_PROVIDER_CLASS" => $arFields["PRODUCT_PROVIDER_CLASS"]))) {
                 $providerParams = array("PRODUCT_ID" => $arFields["PRODUCT_ID"], "QUANTITY" => $arFields["QUANTITY"], "RENEWAL" => $arFields["RENEWAL"], "USER_ID" => isset($arFields["USER_ID"]) ? $arFields["USER_ID"] : 0, "SITE_ID" => isset($arFields["LID"]) ? $arFields["LID"] : false);
                 if (isset($arFields['NOTES'])) {
                     $providerParams['NOTES'] = $arFields['NOTES'];
                 }
                 if (!$productProvider::GetProductData($providerParams)) {
                     return false;
                 }
             } else {
                 if (!CSaleBasket::ExecuteCallbackFunction($arFields["CALLBACK_FUNC"], $arFields["MODULE"], $arFields["PRODUCT_ID"], $arFields["QUANTITY"], $arFields["RENEWAL"], $arFields["USER_ID"], $arFields["LID"])) {
                     return false;
                 }
             }
         }
     }
     if ($isOrderConverted != "Y") {
         foreach (GetModuleEvents("sale", "OnBeforeBasketAdd", true) as $arEvent) {
             if (ExecuteModuleEventEx($arEvent, array(&$arFields)) === false) {
                 return false;
             }
         }
     }
     $bFound = false;
     $bEqAr = false;
     //TODO: is order converted?
     if ($isOrderConverted == "Y") {
         /** @var \Bitrix\Sale\BasketItem $basketItem */
         if (!($basketItem = \Bitrix\Sale\Compatible\BasketCompatibility::add($arFields))) {
             $APPLICATION->ThrowException(Localization\Loc::getMessage('BT_MOD_SALE_BASKET_ERR_ID_ABSENT'), "BASKET_ITEM");
             return false;
         }
         $ID = $basketItem->getId();
         $arFields['QUANTITY'] = $basketItem->getQuantity();
     } else {
         $boolProps = !empty($arFields["PROPS"]) && is_array($arFields["PROPS"]);
         // check if this item is already in the basket
         $arDuplicateFilter = array("FUSER_ID" => $arFields["FUSER_ID"], "PRODUCT_ID" => $arFields["PRODUCT_ID"], "LID" => $arFields["LID"], "ORDER_ID" => "NULL");
         if (!(isset($arFields["TYPE"]) && $arFields["TYPE"] == CSaleBasket::TYPE_SET)) {
             if (isset($arFields["SET_PARENT_ID"])) {
                 $arDuplicateFilter["SET_PARENT_ID"] = $arFields["SET_PARENT_ID"];
             } else {
                 $arDuplicateFilter["SET_PARENT_ID"] = "NULL";
             }
         }
         $db_res = CSaleBasket::GetList(array(), $arDuplicateFilter, false, false, array("ID", "QUANTITY"));
         while ($res = $db_res->Fetch()) {
             if (!$bEqAr) {
                 $arPropsCur = array();
                 $arPropsOld = array();
                 if ($boolProps) {
                     foreach ($arFields["PROPS"] as &$arProp) {
                         if (array_key_exists('VALUE', $arProp) && '' != $arProp["VALUE"]) {
                             $propID = '';
                             if (array_key_exists('CODE', $arProp) && '' != $arProp["CODE"]) {
                                 $propID = $arProp["CODE"];
                             } elseif (array_key_exists('NAME', $arProp) && '' != $arProp["NAME"]) {
                                 $propID = $arProp["NAME"];
                             }
                             if ('' == $propID) {
                                 continue;
                             }
                             $arPropsCur[$propID] = $arProp["VALUE"];
                         }
                     }
                     if (isset($arProp)) {
                         unset($arProp);
                     }
                 }
                 $dbProp = CSaleBasket::GetPropsList(array(), array("BASKET_ID" => $res["ID"]), false, false, array('NAME', 'VALUE', 'CODE'));
                 while ($arProp = $dbProp->Fetch()) {
                     if ('' != $arProp["VALUE"]) {
                         $propID = '';
                         if ('' != $arProp["CODE"]) {
                             $propID = $arProp["CODE"];
                         } elseif ('' != $arProp["NAME"]) {
                             $propID = $arProp["NAME"];
                         }
                         if ('' == $propID) {
                             continue;
                         }
                         $arPropsOld[$propID] = $arProp["VALUE"];
                     }
                 }
                 $bEqAr = false;
                 if (count($arPropsCur) == count($arPropsOld)) {
                     $bEqAr = true;
                     foreach ($arPropsCur as $key => $val) {
                         if (!array_key_exists($key, $arPropsOld) || $arPropsOld[$key] != $val) {
                             $bEqAr = false;
                             break;
                         }
                     }
                 }
                 if ($bEqAr) {
                     $ID = $res["ID"];
                     $arFields["QUANTITY"] += $res["QUANTITY"];
                     CSaleBasket::Update($ID, $arFields);
                     $bFound = true;
                     continue;
                 }
             }
         }
     }
     if (!$bFound) {
         //TODO: is order converted?
         if ($isOrderConverted != "Y") {
             $arInsert = $DB->PrepareInsert("b_sale_basket", $arFields);
             $strSql = "INSERT INTO b_sale_basket(" . $arInsert[0] . ", DATE_INSERT, DATE_UPDATE) VALUES(" . $arInsert[1] . ", " . $DB->GetNowFunction() . ", " . $DB->GetNowFunction() . ")";
             $DB->Query($strSql, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
             $ID = intval($DB->LastID());
             $boolOrder = false;
             if (isset($arFields['ORDER_ID'])) {
                 $boolOrder = 0 < (int) $arFields['ORDER_ID'];
             }
             if (!$boolOrder && !CSaleBasketHelper::isSetItem($arFields)) {
                 $siteID = isset($arFields["LID"]) ? $arFields["LID"] : SITE_ID;
                 $_SESSION["SALE_BASKET_NUM_PRODUCTS"][$siteID]++;
             }
             if ($boolProps) {
                 foreach ($arFields["PROPS"] as &$prop) {
                     if ('' != $prop["NAME"]) {
                         $arInsert = $DB->PrepareInsert("b_sale_basket_props", $prop);
                         $strSql = "INSERT INTO b_sale_basket_props(BASKET_ID, " . $arInsert[0] . ") VALUES(" . $ID . ", " . $arInsert[1] . ")";
                         $DB->Query($strSql, false, "File: " . __FILE__ . "<br>Line: " . __LINE__);
                     }
                 }
                 if (isset($prop)) {
                     unset($prop);
                 }
             }
             // if item is set parent
             if (isset($arFields["TYPE"]) && $arFields["TYPE"] == CSaleBasket::TYPE_SET) {
                 CSaleBasket::Update($ID, array("SET_PARENT_ID" => $ID));
                 if (!isset($arFields["MANUAL_SET_ITEMS_INSERTION"])) {
                     /** @var $productProvider IBXSaleProductProvider */
                     if ($productProvider = CSaleBasket::GetProductProvider($arFields)) {
                         if (method_exists($productProvider, "GetSetItems")) {
                             $arSets = $productProvider::GetSetItems($arFields["PRODUCT_ID"], CSaleBasket::TYPE_SET, array('BASKET_ID' => $ID));
                             if (is_array($arSets)) {
                                 foreach ($arSets as $arSetData) {
                                     foreach ($arSetData["ITEMS"] as $setItem) {
                                         $setItem["SET_PARENT_ID"] = $ID;
                                         $setItem["LID"] = $arFields["LID"];
                                         $setItem["QUANTITY"] = $setItem["QUANTITY"] * $arFields["QUANTITY"];
                                         $setItem['FUSER_ID'] = $arFields['FUSER_ID'];
                                         CSaleBasket::Add($setItem);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
         if ($boolOrder) {
             CSaleOrderChange::AddRecord($arFields["ORDER_ID"], "BASKET_ADDED", array("PRODUCT_ID" => $arFields["PRODUCT_ID"], "NAME" => $arFields["NAME"], "QUANTITY" => $arFields["QUANTITY"]));
         }
     }
     if ($isOrderConverted != "Y") {
         foreach (GetModuleEvents("sale", "OnBasketAdd", true) as $arEvent) {
             ExecuteModuleEventEx($arEvent, array($ID, $arFields));
         }
     }
     return $ID;
 }