Разработка модуля программы лояльности 1С-Битрикс
Встроенный инструмент «бонусы» в Битрикс — это поле b_user.UF_BONUS_POINTS плюс самодельная логика в компонентах. Нет истории начислений, нет срока действия баллов, нет уровней, нет интеграции с заказами через события. Когда клиент говорит «хотим программу лояльности», имеется в виду нечто значительно большее: накопительная система с уровнями, историей, ограниченным сроком действия баллов, частичной оплатой заказа и витриной привилегий.
Модель данных
Модуль vendor.loyalty:
-
b_vendor_loyalty_account— счёт лояльности: id, user_id, balance (текущий баланс), total_earned (всего начислено за всё время), level_id, created_at -
b_vendor_loyalty_transaction— транзакции: id, account_id, type (earn/spend/expire/cancel/manual), amount, order_id, description, expires_at, created_at -
b_vendor_loyalty_level— уровни программы: id, name, min_points, earn_multiplier, privileges (JSON), icon_id -
b_vendor_loyalty_rule— правила начисления: id, event_type (order_paid/review_added/birthday/referral/registration), points_type (fixed/percent), points_value, conditions (JSON), is_active
Начисление баллов
Начисление привязано к событиям Битрикс. Для заказов — OnSaleOrderPaid:
AddEventHandler('sale', 'OnSaleOrderPaid', ['\Vendor\Loyalty\EventHandler', 'onOrderPaid']);
public static function onOrderPaid(\Bitrix\Main\Event $event): void
{
$orderId = $event->getParameter('id');
$order = \Bitrix\Sale\Order::load($orderId);
$userId = $order->getUserId();
$account = AccountTable::getByUserId($userId);
$level = LevelTable::getById($account['LEVEL_ID']);
// Начисляем % от суммы заказа с учётом множителя уровня
$basePoints = floor($order->getPrice() * 0.05); // 5% базово
$earnedPoints = floor($basePoints * $level['EARN_MULTIPLIER']);
TransactionTable::add([
'ACCOUNT_ID' => $account['ID'],
'TYPE' => 'earn',
'AMOUNT' => $earnedPoints,
'ORDER_ID' => $orderId,
'EXPIRES_AT' => (new DateTime())->add(new DateInterval('P1Y')), // срок жизни — 1 год
'DESCRIPTION' => "Начисление за заказ №{$order->getField('ACCOUNT_NUMBER')}",
]);
AccountTable::update($account['ID'], [
'BALANCE' => $account['BALANCE'] + $earnedPoints,
'TOTAL_EARNED' => $account['TOTAL_EARNED'] + $earnedPoints,
]);
// Проверка повышения уровня
LevelUpgradeService::check($account['ID']);
}
Срок действия баллов и истечение
Баллы могут иметь дату истечения. Агент ежедневно проверяет и списывает просроченные баллы:
// Агент запускается в 03:00 ночи
$expired = TransactionTable::getList([
'filter' => ['TYPE' => 'earn', '<=EXPIRES_AT' => new DateTime(), '>AMOUNT' => 0],
])->fetchAll();
foreach ($expired as $tx) {
// Списываем оставшиеся баллы из этой транзакции
TransactionTable::add(['TYPE' => 'expire', 'AMOUNT' => -$tx['REMAINING'], ...]);
// Обновляем баланс счёта
}
Списание баллов при оплате заказа
Частичная оплата заказа баллами реализуется через кастомную систему оплаты (PaySystem):
// В процессоре платёжной системы
public function processRequest(Payment $payment, Request $request): ProcessRequestResult
{
$pointsToSpend = (int)$request->get('loyalty_points');
$account = AccountTable::getByUserId($payment->getOrder()->getUserId());
if ($account['BALANCE'] < $pointsToSpend) {
return ProcessRequestResult::error('Недостаточно баллов');
}
// 1 балл = 1 рубль (настраивается в модуле)
$discountAmount = $pointsToSpend / (int)Option::get('vendor.loyalty', 'points_rate', 1);
$discountAmount = min($discountAmount, $payment->getSum() * 0.5); // максимум 50% заказа
// Списываем баллы и создаём скидку на заказ
TransactionTable::add(['TYPE' => 'spend', 'AMOUNT' => -$pointsToSpend, ...]);
AccountTable::update($account['ID'], ['BALANCE' => $account['BALANCE'] - $pointsToSpend]);
return ProcessRequestResult::success();
}
Уровни программы
Уровни повышаются автоматически по TOTAL_EARNED. При повышении уровня:
- Пересчитывается множитель начислений (
EARN_MULTIPLIER) - Отправляется уведомление пользователю
- Активируются привилегии уровня (бесплатная доставка, приоритетная поддержка — через флаги в
b_user.UF_*)
| Уровень | Порог (всего баллов) | Множитель начислений |
|---|---|---|
| Стандарт | 0 | 1.0x |
| Серебро | 5 000 | 1.2x |
| Золото | 20 000 | 1.5x |
| Платина | 50 000 | 2.0x |
Пороги и множители настраиваются в административном интерфейсе.
Личный кабинет пользователя
Блок «Моя лояльность» в личном кабинете:
- Текущий баланс и уровень
- Прогресс до следующего уровня
- История транзакций с пагинацией
- Ближайшие сгорающие баллы с датами
- Форма применения баллов при оформлении заказа
Сроки разработки
| Этап | Срок |
|---|---|
| ORM-таблицы, модель счёта и транзакций | 1 день |
| Правила начисления, обработчики событий | 2 дня |
| Срок действия баллов, агент истечения | 1 день |
| PaySystem для списания баллов | 2 дня |
| Уровни, автоповышение, привилегии | 2 дня |
| Личный кабинет, история транзакций | 2 дня |
| Административный интерфейс | 1 день |
| Тестирование | 1 день |
Итого: 12 рабочих дней. Интеграция с офлайн-кассой или CRM для начисления баллов за покупки вне сайта — дополнительная оценка.







