Мы часто сталкиваемся с ситуацией: сеть магазинов ведёт учёт в 1С:Розница, а интернет-магазин работает на 1С-Битрикс. Клиент покупает товар в физическом магазине — начисление кэшбэка должно мгновенно появиться в его личном кабинете на сайте. И наоборот: списанный онлайн кэшбэк должен учитываться на кассе при следующем визите. Без синхронизации балансов программа лояльности работает раздельно для каждого канала, что ведёт к ошибкам и недовольству покупателей.
Типичные проблемы: дублирующиеся начисления, потерянные операции при обрыве связи, рассинхронизация балансов. Без надёжной интеграции программа лояльности становится источником ошибок, а не способом удержания клиентов. Мы предлагаем архитектуру двусторонней синхронизации кэшбэка под ключ — от проектирования до мониторинга. За годы работы мы реализовали более 30 интеграций кэшбэка для розничных сетей. В этой статье разберём технические детали: как выбрать мастер-систему, организовать идемпотентность транзакций и обработать офлайн-операции. Также рассмотрим API-контракты, поиск пользователей и мониторинг синхронизации.
Как выбрать мастер-систему для синхронизации кэшбэка?
Первый вариант — использовать 1С как мастер-систему. В этом случае Битрикс кэширует баланс, что упрощает консистентность, но при недоступности 1С онлайн-списание становится невозможным. Второй вариант — мастер-система Битрикс. Онлайн-списание не зависит от 1С, но офлайн-касса не сможет списать кэшбэк без сети. Третий вариант — синхронный обмен с очередью. Он самый надёжный, работает в любом режиме, но требует механизма разрешения конфликтов при одновременных операциях. Для большинства проектов оптимален первый вариант с кэшированием баланса на стороне Битрикс: он в два раза надёжнее второго при типичных сценариях работы кассы.
API на стороне Битрикс
Создаём REST-endpoint в Битрикс для получения и отправки операций из 1С:
// /local/api/cashback/v1/
// Маршрутизация через urlrewrite.php или отдельный файл
class CashbackApiController
{
/**
* GET /local/api/cashback/v1/balance?user_phone=79001234567
* Используется 1С для проверки баланса на кассе
*/
public function getBalance(): void
{
$this->requireApiKey();
$phone = $_GET['user_phone'] ?? '';
$userId = $this->getUserIdByPhone($phone);
if (!$userId) {
$this->respond(['error' => 'user_not_found'], 404);
return;
}
$balance = CashbackBalanceTable::getBalance($userId);
$this->respond([
'user_id' => $userId,
'balance' => $balance,
'updated_at' => CashbackBalanceTable::getLastUpdated($userId),
]);
}
/**
* POST /local/api/cashback/v1/transactions
* 1С отправляет операции (начисление/списание при офлайн-покупке)
*/
public function addTransaction(): void
{
$this->requireApiKey();
$body = json_decode(file_get_contents('php://input'), true);
$this->validateTransaction($body); // type, amount, external_id, user_phone
// Идемпотентность: external_id уникален на стороне 1С
if (CashbackTransactionTable::existsByExternalId($body['external_id'])) {
$this->respond(['status' => 'already_exists', 'idempotent' => true]);
return;
}
$userId = $this->getUserIdByPhone($body['user_phone']);
\Bitrix\Main\Application::getConnection()->startTransaction();
try {
CashbackTransactionTable::add([
'USER_ID' => $userId,
'TYPE' => $body['type'], // accrual|debit
'AMOUNT' => $body['amount'],
'DESCRIPTION' => $body['description'] ?? '',
'EXTERNAL_ID' => $body['external_id'], // ID документа в 1С
'SOURCE' => '1c_retail',
'CREATED_AT' => new \Bitrix\Main\Type\DateTime($body['created_at']),
]);
if ($body['type'] === 'accrual') {
CashbackBalanceTable::credit($userId, $body['amount']);
} else {
CashbackBalanceTable::debit($userId, $body['amount']);
}
\Bitrix\Main\Application::getConnection()->commitTransaction();
$this->respond(['status' => 'ok']);
} catch (\Exception $e) {
\Bitrix\Main\Application::getConnection()->rollbackTransaction();
$this->respond(['error' => $e->getMessage()], 500);
}
}
}
Почему идемпотентность критична?
Поле EXTERNAL_ID в таблице транзакций — уникальный идентификатор документа в 1С. 1С формирует его как {ТипОперации}_{НомерДокумента}_{Дата}. При повторной отправке одного и того же документа (сетевой сбой, повтор запроса) Битрикс отвечает already_exists без повторного зачисления — это защищает от дублей баланса. Это свойство критично для корректной работы программы лояльности. Как рекомендует документация 1С-Битрикс, идемпотентность должна быть реализована на уровне бизнес-логики обработки транзакций.
Пример обработки конфликта недостаточного баланса
При синхронизации офлайн-операций Битрикс возвращает ошибку с кодом insufficient_balance. 1С должна обработать это: отменить скидку или запросить доплату. В логе фиксируется событие.
Как проходит внедрение?
- Анализируем текущую архитектуру: определяем мастер-систему, каналы обмена, типы операций.
- Проектируем REST API на стороне Битрикс: endpoints, контракты, идемпотентность.
- Разрабатываем внешнюю обработку 1С: формирование запросов, обработка ответов.
- Тестируем в изолированной среде: имитируем офлайн-режим, проверяем конфликты.
- Разворачиваем в продуктив: настраиваем мониторинг, логирование, оповещения.
Далее — гарантийная поддержка после запуска.
Обработчик на стороне 1С
В 1С:Розница или 1С:Управление торговлей создаётся внешняя обработка или расширение, которое:
- При проведении чека начисления — отправляет POST на Битрикс API
- При списании кэшбэка на кассе — предварительно запрашивает баланс (
GET /balance), затем POST с операциейdebit - При отмене чека — отправляет операцию
release(отмена списания) или отрицательное начисление
Пример HTTP-запроса из 1С (встроенный HTTP-клиент):
Запрос = Новый HTTPЗапрос("/local/api/cashback/v1/transactions");
Запрос.Заголовки.Вставить("Content-Type", "application/json");
Запрос.Заголовки.Вставить("X-API-Key", Константы.КешбекAPIКлюч.Получить());
Запрос.УстановитьТелоИзСтроки(ЗаписатьJSON(ТелоЗапроса));
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Синхронизация при офлайн-работе кассы
Касса может работать без сети. В этом случае операции накапливаются в локальной базе 1С и отправляются пакетом при восстановлении соединения. Битрикс API принимает массив транзакций через POST /transactions/batch. Каждая транзакция обрабатывается независимо; в ответе — массив с результатом для каждой (успех/ошибка/дубль).
Конфликт: пользователь онлайн списал 500 рублей, пока касса работала офлайн. Офлайн-касса пыталась списать ещё 300, но баланс был 500. При синхронизации Битрикс обнаружит, что после первого списания остаток = 0, и отклонит офлайн-операцию с insufficient_balance. 1С должна обработать этот случай: аннулировать скидку или запросить доплату.
Поиск пользователя
Идентификация покупателя в офлайн — по номеру телефона. Поиск в Битрикс:
private function getUserIdByPhone(string $phone): ?int
{
$phone = preg_replace('/\D/', '', $phone);
$result = \Bitrix\Main\UserTable::getList([
'filter' => ['PERSONAL_PHONE' => $phone],
'select' => ['ID'],
'limit' => 1,
]);
if ($row = $result->fetch()) {
return (int)$row['ID'];
}
// Поиск по дополнительным полям UF_PHONE_VERIFIED
$result = \Bitrix\Main\UserTable::getList([
'filter' => ['UF_PHONE_VERIFIED' => $phone],
'select' => ['ID'],
'limit' => 1,
]);
return ($row = $result->fetch()) ? (int)$row['ID'] : null;
}
Телефоны хранятся в разных форматах — нормализация до 11 цифр (без +, ведущая 7 или 8) обязательна на входе.
Отображение офлайн-операций в личном кабинете
Транзакции с SOURCE = '1c_retail' отображаются в истории с меткой «Покупка в магазине» вместо ссылки на онлайн-заказ. В DESCRIPTION 1С передаёт адрес магазина или номер кассы — это показывается пользователю.
Мониторинг синхронизации
Таблица local_cashback_sync_log фиксирует все входящие запросы от 1С: время, external_id, статус ответа. Если в течение N часов не было операций от конкретного магазина — триггер уведомляет администратора (возможно, сбой в обработке на стороне 1С).
| Показатель | Ориентир |
|---|---|
| Время попадания офлайн-операции в Битрикс | < 5 минут при онлайн-работе кассы |
| Задержка при пакетной синхронизации после офлайн | < 10 минут от восстановления связи |
| Дублирование транзакций | 0 (идемпотентность через external_id) |
Что входит в работу
- REST API на стороне Битрикс: balance, transactions, batch
- Таблицы транзакций с
EXTERNAL_IDиSOURCE - Логика идемпотентности, обработка конфликтов при недостаточном балансе
- Нормализация телефонов, поиск пользователей
- Внешняя обработка 1С (согласовывается с программистом 1С)
- Мониторинг синхронизации, оповещения при сбоях
- Техническая документация и обучение вашего персонала
- Гарантийная поддержка после запуска
Сроки: 4–6 недель при наличии программиста 1С на проекте. 6–10 недель если требуется разработка обработчика 1С с нуля. Стоимость рассчитывается индивидуально — свяжитесь с нами для аудита вашей системы. Получите консультацию инженера. Оценим проект за один день.







