Настройка комплектов товаров (бандлов) на 1С-Битрикс
Магазин хочет продавать ноутбук вместе с мышью и сумкой как единый товар со скидкой 10%. На первый взгляд — просто новый элемент каталога. На практике это ломает учёт остатков, обмен с 1С и расчёт маржинальности, если сделать бандл «в лоб» как обычный товар.
Два подхода к реализации бандлов
Подход 1: Бандл как отдельный товар. Создаётся элемент инфоблока, остатки ведутся отдельно. Простой, но проблемный: при продаже бандла остатки входящих товаров не уменьшаются. Покупатель может купить мышь отдельно и в составе бандла, что приведёт к overselling.
Подход 2: Бандл как виртуальный товар с дочерними позициями. Бандл в каталоге — агрегат. Его «остаток» — минимальное количество среди входящих компонентов. При продаже уменьшаются остатки реальных дочерних товаров. Это правильный подход.
Битрикс поддерживает второй подход через тип продукта TYPE_SET = 4 в b_catalog_product. Поле TYPE в b_catalog_product принимает значения: 1 — простой товар, 2 — товар с торговыми предложениями, 4 — комплект (SET).
Структура хранения комплекта
Связь «комплект → компонент» хранится в таблице b_catalog_product_set:
-
SET_ID— ID комплекта (ID элемента инфоблока сTYPE = 4) -
ITEM_ID— ID товара-компонента -
QUANTITY— количество в комплекте -
SORT— порядок отображения -
IS_REQUIRED— обязательный или опциональный (0/1)
Создание комплекта через API:
// Создаём товар типа SET
$elementId = $iblock->Add([
'NAME' => 'Ноутбук + мышь + сумка',
'IBLOCK_ID' => CATALOG_IBLOCK_ID,
'ACTIVE' => 'Y',
]);
// Устанавливаем тип SET
\Bitrix\Catalog\ProductTable::update($elementId, ['TYPE' => \Bitrix\Catalog\ProductTable::TYPE_SET]);
// Добавляем компоненты
\Bitrix\Catalog\ProductSetTable::add([
'SET_ID' => $elementId,
'ITEM_ID' => $laptopId,
'QUANTITY' => 1,
'SORT' => 10,
'IS_REQUIRED' => 1,
]);
\Bitrix\Catalog\ProductSetTable::add([
'SET_ID' => $elementId,
'ITEM_ID' => $mouseId,
'QUANTITY' => 1,
'SORT' => 20,
'IS_REQUIRED' => 1,
]);
Расчёт остатков и цены бандла
Доступное количество бандла — минимум среди компонентов:
$components = \Bitrix\Catalog\ProductSetTable::getList([
'filter' => ['SET_ID' => $bundleId],
'select' => ['ITEM_ID', 'QUANTITY'],
])->fetchAll();
$available = PHP_INT_MAX;
foreach ($components as $c) {
$stock = \Bitrix\Catalog\ProductTable::getByPrimary(
$c['ITEM_ID'], ['select' => ['QUANTITY']]
)->fetch();
$available = min($available, floor((float)$stock['QUANTITY'] / $c['QUANTITY']));
}
Цена бандла может быть задана отдельно (скидка на комплект) или рассчитана как сумма цен компонентов. В Битрикс цена бандла хранится в b_catalog_price так же, как у обычного товара. Если нужна автоматическая скидка N% на комплект — используется правило корзины через b_sale_discount, не ручная цена.
Списание остатков при продаже
При добавлении бандла в корзину через стандартный компонент bitrix:sale.basket.basket Битрикс автоматически раскрывает комплект: в b_sale_basket создаются строки для каждого компонента с флагом SET_PARENT_ID, ссылающимся на строку бандла. При проведении заказа остатки списываются с каждого компонента отдельно.
Проблема возникает при прямом добавлении через \Bitrix\Sale\Basket::create() — если не передать параметры TYPE = TYPE_SET и дочерние позиции, раскрытия не произойдёт. Всегда используйте \Bitrix\Catalog\Product\Bundle::add() вместо прямой работы с корзиной.
Что настраиваем
- Создание товаров типа
TYPE_SETи заполнениеb_catalog_product_set - Расчёт доступного количества по минимуму среди компонентов
- Правило корзины для скидки на комплект через
b_sale_discount - Корректное добавление в корзину через
Bundle::add() - Интерфейс управления комплектами в административной части
- Проверку синхронизации с 1С: тип SET должен корректно передаваться при обмене







