Запуск программы лояльности

Запуск программы лояльности

Задача: необходимо запустить систему лояльности в приложении. В списке товаров и детальной карточке, отображаем количество бонусов для начисления.В оформлении заказа даем списать и начислить. В личном кабинете отображаем историю списания, начисления и количество активных бонусов.  

Важно
На стороне сайта уже функционирует бонусная система и разработчик знаком с методами, которые позволят начислить, списать и провести расчет бонусов. Предполагается, что необходимые настройки в панели управления сайта уже проведены.

Условия программы лояльности

  1. За каждый товар со скидкой, начисляется 5% от конечной стоимости
  2. За товар БЕЗ скидки, начисляются 10% от стоимости
  3. Если клиент положил в корзину, товаров более чем на 5000 руб., дополнительно начислим 5% от суммы всей корзины
  4. Списать можно только 30% от суммы покупки

Создание новой платежной системы

В административном разделе сайта создаем новую платежную систему, с параметрами:

  • Обработчик: Наличный расчет (cash)
  • Название: Оплата бонусами

Привяжем созданную платежную систему в настройках модуля MobiusApp

Расчет количества бонусов в списке товаров

Для расчета бонусов и вывод их в списке товаров и детальной карточке, нам нужно написать обработчик события в БУСе. Здесь официальная документация на этот счет.

Приступим к пошаговой реализации.

Создадим файл /local/php_interface/mobiusapp_loyalty.php с содержимым:

PHP
use Bitrix\Main; class MobiusAppLoyaltyEvents { /** * Этот метод будет вызван для каждого элемента каталога при его выводе в мобильном приложении * Результат выполнения функции всегда должен быть целым числом */ public static function onCatalogElementLoyaltyCalculate(Main\Event $event) :int { $result = $event->getParameter('attributes'); // На товар без скидки начисляем 10% на товар со скидкой 5% return (int)$result['BASE_PRICE'] > (int)$result['PRICE'] ? $result['PRICE'] * 0.05 : $result['PRICE'] * 0.1; } } Main\EventManager::getInstance()->addEventHandler( 'mobiusapp.backend', 'onCatalogElementLoyaltyCalculate', ['MobiusAppLoyaltyEvents', 'onCatalogElementLoyaltyCalculate'] );

Добавим в конец файла /local/php_interface/init.php строку (если файла нет - создаем):

PHP
include_once(__DIR__ . "/mobiusapp_loyalty.php");

Проверим работоспособность, вызвав api-метод списка товаров. Ответ должен содержать корректный JSON-объект и у каждого элемента должен быть ключ "bonuses" отличный от нуля.

Вывод бонусов в профиле

Количество активных бонусов

Расширим содержание файла /local/php_interface/mobiusapp_loyalty.php новой подпиской на событие onGetCurrentLoyaltyBalance:

getParameter('user'); $eventResult = new Main\Entity\EventResult($event->getEventType()); if (!empty($user['ID'])) { $resource = \Bitrix\Main\UserTable::getList([ 'select' => [ "ID", "UF_ACTIVE_BONUSES" ], 'filter' => [ '=ID' => $user['ID'], ], 'limit' => 1 ])->fetch(); $result["currentAmount"] = $resource && $resource['UF_ACTIVE_BONUSES'] ? (int)$resource['UF_ACTIVE_BONUSES'] : 0; $eventResult->modifyFields($result); } return $eventResult; } } ... Main\EventManager::getInstance()->addEventHandler( 'mobiusapp.backend', 'onGetCurrentLoyaltyBalance', ['MobiusAppLoyaltyEvents', 'onGetCurrentLoyaltyBalance'] );
Не забудьте
Если вы полностью копируете код выше, создайте пользовательское свойство UF_ACTIVE_BONUSES. Без этого, код будет выдавать ошибку.

Проверим работоспособность, вызвав api-метод получения текущего бонусного счета клиента. Ответ должен содержать корректный JSON-массив. Каждый элемент должен соответствовать структуре:  

{ "data": { "currentAmount": 999 } }
Производительность
Мы настоятельно рекомендуем кешировать результаты из сторонних API. Множественные лишние запросы могут привести к потере производительности всего приложения.

История списания и начисления

Расширим содержание файла /local/php_interface/mobiusapp_loyalty.php новой подпиской на событие onGetLoyaltyHistory:

getParameter('user'); $eventResult = new Main\Entity\EventResult($event->getEventType()); if (!empty($user['ID'])) { // Здесь код для получения выборки записей истории списания и начисления // Например из стороннего API или напрямую из БД // Сформируем массив с фиксированным набором ключей $result = []; $result[] = [ "AMOUNT" => 999, "TITLE" => "Начисление за покупку", "CREATED_DATE" => "20.10.2024" ]; $result[] = [ "AMOUNT" => -200, "TITLE" => "Списание", "CREATED_DATE" => "18.10.2024" ]; $eventResult->modifyFields($result); } return $eventResult; } } ... Main\EventManager::getInstance()->addEventHandler( 'mobiusapp.backend', 'onGetLoyaltyHistory', ['MobiusAppLoyaltyEvents', 'onGetLoyaltyHistory'] );

Проверим работоспособность, вызвав api-метод получения истории. Ответ должен содержать корректный JSON-массив. Каждый элемент должен соответствовать структуре:  

{ "data": [ { "title": "Начисление за покупку", "createdDate": "20.10.2024", "amount": 999 }, { "title": "Списание", "createdDate": "18.10.2024", "amount": -200 } ], "meta": null }

Расчет бонусов к списанию на экране оформления заказа

Обработчик события будет вызван при старте экрана заказа и непосредственно при оформлении заказа.

Расширим содержание файла /local/php_interface/mobiusapp_loyalty.php новой подпиской на событие onOrderLoyaltyCalculate:

getParameter('user'); $result = $event->getParameter('result'); $order = $event->getParameter('order'); $eventResult = new Main\Entity\EventResult($event->getEventType()); if ($order && !empty($user['ID'])) { // Получим актуальную корзину из заказа // Для товаров со скидкой начислим 5%, для товаров без скидки 10% // Если клиент списывает бонусы, начислится только 5% $discounts = $order->getDiscount(); $discountResult = $discounts->calculate(); $basket = $order->getBasket()->getOrderableItems(); if ($basket->isEmpty()) return $eventResult; if ($discountResult->isSuccess()) { $showPrices = $discounts->getShowPrices(); if (!empty($showPrices['BASKET'])) { foreach ($showPrices['BASKET'] as $basketCode => $data) { $basketItem = $basket->getItemByBasketCode($basketCode); if ($basketItem instanceof \Bitrix\Sale\BasketItemBase) { $basketItem->setFieldNoDemand('BASE_PRICE', $data['SHOW_BASE_PRICE']); $basketItem->setFieldNoDemand('PRICE', $data['SHOW_PRICE']); $basketItem->setFieldNoDemand('DISCOUNT_PRICE', $data['SHOW_DISCOUNT']); } } unset($basketItem, $basketCode, $data); } unset($showPrices); } unset($discountResult); // Ниже представлена структура результирующего массива. Сохраните его структуру. $finallyResult = array_merge($result, [ "canSpent" => 0, // Количество бонусов, доступных к списанию для этого заказа "accrualAmount" => [ // Массив с данными о начислении "withSpend" => 0, // Сумма начисления когда клиент СПИСЫВАЕТ бонусы "withoutSpend" => 0 // Сумма к начислению БЕЗ СПИСАНИЯ бонусов ] ]); foreach ($basket as $basketItem) { // Списать можно 30% от стоимости корзины $finallyResult["canSpent"] += ($basketItem->getQuantity() * $basketItem->getPrice()) * 0.3; if ($basketItem->getPrice() < $basketItem->getBasePrice()) { // Товар СО скидкой. Начисляем только 5% $finallyResult["accrualAmount"]["withSpend"] += ($basketItem->getQuantity() * $basketItem->getPrice()) * 0.05; $finallyResult["accrualAmount"]["withoutSpend"] += ($basketItem->getQuantity() * $basketItem->getPrice()) * 0.05; } else { // Товар БЕЗ скидки. Начисляем 10%, если клиент НЕ списывает бонусы и 5% если списывает $finallyResult["accrualAmount"]["withSpend"] += ($basketItem->getQuantity() * $basketItem->getPrice()) * 0.05; $finallyResult["accrualAmount"]["withoutSpend"] += ($basketItem->getQuantity() * $basketItem->getPrice()) * 0.1; } } $eventResult->modifyFields($finallyResult); } return $eventResult; } } ... Main\EventManager::getInstance()->addEventHandler( 'mobiusapp.backend', 'onOrderLoyaltyCalculate', ['MobiusAppLoyaltyEvents', 'onOrderLoyaltyCalculate'] );

Списание бонусов при оформлении заказа

В примере ниже, мы умышленно не написали код на списание бонусов, вы должны сделать это самостоятельно

Обновлено 06.08.2025 14:54