Отправка универсальных передаточных документов (УПД) — одна из самых массовых операций в российском ЭДО. Для компании с сотней контрагентов и несколькими десятками документов в день ручной процесс быстро превращается в узкое горло: бухгалтер отвлекается от аналитики, появляются ошибки при повторном вводе, а задержки с отправкой влияют на сроки оплаты. Автоматизация отправки УПД из 1С в СБИС через cron решает эту проблему на уровне архитектуры, а не инструкций для сотрудников.
Почему стандартные способы интеграции не закрывают задачу
Перед тем как писать свой коннектор, мы изучили три типовых пути: готовый модуль 1С, встроенный обмен СБИС и ручную выгрузку через веб-интерфейс. Ни один из них не подошёл под нашу инфраструктуру без критических компромиссов.
Готовый модуль интеграции 1С и СБИС
Модуль существует, он официальный и поддерживается. Но он работает внутри 1С, использует встроенный язык и требует прямого доступа к базе. В нашей ситуации база 1С уже была нагружена операционной работой, а добавление регламентных заданий по обмену с ЭДО увеличивало риск блокировок при пиковой нагрузке. Кроме того, любое обновление конфигурации 1С потенциально ломало доработки модуля — и мы не хотели завязывать жизненный цикл интеграции на цикл обновлений учётной системы.
Встроенный обмен через API СБИС напрямую из 1С
Теоретически можно написать обработку на встроенном языке 1С, которая будет ходить в API СБИС. Практически — встроенный язык не проектировался для надёжной сетевой работы: нет встроенного retry с экспоненциальным backoff, нет типизированных DTO, нет unit-тестирования. При недоступности API СБИС регламентное задание падает, и диагностировать причину приходится вручную через журнал регистрации.
Ручная работа через личный кабинет
Это то, с чего начинают почти все. Бухгалтер формирует УПД в 1С, сохраняет в файл, заходит в СБИС, загружает, проверяет, подписывает, отправляет. При десяти документах в день это терпимо. При пятидесяти — становится полноценной рутиной, которая отнимает время, концентрацию и повышает риск человеческой ошибки.
Архитектура коннектора: общая схема
Мы выделили интеграцию в отдельный сервис на Symfony. Он живёт рядом с основным приложением, но не внутри 1С. Связь с учётной системой — через OData. Связь с СБИС — через REST API. Управление потоком — через cron и очередь сообщений Symfony Messenger.
| Компонент | Технология | Назначение |
|---|---|---|
| Ядро сервиса | Symfony 6/7 | DI-контейнер, команды, конфигурация |
| Клиент 1С | OData + HTTP-клиент | Чтение документов и статусов из 1С |
| Клиент СБИС | REST API + OAuth2 | Авторизация, отправка, проверка статуса |
| Очередь | Symfony Messenger + Redis | Асинхронная обработка и retry |
| Хранение | PostgreSQL | Локальное хранение документов и логов |
| Планировщик | cron + Symfony Console | Регулярный запуск синхронизации |
Как работает поток данных
Коннектор не пытается заменить 1С или СБИС. Он выполняет роль переводчика и доставщика: забирает готовый документ из учётной системы, преобразует в формат, понятный оператору ЭДО, отправляет и следит за статусом. Вся логика разбита на три консольные команды, которые вызываются по расписанию.
Шаг 1. Синхронизация исходящих УПД
Команда sbis:sync-upd запускается по cron каждые 10 минут. Она обращается к OData-сервису 1С и запрашивает документы, у которых статус «К отправке» и дата больше последней успешной синхронизации. Для каждого найденного документа создаётся DTO, валидируется обязательная структура, и сообщение отправляется в очередь Messenger.
Почему не отправляем сразу? Потому что API СБИС может быть недоступен, а 1С — нет. Разделение чтения и отправки через очередь позволяет 1С не ждать ответа от внешнего сервиса и не блокировать своё соединение.
Шаг 2. Отправка в СБИС
Consumer очереди забирает сообщение и вызывает DocumentService::send(). Сервис формирует JSON по спецификации СБИС, авторизуется через OAuth2, выполняет POST-запрос. В ответ получает идентификатор документа в системе СБИС, который сохраняет в локальную таблицу sbis_document. Если запрос падает по таймауту или возвращает 5xx — Symfony Messenger делает retry с экспоненциальной задержкой. После исчерпания попыток сообщение уходит в dead-letter очередь для ручного разбора.
Шаг 3. Проверка статусов
Команда sbis:check-status запускается каждые 15 минут. Она выбирает из локальной таблицы все документы, отправленные за последние 48 часов, и опрашивает СБИС о текущем статусе: доставлено, подписано контрагентом, отклонено, аннулировано. Обновлённые статусы пишутся в базу коннектора и, при необходимости, синхронизируются обратно в 1С через OData PATCH.
Шаг 4. Обработка входящих
Команда sbis:fetch-incoming забирает из СБИС документы, адресованные организации: входящие УПД, акты, счета-фактуры. Они валидируются, сохраняются локально и передаются в 1С для проведения. Это закрывает полный цикл двустороннего обмена, а не только исходящий трафик.
Что скрывается за абстракциями: нюансы реализации
Архитектура на бумаге выглядит линейно. На практике каждый слой добавил неочевидных сложностей, которые не описаны в документации СБИС и не решаются одним HTTP-запросом.
OAuth2: токен живёт дольше, чем написано
Документация СБИС указывает время жизни токена. На деле токен иногда остаётся валидным дольше, а иногда сбрасывается раньше при параллельных запросах из разных сервисов. Мы реализовали клиент с ленивым обновлением: перед каждым запросом проверяем TTL, при необходимости делаем refresh, а при 401 на лету повторяем запрос с новым токеном без падения основной операции.
Формат УПД: структура и валидация
СБИС принимает УПД в JSON, но структура отличается от того, что 1С называет «УПД». Например, поля контрагента, суммы НДС, номера ГТД и маркировки имеют разную вложенность. Мы ввели промежуточный DTO UpdDto, который описывает документ в терминах бизнеса, а не в терминах конкретного API. Маппер преобразует DTO в JSON СБИС, и если завтра формат изменится — правки идут только в маппер, а не в бизнес-логику.
Retry: не всё, что 5xx, стоит повторять
Симфонийский retry из коробки работает по HTTP-статусу. Но СБИС может вернуть 200 с ошибкой внутри тела, или 400 при невалидном ИНН контрагента, который повторным запросом не исправится. Мы добавили кастомный SbisApiException, который анализирует тело ответа и помечает ошибку как retriable или fatal. Fatal-ошибки сразу уходят в dead-letter, не тратя попытки retry.
Идемпотентность: как не отправить один УПД дважды
Если cron запустится во время работы предыдущего процесса, или consumer упадёт после отправки, но до подтверждения — документ может уйти в СБИС повторно. Мы используем локальную таблицу с уникальным индексом по связке «номер документа 1С + дата + контрагент». Перед отправкой коннектор проверяет, не существует ли уже такой записи со статусом «отправлено». Это не гарантия на 100% — гарантия даёт только идемпотентный API, которого у СБИС нет — но сводит риск дублирования к минимуму.
Как выглядит cron-расписание
Мы разнесли команды по разным интервалам, чтобы не создавать пиковых нагрузок и не перегружать API СБИС:
sbis:sync-upd — поиск новых документов к отправке в 1С.
sbis:check-status — обновление статусов ранее отправленных документов.
sbis:fetch-incoming — забор входящих документов из СБИС.
Ротация логов и очистка старых записей в dead-letter очереди.
Интервалы подбирались эмпирически: при 50–100 документах в день 10 минут — баланс между оперативностью и нагрузкой. При росте объёма можно уменьшить интервал или добавить параллельных consumer-процессов — Symfony Messenger масштабируется горизонтально без изменения кода.
Мониторинг: как понять, что что-то пошло не так
Автоматизация хороша, пока работает. Когда ломается — важно узнать об этом до звонка от бухгалтера или контрагента. Мы настроили три уровня наблюдаемости.
Логи и трассировка
Каждый запрос к СБИС логируется: URL, статус, время выполнения, correlation ID. При ошибке в логе остаётся полное тело ответа — это сокращает время отладки с часов до минут. Логи пишутся в stdout и забираются стеком ELK.
Метрики очереди
Количество сообщений в очереди, количество failed, время обработки — всё это экспортируется в Prometheus. Алерт срабатывает, если failed-сообщений больше пяти за час: это сигнал, что проблема массовая, а не единичная.
Проверка «здоровья»
Отдельная команда sbis:health-check проверяет доступность API СБИС, валидность токена, связь с 1С и размер очереди. Она вызывается из системы мониторинга каждую минуту. Если хотя бы один чек не проходит — алерт уходит в Telegram-канал DevOps.
Результаты внедрения: что изменилось через три месяца
Коннектор работает в продакшене с начала года. За это время мы накопили метрики, которые позволяют говорить о результатах не в терминах «стало удобнее», а в цифрах.
| Показатель | До внедрения | После внедрения |
|---|---|---|
| Время на отправку УПД (в день) | 1,5–2 часа бухгалтера | 0 (полностью автоматически) |
| Задержка между созданием и отправкой | От 2 часов до 1 дня | До 10 минут |
| Ошибки при ручном вводе (дубли, неверный контрагент) | 3–5 в неделю | 0 |
| Время реакции на сбой API СБИС | От 4 часов (по жалобе) | До 5 минут (по алерту) |
| Нагрузка на сервер 1С от обмена | Заметная (регламентные задания) | Минимальная (OData-запросы) |
Кому подойдёт такая архитектура
Коннектор не является универсальным решением для любой компании. Он окупается при определённых условиях, и важно не строить оверинжиниринг ради технологий.
Меньше — ручная работа дешевле, чем поддержка отдельного сервиса. Больше — экономия времени перекрывает затраты на инфраструктуру.
Если OData недоступен — придётся добавлять дополнительный слой интеграции, что усложняет архитектуру.
Коннектор — это не no-code решение. Для доработки, отладки и обновлений нужен разработчик соответствующего стека.
Если задержка в полдня критична для цепочки поставок или оплаты — автоматизация через cron закрывает этот риск.
Итог
Автоматизация отправки УПД из 1С в СБИС через cron — это не просто замена ручных действий скриптом. Это смена архитектурного подхода: интеграция выносится из учётной системы в отдельный сервис, получает очередь сообщений, retry, мониторинг и масштабируемость.
Такой коннектор не решает все проблемы ЭДО, но решает ключевую: он убирает рутину, снижает количество ошибок и даёт бизнесу предсказуемость в том, когда документ окажется у контрагента. Если ваш поток документов уже перерос ручное управление — это сигнал, что пора инвестировать в инфраструктуру, а не в инструкции.
Исходный код коннектора, на котором основана статья, доступен в репозитории sbis-1c-connector — он содержит реализацию клиента, DTO, сервисов и команд, описанных выше.