Настройка единой программы лояльности онлайн и оффлайн в 1С-Битрикс
Мы сталкивались с ситуацией: клиент накопил 500 бонусов на сайте, приходит в магазин — кассир их не видит. Или покупка в магазине не начисляет баллы на онлайн-аккаунт. Разрыв между онлайн и оффлайн программой лояльности — это не только UX-проблема, но и прямые потери повторных продаж. Мы настраиваем единую систему лояльности под ключ: интеграция сайта и касс, синхронизация бонусов в реальном времени, полная прозрачность для клиента.
Как устроена лояльность в Битрикс
Модуль sale реализует дисконтную систему через b_sale_user_discount (персональные скидки) и бонусную систему через b_sale_discount (правила корзины). Для полноценной программы лояльности с накопительными баллами требуется либо отдельный модуль, либо интеграция с внешней системой. В Битрикс24 есть CRM-модуль с бонусами (b_crm_loyalty_bonus_transaction), но для интернет-магазина без Битрикс24 чаще применяется либо модуль marketingcrm, либо собственная таблица транзакций. По нашему опыту, кастомная реализация даёт наибольшую гибкость и надёжность — вы не привязаны к ограничениям типового модуля.
Структура хранения бонусов: таблицы и транзакции
Минимальная структура для единой программы:
CREATE TABLE bl_loyalty_account ( id SERIAL PRIMARY KEY, user_id INT UNIQUE, -- b_user.ID (онлайн) card_number VARCHAR(20) UNIQUE, -- номер карты для оффлайн balance NUMERIC(10,2) DEFAULT 0, created_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE bl_loyalty_transaction ( id SERIAL PRIMARY KEY, account_id INT NOT NULL REFERENCES bl_loyalty_account(id), amount NUMERIC(10,2) NOT NULL, -- положительное=начисление, отрицательное=списание type VARCHAR(20) NOT NULL, -- 'earn_online', 'earn_offline', 'spend', 'expire' order_id INT, -- b_sale_order.ID или внешний ID оффлайн-чека source VARCHAR(20) NOT NULL, -- 'web', 'pos', 'mobile' created_at TIMESTAMP DEFAULT NOW() ); Транзакционная модель с историей — единственный надёжный способ хранить бонусы. Никогда не обновляйте balance напрямую без записи транзакции. balance — это либо денормализованный агрегат (обновляется триггером БД), либо считается как SUM(amount) по таблице транзакций. Последний подход безопаснее, но медленнее при частых запросах баланса.
Как идентифицировать клиента на оффлайн-кассе?
Ключевая задача: кассир должен найти аккаунт клиента. Способы идентификации:
- Номер карты лояльности (физическая карта или штрихкод в мобильном приложении)
- Номер телефона (самый распространённый)
- QR-код с токеном (генерируется в личном кабинете сайта)
При идентификации по телефону кассовое ПО отправляет запрос к API Битрикс:
// /local/ajax/loyalty/find-account.php $phone = normalizePhone($_POST['phone']); $bitrixUser = \CUser::GetList([], ['PERSONAL_PHONE' => $phone])->Fetch(); if ($bitrixUser) { $account = getLoyaltyAccount($bitrixUser['ID']); echo json_encode(['balance' => $account['balance'], 'account_id' => $account['id']]); } Начисление бонусов при онлайн-заказе
Обработчик смены статуса заказа — после доставки/завершения:
AddEventHandler('sale', 'OnSaleStatusOrderChange', function(\Bitrix\Main\Event $event) { $order = $event->getParameter('ENTITY'); $status = $order->getField('STATUS_ID'); if ($status !== 'F') return; // Только завершённые заказы $userId = $order->getUserId(); $bonus = round($order->getPrice() * BONUS_RATE); // BONUS_RATE = 0.05 (5%) addLoyaltyTransaction($userId, $bonus, 'earn_online', $order->getId(), 'web'); }); Списание бонусов при онлайн-оплате
Бонусы применяются через правило корзины или через кастомный платёжный метод. Правило корзины (b_sale_discount) может давать скидку фиксированной суммой. Для более гибкой схемы — собственный «платёжный метод» типа «Оплата бонусами», который при проведении заказа списывает транзакцию из bl_loyalty_transaction.
Почему транзакционное списание критически важно?
Оффлайн-касса вызывает три endpoint:
-
GET /loyalty/balance?phone=...— проверить баланс -
POST /loyalty/spend— списать бонусы при продаже (должен быть транзакционным: начало продажи → резервирование → подтверждение) -
POST /loyalty/earn— начислить бонусы после продажи
Резервирование при списании — критически важный шаг. Без него два параллельных запроса от разных касс могут одновременно прочитать баланс 500 бонусов и дважды списать по 500, уйдя в минус. Резервирование через SELECT ... FOR UPDATE в PostgreSQL или через строгое UPDATE с проверкой результата:
UPDATE bl_loyalty_account SET balance = balance - :amount WHERE id = :account_id AND balance >= :amount RETURNING balance; -- Если обновлено 0 строк — недостаточно бонусов Этот подход надёжнее использования блокировок на уровне приложения.
Сравнение подходов: кастомная таблица vs модуль Битрикс
| Критерий | Кастомная реализация | Модуль marketingcrm | Битрикс24 CRM |
|---|---|---|---|
| Гибкость | Полная | Ограниченная | Средняя |
| Производительность | Высокая | Средняя | Средняя |
| Сложность интеграции с кассой | Средняя | Низкая | Низкая |
| Поддержка оффлайн-транзакций | Да | Ограниченно | Да |
| Стоимость лицензии | Бесплатно | Входит в редакцию | Требует Битрикс24 |
Кастомная таблица проигрывает модулям по скорости внедрения, но в 2-3 раза надёжнее при высоких нагрузках и нестандартных бизнес-логиках.
Что входит в работу
- Проектирование структуры таблиц
bl_loyalty_accountиbl_loyalty_transaction - Разработка REST API для кассовых систем (баланс, начисление, списание)
- Создание обработчиков событий
OnSaleStatusOrderChangeдля онлайн-начислений - Механизм идентификации клиента по телефону/карте
- Транзакционное списание с защитой от race condition
- Административный интерфейс для просмотра и отмены транзакций
- Документация по API и инструкция для кассиров
- Тестирование и гарантия 30 дней
Сроки и бюджет
Настройка единой программы лояльности занимает от 5 до 15 рабочих дней в зависимости от сложности (количество касс, необходимость интеграции с 1С, требования к отчётности). Стоимость рассчитывается индивидуально после аудита текущей системы. Оценим ваш проект за 1 день.
Типичные ошибки при настройке
- Обновление баланса напрямую без транзакции — потеря данных при сбое.
- Отсутствие блокировок при списании — двойное списание.
- Игнорирование API-логирования — сложно отлаживать.
- Использование только модуля marketingcrm для оффлайн — не поддерживает резервирование.
Избежать этих ошибок помогает опыт — мы реализовали более 30 проектов по лояльности на Битрикс, включая сети с 50+ кассами.
Свяжитесь с нами для консультации: расскажем, как объединить онлайн и оффлайн лояльность в вашем бизнесе.







