Добавление товаров в корзину в современной редакции Битрикса. Конспект вебинара
Часть 1 / Часть 2 / Часть 3
Вебинар:
¶Добавление в корзину
Процедура, которую проводит система при добавлении товара в корзину через публичную часть:
- проверка существования товара, его доступности, формирование данных для элемента корзины
- создание элемента корзины
- запрос у провайдера цен стоимости товара (можно добавлять без указания цены, провайдер сам вычислит актуальную), запрос доступного количества, учёт доступности товара;
- запись в базу
Было: $basketId = Add2BasketByProductID(27, 3);
Стало (! читать про особенность кода ниже):
use Bitrix\Catalog\Product\Basket;
/**
 * Поля, которые могут быть установлены
 * нами при добавлении товара в корзину:
 *
 * "BARCODE_MULTI"              "BASE_PRICE"
 * "CALLBACK_FUNC"              "CAN_BUY"
 * "CANCEL_CALLBACK_FUNC"       "CATALOG_XML_ID"
 * "CURRENCY"                   "CUSTOM_PRICE"
 * "DELAY"                      "DETAIL_PAGE_URL"
 * "DIMENSIONS"                 "DISCOUNT_COUPON"
 * "DISCOUNT_NAME"              "DISCOUNT_PRICE"
 * "DISCOUNT_VALUE"             "LID"
 * "MARKING_CODE_GROUP"         "MEASURE_CODE"
 * "MEASURE_NAME"               "NAME"   "NOTES"
 * "ORDER_CALLBACK_FUNC"        "PAY_CALLBACK_FUNC"
 * "PRICE_TYPE_ID"              "PRICE"
 * "PRODUCT_ID"                 "PRODUCT_PRICE_ID"
 * "PRODUCT_PROVIDER_CLASS"     "PRODUCT_XML_ID"
 * "QUANTITY"                   "RECOMMENDATION"
 * "SET_PARENT_ID"              "SORT"
 * "SUBSCRIBE"                  "TYPE"
 * "VAT_INCLUDED"               "VAT_RATE"
 * "WEIGHT"                     "XML_ID"
 */
$product = [
    'PRODUCT_ID' => $productId,
    'QUANTITY' => $quantity,
    'CUSTOM_PRICE' => 777,
    'PROPS' => [
        [
            "NAME" => 'Материал',
            "CODE" => 'matherial',
            "VALUE" => 'Натуральная кожа',
            "SORT" => 100,
        ],
        [
            "NAME" => 'Цвет заклёпок',
            "CODE" => 'clips_color',
            "VALUE" => 'Серебро',
            "SORT" => 200,
        ],
    ]
];
// Только если мы хотим
// заменить на отличающиеся
// от того, что есть в каталоге
$product += [
    'WEIGHT' => 700,
    'DIMENSIONS' => [
        'WIDTH' => 50,
        'LENGTH' => 100,
        'HEIGHT' => 1000,
    ],
];
// По сути мержатся поверх $product.
// Единственный ключ, обрабатываемый отдельно — SITE_ID
// При установке этого ключа
// контекст переключается на указанный код сайта
// ... вместо константы SITE_ID
$basketFields = [
    // Этот ключ переопределит ключ из $product
    'QUANTITY' => $quantity * 2,
    // Контекст будет переключен на другой сайт
    'SITE_ID' => 's2'
];
$options = [
    // Если такой товар уже есть в корзине,
    // не объединять добавляемый с ним
    // ...а создавать рядом новую запись в корзине
    'USE_MERGE' => 'N',
    // Если в корзину добавляется
    // товарное предложение:
    //      Catalog\ProductTable::TYPE_OFFER
    // свойства товара
    // будут заполнены автоматически
    'FILL_PRODUCT_PROPERTIES' => 'Y',
];
Basket::addProduct(
    $product, $basketFields, $options
);
Свойства в объекте корзины:

(!) Особенность в том, что каждый вызов кода выше будет поднимать объект корзины, добавлять в неё новый товар и сохранять в базу данных. Подходит для добавления например через аякс.
¶Комплексное добавление
Отделяем поднятие и фиксацию корзины от добавления в неё элементов.
use \Bitrix\Sale;
use \Bitrix\Catalog\Product\Basket;
$registry = Sale\Registry::getInstance(
    Sale\Registry::REGISTRY_TYPE_ORDER
);
$context = ['SITE_ID' => SITE_ID];
$options = [
    // Если такой товар уже есть в корзине,
    // не объединять добавляемый с ним
    // ...а создавать рядом новую запись в корзине
    'USE_MERGE' => 'N',
    // Если в корзину добавляется
    // товарное предложение:
    //      Catalog\ProductTable::TYPE_OFFER
    // ...свойства товара
    // будут заполнены автоматически
    'FILL_PRODUCT_PROPERTIES' => 'Y',
    // При чтении информации о товаре через
    // \CIBlockElement::GetList
    // проверяет (или нет) доступы
    'CHECK_PERMISSIONS' => 'N',
];
// 01.1 Поднимаем объект корзины
$basketClass = $registry->getBasketClassName();
$basket = $basketClass::loadItemsForFUser(
    Sale\Fuser::getId(), SITE_ID
);
// 02. Набрасываем товаров
$productInfo01 = [/* ... */];
$productInfo02 = [/* ... */];
$productInfo03 = [/* ... */];
$res = Basket::addProductToBasket(
    $basket, $productInfo01, $context, $options
);
$res = Basket::addProductToBasket(
    $basket, $productInfo02, $context, $options
);
$res = Basket::addProductToBasket(
    $basket, $productInfo03, $context, $options
);
// Дальше, например:
// $order->setBasket($basket);
// $order->save();
Обсуждение статьи 7
Делаю примерно так:
/////////
use \Bitrix\Sale;
use \Bitrix\Catalog\Product\Basket;
// получаем заказ по id
$orderOb = \Bitrix\Sale\Order::load($order['ORDER_ID']);
// получаем корзину заказа
$basket = $orderOb->getBasket();
// Далее происходит некий цикл, где мы добавляем товары, вот так
$context = ['SITE_ID' => 's1'];
$options = ['USE_MERGE' => 'Y', 'FILL_PRODUCT_PROPERTIES' => 'Y'];
$product = [
'PRODUCT_ID' => $arOrders[$keyOrder]['BASKET'][$keyBasket]['PRODUCT_ID'],
'QUANTITY' => $arOrders[$keyOrder]['BASKET'][$keyBasket]['COUNT'],
'CURRENCY' => 'RUB'
];
Basket::addProductToBasket($basket, $product, $context, $options);
Потом выходим из цикла и сохраняем заказ
$orderOb->save();
////////////////
По идее 2 товара должны пересчитаться кол-во и стоимость, а третий товар добавиться с нужным кол-вом, а они добавляются вот так: https://disk.yandex.ru/i/8SJt_ug0kgJZLg
Что это такое?
Кроме того, я думал, что данный способ корректно добавит новый товар в корзину заказа, но и он добавляется не правильно.