Розробка функціоналу «собери набір» на 1С-Bitrix
«Собери набір» — легша варіація конструктора: користувач не налаштовує сумісність компонентів, а просто вибирає N товарів з фіксованого пулу, отримуючи скидку за комплектність. Типові випадки: «Вибери 3 із 10 косметичних засобів», «Скомплектуй піцу + напиток + десерт», «Подарункова коробка: вибери 5 цукерок з 30 смаків». Завдання здається простішим конструктора ПК, але в реалізації є нетривіальні моменти.
Структура функціоналу
Функціонал «собери набір» складається з трьох компонентів:
- Сторінка набору — опис акції, правила (скільки вибрати, фіксована або змінна ціна)
- Інтерфейс вибору — сітка доступних товарів з чекбоксами/кнопками додавання
- Кошик набору — mini-кошик на сторінці, показуючий поточний вибір і прогрес
Зберігання даних набору
Набір описується елементом інфоблока (або записом кастомної таблиці):
// Властивості інфоблока «Набори»
'MIN_ITEMS' => 3, // мінімум позицій для активації скидки
'MAX_ITEMS' => 5, // максимум позицій в наборі
'SET_PRICE' => 1990, // фіксована ціна набору (якщо задана)
'DISCOUNT_PCT' => 15, // скидка на суму вибраних товарів (альтернатива)
'PRODUCTS' => [12, 15, 18, 22, ...], // ID дозволених товарів
'ACTIVE_FROM' => '2025-03-01', // строк акції
'ACTIVE_TO' => '2025-04-01',
При великому пулу товарів (50+) список дозволених позицій задається не перечисленням ID, а фільтром по розділу або тегу:
'ALLOWED_SECTIONS' => [5, 7, 12], // ID розділів, з яких можна вибирати
'ALLOWED_TAGS' => ['promo-may', 'gift-set'],
Інтерфейс вибору: ключові UX-паттерни
Лічильник прогресу — показує «Вибрано 2 з 3». Без нього користувач теряється. Реалізація:
const maxItems = 3;
let selected = [];
function toggleProduct(productId, btn) {
if (selected.includes(productId)) {
selected = selected.filter(id => id !== productId);
btn.classList.remove('selected');
} else if (selected.length < maxItems) {
selected.push(productId);
btn.classList.add('selected');
}
updateProgress();
}
function updateProgress() {
document.querySelector('.progress-text').textContent = `Вибрано ${selected.length} з ${maxItems}`;
document.querySelector('.add-to-cart-btn').disabled = selected.length < minItems;
}
Блокування лишніх виборів — коли вибрано максимум, решта товарів стають неактивними (disabled), але можна знімати вибір з уже доданих. Візуально: карточка сіра, кнопка неактивна.
Превью набору — справа (на комп'ютері) або знизу (на мобільному) фіксована панель зі списком вибраних товарів, финальною ціною й кнопкою «В кошик».
Розрахунок ціни
Два режими ціноутворення:
Фіксована ціна набору. Користувач вибрав будь-які 3 товари — платить 999 рублів, незалежно від цін окремих позицій. У кошику додається спеціальна позиція «Набір» з ціною 999 р., без деталізації по товарам.
Скидка на вибрані позиції. Сума цін вибраних товарів множиться на коефіцієнт (наприклад, ×0,85 при скидці 15%). У кошику кожен товар додається за зниженою ціною.
Для другого варіанту можна використовувати правила кошика (b_sale_discount), але простіше встановити ціну програмно при додаванні в кошик через поле PRICE позиції й CUSTOM_PRICE => 'Y'.
Додавання в кошик
// Контролер AJAX-запроса додавання набору в кошик
public function addSetToCartAction(int $setId, array $productIds): array {
// 1. Валідація: всі productIds дозволені для цього набору
$setData = $this->loadSetData($setId);
if (!$this->validateProducts($productIds, $setData)) {
return ['success' => false, 'error' => 'Недопустимі товари'];
}
// 2. Перевірка кількості
if (count($productIds) < $setData['MIN_ITEMS'] || count($productIds) > $setData['MAX_ITEMS']) {
return ['success' => false, 'error' => 'Неверна кількість позицій'];
}
// 3. Розрахувати ціни
$prices = $this->calcPrices($productIds, $setData);
// 4. Додати в кошик
$setCode = 'bundle_' . $setId . '_' . uniqid();
$basket = \Bitrix\Sale\Basket::loadItemsForFUser(\CSaleBasket::GetBasketUserID(), SITE_ID);
foreach ($productIds as $i => $pid) {
$item = $basket->createItem('catalog', $pid);
$item->setFields([
'QUANTITY' => 1,
'CUSTOM_PRICE' => 'Y',
'PRICE' => $prices[$i],
'BASE_PRICE' => $prices[$i],
]);
// Записуємо SET_CODE у props для групування в кошику
$propCol = $item->getPropertyCollection();
$propCol->setProperty(['CODE' => 'SET_CODE', 'VALUE' => $setCode]);
}
$basket->save();
return ['success' => true, 'basket_count' => count($basket)];
}
Відображення в кошику й замовленні
В кошику товари з одного набору відображаються як група. Шаблон компонента bitrix:sale.basket.basket кастомізується: товари групуються по SET_CODE, відображаються зі скидкою й з можливістю редагування набору (посилання назад на конструктор).
У замовленні (таблиця b_sale_order_props) зберігається SET_CODE як реквізит позиції — для коректної обробки повернень та аналітики.
Обмеження по остаткам
Якщо товар із набору закінчився на складі, його не можна вибирати. Перевірка через CCatalogProduct::GetByID() або \Bitrix\Catalog\ProductTable:
$product = \Bitrix\Catalog\ProductTable::getRow([
'filter' => ['ID' => $productId],
'select' => ['QUANTITY', 'QUANTITY_TRACE', 'CAN_BUY_ZERO'],
]);
$available = ($product['CAN_BUY_ZERO'] === 'Y') || ($product['QUANTITY'] > 0);
Остатки кешуються на 5–10 хвилин — занадто часті запити до бази при великому пулі товарів навантажують систему.
Аналітика
Набір — це конверсійний інструмент, його ефективність потрібно виміряти. Що відстежувати:
- Скільки користувачів почали вибір (перегляд сторінки)
- Скільки завершили вибір і додали в кошик
- Скільки дійшли до оплати
- Середній склад набору (які товари вибираються частіше)
События передаються в Яндекс.Метрику або Google Analytics через dataLayer.push() на кожному кроці.
Графіки виконання
| Варіант | Що входить | Строк |
|---|---|---|
| Простий набір (фіксована ціна) | UI вибору + кошик + сторінка набору | 1–2 тижні |
| Зі скидкою на позиції + обмеження | + розрахунок скидок, остатки, аналітика | 2–4 тижні |
| Кілька активних наборів | + управління в админці, строки акцій | 3–5 тижнів |
Функціонал «собери набір» працює краще всього як обмежена акція: строк дії створює urgency, а можливість вибору — відчуття персоналізації. Це поєднання конвертує краще, ніж статичний готовий набір за такою ж ціною.







