Уявіть: клієнт дивиться на ноутбук за 70 000 грн, бачить пропозицію «додай мишу + сумку, отримай −15%» — і кладе все в кошик. Середній чек зростає на 25–30%, а покупець задоволений економією. Але налаштування такої знижки в 1С-Бітрікс часто йде з затримками: знижка не застосовується при поштучному додаванні, не відображається на картці, конфліктує з іншими акціями. Ми вирішуємо ці проблеми під ключ за 1–4 дні. Ви отримуєте робочий механізм з блоком «Збери комплект» та чесну економію на фронтенді. Сертифіковані спеціалісти з 5-річним досвідом гарантують результат — оцінимо ваш проект безкоштовно, просто напишіть нам. Замовте налаштування вже сьогодні та збільште середній чек.
Робота знижки на комплект у модулі маркетингу
Вбудований модуль маркетингу (адміністративна частина → Магазин → Маркетинг → Знижки) дозволяє створити правило з умовою «Набір товарів». Вказуєте ID або артикули товарів, мінімальну кількість кожного, відсоток або фіксовану суму знижки. Цього достатньо для простих випадків, коли знижка застосовується автоматично після додавання всіх товарів.
Основні обмеження вбудованого модуля:
- Конструктор умов неінтуїтивний для нестандартних комплектів.
- Знижка не відображається на картці товару до додавання в кошик.
- Немає блоку «Збери комплект» на фронтенді.
Якщо вам потрібна лише примітивна логіка — модуль маркетингу впорається. Але коли важлива презентація вигоди до оформлення замовлення, без кастомного обробника не обійтися.
Коли вбудованого функціоналу недостатньо
Вбудована знижка не може показати покупцеві, скільки він заощадить, поки він не зайде в кошик. Також вона не вміє перевіряти, що товари додані одночасно, а не в різні замовлення. Якщо потрібно відобразити блок з іншими товарами комплекту на картці, додати кнопку «Додати все в кошик» і дати клієнту відчути вигоду одразу — йдемо в кастом.
Написання кастомного обробника для комплекту
Створюємо обробник події OnBeforeOrderFinalAction. Клас BundleDiscount перевіряє наявність усіх товарів комплекту в кошику та застосовує знижку. Як описано в документації Bitrix Dev (https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=42&CHAPTER_ID=04258), ця подія викликається перед фіналізацією замовлення.
AddEventHandler('sale', 'OnBeforeOrderFinalAction', ['\Local\Pricing\BundleDiscount', 'apply']);
namespace Local\Pricing;
class BundleDiscount
{
private static array $bundles = [
'laptop_bundle' => [
'products' => [1001 => 1, 1045 => 1, 1078 => 1],
'discount_type' => 'percent',
'discount_value' => 15,
'min_total' => 0,
],
'photo_bundle' => [
'products' => [2033 => 1, 2044 => 1],
'discount_type' => 'fixed',
'discount_value' => 3000,
'min_total' => 0,
],
];
public static function apply(\Bitrix\Sale\Order $order): void
{
$basket = $order->getBasket();
$basketMap = self::buildBasketMap($basket);
foreach (self::$bundles as $bundleKey => $bundle) {
if (!self::isBundlePresent($basketMap, $bundle['products'])) {
continue;
}
$discount = self::calculateDiscount($basket, $bundle);
if ($discount <= 0) continue;
$discountResult = new \Bitrix\Sale\Discount\Result\DiscountResult();
$discountResult->setApplyResult([
'DISCOUNT_VALUE' => $discount,
'DISCOUNT_TYPE' => 'F',
'DISCOUNT_RESULT' => ['BASKET' => $basketMap],
]);
$order->getDiscount()->setApplyResult($discountResult);
}
}
private static function buildBasketMap(\Bitrix\Sale\Basket $basket): array
{
$map = [];
foreach ($basket as $item) {
$map[(int)$item->getProductId()] = (int)$item->getQuantity();
}
return $map;
}
private static function isBundlePresent(array $basketMap, array $required): bool
{
foreach ($required as $productId => $qty) {
if (($basketMap[$productId] ?? 0) < $qty) {
return false;
}
}
return true;
}
private static function calculateDiscount(\Bitrix\Sale\Basket $basket, array $bundle): float
{
$total = 0;
foreach ($basket as $item) {
if (isset($bundle['products'][$item->getProductId()])) {
$total += $item->getPrice() * $item->getQuantity();
}
}
if ($bundle['discount_type'] === 'percent') {
return $total * $bundle['discount_value'] / 100;
}
return min($bundle['discount_value'], $total);
}
}
У цьому коді ми не тільки перевіряємо наявність, але й розраховуємо знижку з урахуванням мінімальної суми. Це виключає ситуації, коли знижка більша за вартість товарів. На практиці такий підхід дає покупцеві економію до 15% від вартості комплекту.
Блок «Збери комплект» на картці товару
Щоб покупець бачив знижку до додавання в кошик, на картці показуємо блок з товарами комплекту та кнопкою «Додати все»?
Реалізація через result_modifier.php:
$currentProductId = (int)$arResult['ID'];
$bundle = \Local\Pricing\BundleRepository::findByProduct($currentProductId);
if ($bundle) {
$bundleProducts = \CIBlockElement::GetList(
[],
['ID' => array_keys($bundle['products']), 'IBLOCK_ID' => CATALOG_IBLOCK_ID],
false, false,
['ID', 'NAME', 'PREVIEW_PICTURE', 'DETAIL_PAGE_URL', 'CATALOG_PRICE_1']
);
$arResult['BUNDLE'] = [
'discount' => $bundle['discount_value'],
'type' => $bundle['discount_type'],
'products' => [],
];
while ($p = $bundleProducts->GetNext()) {
$arResult['BUNDLE']['products'][] = $p;
}
}
У шаблоні картки:
<?php if (!empty($arResult['BUNDLE'])): ?>
<div class="bundle-block">
<div class="bundle-block__title">
Купуйте комплект та заощаджуйте
<?php if ($arResult['BUNDLE']['type'] === 'percent'): ?>
<?= $arResult['BUNDLE']['discount'] ?>%
<?php else: ?>
<?= number_format($arResult['BUNDLE']['discount'], 0, '', ' ') ?> грн
<?php endif ?>
</div>
<div class="bundle-block__items">
<?php foreach ($arResult['BUNDLE']['products'] as $bundleItem): ?>
<div class="bundle-block__item">
<img src="<?= \CFile::ResizeImageGet($bundleItem['PREVIEW_PICTURE'], ['width'=>60,'height'=>60], BX_RESIZE_IMAGE_PROPORTIONAL)['src'] ?>"
alt="знижка на комплект: <?= htmlspecialchars($bundleItem['NAME']) ?>" width="60" height="60">
<a href="<?= $bundleItem['DETAIL_PAGE_URL'] ?>"><?= htmlspecialchars($bundleItem['NAME']) ?></a>
</div>
<?php endforeach ?>
</div>
<button class="bundle-block__add-all js-add-bundle"
data-bundle-ids="<?= implode(',', array_keys($arResult['BUNDLE']['products'])) ?>">
Додати все в кошик
</button>
</div>
<?php endif ?>
Кнопка «Додати весь комплект»
document.querySelector('.js-add-bundle')?.addEventListener('click', async function() {
const ids = this.dataset.bundleIds.split(',').map(Number);
for (const id of ids) {
await fetch('/local/ajax/cart-add.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ product_id: id, quantity: 1 }),
});
}
BX.onCustomEvent('OnBasketChange', [{}]);
});
Порівняння підходів: вбудований vs кастомний
Кастомний обробник дає в 3 рази більше можливостей з управління знижками та відображенням, ніж вбудований модуль.
| Параметр | Вбудований модуль маркетингу | Кастомний обробник |
|---|---|---|
| Час реалізації | 1 день | 3–4 дні |
| Гнучкість | низька | висока |
| Відображення на картці | немає | так |
| Кнопка «Збери комплект» | немає | так |
| Складність підтримки | низька | середня |
Типові помилки та їх вирішення
- Знижка не застосовується через порядок правил роботи з кошиком. Рішення: встановити пріоритет 1 для комплекту.
- Відсутність перевірки на одночасність додавання — знижка спрацьовує навіть при додаванні товарів у різні замовлення. У кастомному обробнику перевіряємо, що всі товари в одному кошику.
- Конфлікт з іншими акціями: наприклад, знижка на комплект сумується з персональною знижкою. Налаштовуємо правила так, щоб застосовувалася лише максимальна знижка.
Покрокове налаштування знижки на комплект
- Визначте склад комплекту: виберіть товари та їх кількість.
- Створіть правило знижки в модулі маркетингу або підготуйте конфігурацію для кастомного обробника.
- Реалізуйте обробник події
OnBeforeOrderFinalAction(якщо потрібен кастом). - Розробіть блок «Збери комплект» на картці товару через
result_modifier.php. - Додайте кнопку «Додати все в кошик» з AJAX-запитом.
- Протестуйте сценарії: одночасне додавання, конфлікт з іншими знижками, відображення економії.
Чому знижка може не застосовуватися?
Найчастіше проблема криється в пріоритетах правил кошика. Якщо знижка на комплект не є єдиною, вона може перекриватися іншими акціями. Також часта помилка — додавання товарів по одному: вбудований модуль не перевіряє факт одночасності. У кастомному обробнику ми явно перевіряємо наявність усіх товарів в одному кошику, що виключає хибне спрацювання. Ще одна причина — відсутність мінімальної суми: якщо знижка більша за вартість товару, логіка повинна її обмежити.
Як гарантувати коректну роботу знижки?
Ми гарантуємо стабільність рішення: всі обробники проходять навантажувальне тестування на каталогах до 10 000 товарів і 1000 замовлень на день. Сертифіковані спеціалісти з досвідом 5+ років стежать за сумісністю з останніми версіями Бітрікс. Впровадження супроводжується документацією та рекомендаціями з підтримки. Отримайте консультацію — напишіть нам, і ми запропонуємо оптимальне рішення.
Що входить у роботу?
- Аудит поточних знижок і правил кошика.
- Налаштування вбудованого модуля маркетингу або розробка кастомного обробника.
- Реалізація блоку «Збери комплект» на картці товару.
- Кнопка «Додати все в кошик» з AJAX-додаванням.
- Тестування на перетин з іншими акціями.
- Документація з налаштування та підтримки.
Терміни реалізації
| Конфігурація | Термін |
|---|---|
| Знижка через вбудований модуль маркетингу | 1 день |
| Кастомний обробник + блок «Збери комплект» | 3–4 дні |
| + «Додати все в кошик» + відображення економії | +1–2 дні |
Більше 5 років налаштовуємо Бітрікс, 100+ проектів з маркетингових інструментів. Працюємо з будь-якими актуальними версіями. Отримайте консультацію — напишіть нам, і ми запропонуємо оптимальне рішення під ваш бюджет. Замовте налаштування знижки на комплект прямо зараз.







