Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Фискализация чеков и онлайн-касса в интеграции

Фискализация чеков: взаимодействие сервиса с онлайн-кассой

Фискализация платежей: формирование чека, отправка в кассу, фискальный признак, повторная отправка и действия при недоступности кассы.

Прямой ответ

Фискализация — формирование чека и его регистрация в контрольно-кассовой технике с получением фискального признака. Чек формируется после успешной оплаты и регистрируется через кассу либо сервис облачной кассы.

Последовательность операции:

Оплата подтверждена ──▶ Формирование чека ──▶ Отправка в кассу
                                                    │
Фискальный признак ◀── Ответ кассы ◀────────────────┘
receipt = {
    "external_id": f"order-{order_id}",
    "customer": {"email": user_email},
    "items": [{"name": "Ноутбук", "quantity": 1,
               "price_minor": 74000, "vat": "vat20"}],
    "payment_type": "card",
}
r = httpx.post(f"{KASSA_API}/receipts", json=receipt,
               headers={"Authorization": f"Bearer {KASSA_TOKEN}"}, timeout=15.0)
fiscal_id = r.json()["fiscal_document_number"]

Собственная таблица чеков хранит состояние регистрации:

CREATE TABLE receipts (
    id             bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    order_id       bigint NOT NULL,
    external_id    text NOT NULL UNIQUE,
    fiscal_number  text,
    status         text NOT NULL,
    attempts       int NOT NULL DEFAULT 0,
    created_at     timestamptz NOT NULL DEFAULT now(),
    registered_at  timestamptz
);

Внешний идентификатор чека уникален, поэтому повторная отправка не создаёт второй чек. О механизме — в статье про ключ идемпотентности.

Состояние чека Значение Действие
pending Сформирован, не отправлен Отправить в кассу
sent Отправлен, ответ не получен Уточнить состояние
registered Фискальный признак получен Завершено
failed Отклонён кассой Разбор причины

Состояние sent обязательно: ответ кассы может не дойти после регистрации чека, и повторная отправка без уточнения создаёт дубль.

Состав чека и расхождения с платёжными данными

Чек формируется из состава заказа, а не из суммы платежа. Различие возникает в четырёх ситуациях.

Скидка. Скидка распределяется по позициям, поскольку чек содержит цены позиций, а не итоговую сумму. Распределение выполняется с учётом округления, иначе сумма позиций не совпадает с суммой чека.

Доставка. Доставка указывается отдельной позицией, поскольку имеет собственную ставку налога.

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

Изменение состава после оплаты. Замена позиции после оплаты требует чека коррекции, а не нового чека прихода.

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

SELECT SUM(quantity * price_minor) AS items_total
FROM receipt_items WHERE receipt_id = $1;

Отдельный вопрос — момент формирования чека. Чек формируется после подтверждения оплаты, а не в момент создания заказа, поскольку отменённый заказ не требует регистрации. Уведомление об оплате приходит асинхронно, поэтому формирование выполняется по событию; о приёме уведомлений — в статье про платёжные вебхуки.

Очередь чеков и поведение при сбое кассы

Касса либо сервис облачной кассы может быть недоступен, а регистрация чека обязательна. Между подтверждением оплаты и регистрацией существует промежуток, который требует очереди.

Очередь сформированных чеков. Чек сохраняется в состоянии pending и отправляется при доступности кассы. Отсутствие очереди означает потерю чека при сбое, поскольку оплата подтверждена, а регистрации нет.

Ограничение числа попыток. Бесконечные повторы при недоступности кассы создают нагрузку и не приводят к регистрации. После исчерпания попыток чек переходит в очередь недоставленных сообщений для разбора.

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

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

Практическое следствие: формирование чека и его регистрация — два независимых шага, разделённых очередью. Формирование выполняется в транзакции с подтверждением оплаты, поэтому чек не теряется при сбое кассы, а регистрация выполняется отдельно и повторяется до успеха.

Отдельный аспект — восстановление после длительного сбоя. Накопившаяся очередь отправляется с ограничением скорости, поскольку массовая отправка создаёт пиковую нагрузку на кассу. Ограничение задаётся числом чеков в единицу времени.

Практика: организация фискализации

1. Формируйте чек после подтверждения оплаты. Отменённый либо неуспешный платёж не требует регистрации чека.

2. Используйте уникальный внешний идентификатор чека. Повторная отправка возвращает существующий чек вместо создания дубля.

3. Проверяйте сумму позиций до отправки. Расхождение суммы позиций и суммы чека отклоняется кассой.

4. Учитывайте состояние неопределённости. Ответ кассы может не дойти после регистрации, поэтому состояние уточняется запросом.

5. Различайте чек прихода, возврата и коррекции. Каждый тип имеет собственный состав и правила формирования.

6. Распределяйте скидку по позициям. Чек содержит цены позиций, поэтому скидка не указывается отдельной суммой.

7. Повторяйте отправку с ограничением числа попыток. Чек, который не удаётся зарегистрировать, помещается в очередь недоставленных сообщений; о разборе ошибок — в статье про dead letter queue.

8. Мониторьте незарегистрированные чеки. Рост числа чеков в промежуточном состоянии указывает на сбой кассы либо связи.

Рекомендации:

  1. Не отправляйте чек повторно без уточнения. Дубль чека требует отмены, а уточнение состояния исключает дублирование.
  2. Храните фискальный признак. Признак требуется при разборе обращений и при сверке с данными кассы.
  3. Проверяйте ставку налога по позиции. Неверная ставка приводит к расхождению отчётности.
  4. Учитывайте недоступность кассы. Регистрация выполняется после восстановления связи, поэтому очередь неотправленных чеков обязательна.
  5. Документируйте состав чека. Правила распределения скидки и указания доставки фиксируются, поскольку влияют на отчётность.

Практический сценарий: дубль чека при повторной отправке

Контекст: в отчёте кассы оказались два чека по одному заказу с одинаковой суммой.

  1. Диагностика. В таблице чеков одна запись в состоянии sent, в отчёте кассы два зарегистрированных документа с разными фискальными номерами.
  2. Причина. Первый запрос регистрации выполнен успешно, но ответ не дошёл из-за таймаута. Повторная отправка выполнена с новым внешним идентификатором, поэтому касса зарегистрировала второй чек. Уточнение состояния перед повтором отсутствовало.
  3. Действия. (а) Зафиксировали внешний идентификатор чека до отправки и сделали его уникальным, чтобы повтор возвращал существующий документ; (б) добавили уточнение состояния по внешнему идентификатору перед повторной отправкой; (в) при таймауте перевели чек в состояние sent с уточнением по расписанию вместо немедленного повтора; (г) оформили отмену дубля чека через кассу; (д) добавили сверку числа чеков в отчёте кассы с числом зарегистрированных чеков в базе.
  4. Результат. Повторная отправка возвращает существующий чек, а расхождение с отчётом кассы обнаруживается сверкой.

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

FAQ

Когда формируется чек — при создании заказа или после оплаты? После подтверждения оплаты. Отменённый либо неуспешный платёж не требует регистрации.

Что делать, если ответ кассы не получен? Уточнить состояние по внешнему идентификатору. Повторная отправка без уточнения создаёт дубль чека.

Как оформляется частичный возврат? Чеком возврата на часть позиций. Исходный чек прихода не изменяется.

Что делать при недоступности кассы? Чек остаётся в очереди и регистрируется после восстановления связи. Мониторинг числа неотправленных чеков обязателен.

Источники: ФНС России (учёт и ККТ), АТОЛ API, PostgreSQL explicit locking — ссылки в шапке.