Настройка транзакционных уведомлений в мессенджеры 1С-Битрикс
Транзакционное уведомление — это сообщение, которое отправляется в ответ на конкретное действие пользователя: оформил заказ, оплатил, статус изменился, пришёл возврат. В Битрикс стандартный механизм таких уведомлений работает через b_event_message и email. Добавление мессенджеров (Telegram, Viber, WhatsApp) требует отдельной архитектуры: одного обработчика событий, абстрактного интерфейса отправщика и маршрутизации по предпочтениям пользователя.
Типы транзакционных событий в Битрикс
Ключевые события модуля sale:
-
OnSaleOrderSaved— заказ создан -
OnSaleOrderStatusChange— смена статуса -
OnSaleOrderPaid— оплата подтверждена -
OnSaleOrderCanceled— заказ отменён -
OnSaleShipmentTracking— обновление трека доставки
Модуль main:
-
OnAfterUserRegister— регистрация пользователя
Архитектура: единый диспетчер уведомлений
Вместо того чтобы вешать обработчик отдельно для каждого мессенджера, строим диспетчер:
// /local/lib/Notifications/Dispatcher.php
namespace Local\Notifications;
class Dispatcher
{
private static array $channels = [
'telegram' => TelegramChannel::class,
'viber' => ViberChannel::class,
'whatsapp' => WhatsAppChannel::class,
'email' => EmailChannel::class,
];
public static function send(int $userId, string $event, array $data): void
{
$prefs = self::getUserPreferences($userId);
foreach ($prefs as $channelName => $enabled) {
if (!$enabled) {
continue;
}
$channelClass = self::$channels[$channelName] ?? null;
if (!$channelClass) {
continue;
}
try {
/** @var ChannelInterface $channel */
$channel = new $channelClass($userId);
$channel->send($event, $data);
} catch (\Exception $e) {
// Логируем, не прерываем отправку в другие каналы
\Bitrix\Main\Diag\Debug::writeToFile(
"Notification error [{$channelName}]: " . $e->getMessage(),
'', '/local/logs/notifications.log'
);
}
}
}
private static function getUserPreferences(int $userId): array
{
$user = \Bitrix\Main\UserTable::getById($userId)->fetch();
return [
'telegram' => !empty($user['UF_TELEGRAM_CHAT_ID']) && $user['UF_NOTIFY_TELEGRAM'] === '1',
'viber' => !empty($user['UF_VIBER_USER_ID']) && $user['UF_NOTIFY_VIBER'] === '1',
'whatsapp' => !empty($user['UF_PHONE']) && $user['UF_NOTIFY_WHATSAPP'] === '1',
'email' => true, // email всегда включён как fallback
];
}
}
Интерфейс канала и шаблоны сообщений
// /local/lib/Notifications/ChannelInterface.php
namespace Local\Notifications;
interface ChannelInterface
{
public function send(string $event, array $data): void;
}
Шаблоны сообщений выносим отдельно — не в логику канала:
// /local/lib/Notifications/Templates.php
namespace Local\Notifications;
class Templates
{
private static array $templates = [
'order_created' => [
'text' => 'Заказ #{{ORDER_ID}} оформлен на сумму {{TOTAL}} {{CURRENCY}}.',
],
'order_paid' => [
'text' => 'Оплата по заказу #{{ORDER_ID}} подтверждена. Ждите отгрузки.',
],
'order_shipped' => [
'text' => 'Заказ #{{ORDER_ID}} передан в доставку. Трек: {{TRACKING_CODE}}.',
],
'order_delivered' => [
'text' => 'Заказ #{{ORDER_ID}} доставлен. Спасибо за покупку!',
],
'order_canceled' => [
'text' => 'Заказ #{{ORDER_ID}} отменён.',
],
];
public static function render(string $event, array $data): string
{
$template = self::$templates[$event]['text'] ?? '';
foreach ($data as $key => $value) {
$template = str_replace('{{' . $key . '}}', $value, $template);
}
return $template;
}
}
Регистрация обработчиков событий
// /local/php_interface/init.php
use Local\Notifications\Dispatcher;
$em = \Bitrix\Main\EventManager::getInstance();
// Заказ создан
$em->addEventHandler('sale', 'OnSaleOrderSaved', function (\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
if (!$order->isNew()) {
return;
}
Dispatcher::send($order->getUserId(), 'order_created', [
'ORDER_ID' => $order->getId(),
'TOTAL' => number_format($order->getPrice(), 2, '.', ' '),
'CURRENCY' => $order->getCurrency(),
]);
});
// Смена статуса
$em->addEventHandler('sale', 'OnSaleOrderStatusChange', function (\Bitrix\Main\Event $event) {
$order = $event->getParameter('ENTITY');
$statusId = $order->getField('STATUS_ID');
$eventMap = [
'P' => 'order_shipped',
'F' => 'order_delivered',
'X' => 'order_canceled',
];
$notifyEvent = $eventMap[$statusId] ?? null;
if (!$notifyEvent) {
return;
}
$data = ['ORDER_ID' => $order->getId(), 'TRACKING_CODE' => ''];
if ($notifyEvent === 'order_shipped') {
// Получаем трек из отгрузки
$shipment = $order->getShipmentCollection()->getNotSystemItems()->current();
$data['TRACKING_CODE'] = $shipment?->getField('TRACKING_NUMBER') ?? 'уточняется';
}
Dispatcher::send($order->getUserId(), $notifyEvent, $data);
});
Управление подписками в личном кабинете
Пользователь сам выбирает каналы в /personal/notifications/:
- Чекбоксы «Уведомления в Telegram / Viber / WhatsApp»
- Кнопки подключения канала (deep link / ввод телефона)
- Предпросмотр типовых уведомлений
Настройки сохраняются в пользовательских полях UF_NOTIFY_TELEGRAM, UF_NOTIFY_VIBER, UF_NOTIFY_WHATSAPP (тип «Да/Нет»).
Очередь отправки
Синхронная отправка в три мессенджера при каждой смене статуса добавляет задержку к обработке заказа. Для highload — асинхронная очередь:
// Вместо прямого вызова — ставим в очередь
Queue::push('notification', [
'user_id' => $userId,
'event' => $notifyEvent,
'data' => $data,
'created' => time(),
]);
Воркер разбирает очередь и делает реальные запросы к API мессенджеров. Битрикс агент как простой вариант очереди — проверяет таблицу задач каждую минуту.
Сроки настройки
Диспетчер уведомлений с поддержкой Telegram + Viber, шаблоны по 5 событиям, страница управления подписками в личном кабинете, без очереди (синхронно) — 2–3 рабочих дня. С асинхронной очередью и тремя мессенджерами — 4–6 рабочих дней.







