Налаштування правил нарахування кешбеку за категоріями 1С-Бітрікс
Маркетолог хоче давати 5% кешбеку на електроніку, 2% на побутову хімію і 0% на акційні товари. При цьому правила мають комбінуватися: картка лояльності «Золото» дає +1% до базової ставки в будь-якій категорії. Стандартний модуль знижок (catalog.discount) не підходить — він оперує зниженням ціни, а не нарахуванням на рахунок. Потрібна окрема система правил.
Архітектура правил
Правила зберігаються в таблиці local_cashback_rules. Мінімальна структура:
CREATE TABLE local_cashback_rules (
ID INT AUTO_INCREMENT PRIMARY KEY,
RULE_TYPE ENUM('category','product','user_group','promo') NOT NULL,
ENTITY_ID INT, -- ID розділу інфоблоку, товару, групи
CASHBACK_PCT DECIMAL(5,2), -- відсоток нарахування
PRIORITY INT DEFAULT 10,-- чим менше, тим вищий пріоритет
DATE_FROM DATE,
DATE_TO DATE,
ACTIVE CHAR(1) DEFAULT 'Y'
);
Правила з RULE_TYPE = 'category' прив'язані до розділів інфоблоку каталогу. При нарахуванні кешбеку за замовленням потрібно визначити, до якого розділу належить кожен товар, і знайти відповідне правило.
Визначення категорії товару
Товар може бути прив'язаний до кількох розділів (множинна прив'язка). Для вибору правила беремо «основний» розділ:
function getCashbackRateForProduct(int $productId): float
{
// Основний розділ через b_iblock_element
$element = \CIBlockElement::GetByID($productId)->Fetch();
$sectionId = (int)$element['IBLOCK_SECTION_ID'];
// Шукаємо правило: спочатку за точним розділом, потім за батьками
while ($sectionId > 0) {
$rule = CashbackRuleTable::getActiveRuleForSection($sectionId);
if ($rule) {
return (float)$rule['CASHBACK_PCT'];
}
// Піднімаємося вгору по дереву розділів
$section = \CIBlockSection::GetByID($sectionId)->Fetch();
$sectionId = (int)$section['IBLOCK_SECTION_ID'];
}
// Правило за замовчуванням
return CashbackConfig::getDefaultRate();
}
Успадкування правил по дереву розділів: якщо на «Електроніка» встановлено 5%, а на «Ноутбуки» немає явного правила — ноутбуки отримають 5% від батьківського розділу. Явне правило на дочірньому розділі завжди перекриває батьківське.
Пріоритет і комбінування правил
Складна логіка з кількома одночасно активними правилами — через пріоритети:
function resolveCashbackRate(int $productId, int $userId): float
{
$baseRate = getCashbackRateForProduct($productId);
// Додаткові правила за групою користувача
$userGroups = CUser::GetUserGroup($userId);
$bonusRates = [];
foreach ($userGroups as $groupId) {
$rule = CashbackRuleTable::getQuery()
->setFilter([
'RULE_TYPE' => 'user_group',
'ENTITY_ID' => $groupId,
'ACTIVE' => 'Y',
'<=DATE_FROM' => new \Bitrix\Main\Type\Date(),
'>=DATE_TO' => new \Bitrix\Main\Type\Date(),
])
->setOrder(['PRIORITY' => 'ASC'])
->fetchObject();
if ($rule) {
$bonusRates[] = (float)$rule->getCashbackPct();
}
}
// Стратегія: беремо максимальний бонус від групи + базова категорійна ставка
$bonusRate = empty($bonusRates) ? 0 : max($bonusRates);
return $baseRate + $bonusRate;
}
Стратегію додавання або заміни обирає бізнес. Для більшості програм лояльності: категорійна ставка + груповий бонус (додавання), але не більше максимально допустимого відсотка.
Винятки: акційні товари та промо-періоди
Нульова ставка на акційні товари реалізується правилом із CASHBACK_PCT = 0 і максимальним пріоритетом (мінімальне число в полі PRIORITY). Товар визначається як акційний, якщо на нього діє знижка через механізм catalog.discount або через користувацьку властивість IS_PROMO = Y.
Промо-періоди — ті самі правила з DATE_FROM і DATE_TO. Автоматичне вмикання/вимикання без втручання розробника.
Нарахування після завершення замовлення
Кешбек нараховується при зміні статусу замовлення на «Виконано» (не при оплаті — щоб не нараховувати на повернені товари):
AddEventHandler('sale', 'OnSaleStatusOrder', function(string $statusId, \Bitrix\Sale\Order $order) {
if ($statusId !== 'F') { // F = Виконано
return;
}
$userId = $order->getUserId();
$totalCashback = 0;
foreach ($order->getBasket() as $item) {
$productId = (int)$item->getProductId();
$rate = resolveCashbackRate($productId, $userId);
$cashback = $item->getPrice() * $item->getQuantity() * ($rate / 100);
$totalCashback += $cashback;
// Фіксуємо за позицією для детальної історії
CashbackTransactionTable::add([
'USER_ID' => $userId,
'ORDER_ID' => $order->getId(),
'PRODUCT_ID' => $productId,
'AMOUNT' => $cashback,
'RATE' => $rate,
'TYPE' => 'accrual',
]);
}
CashbackBalanceTable::credit($userId, $totalCashback);
});
Управління правилами з адмінки
Інтерфейс управління правилами будується на CAdminList + CAdminForm або React-компонентом у розділі /local/admin/. Мінімальний набір: список правил з фільтром за типом/активністю, форма редагування з деревом розділів каталогу для вибору категорії.
Терміни
| Завдання | Термін |
|---|---|
| Таблиці правил, базова категорійна логіка | 3–5 днів |
| Групові бонуси, винятки, промо-періоди | 3–5 днів |
| Нарахування за замовленням з детальною історією | 2–3 дні |
| Інтерфейс управління правилами в адмінці | 3–5 днів |
| Повний комплекс | 2–3 тижні |







