Банковские транзакции: Почему ссылки на оплату в Ощадбанке (orderId) часто дублируются в логах и как отслеживать их статус по времени (PlanConnectLater)?
При интеграции платёжного шлюза Ощадбанка разработчики нередко сталкиваются с ситуацией, когда один и тот же идентификатор заказа (orderId) появляется в логах несколько раз. Это создаёт путаницу при анализе транзакций и может приводить к ошибкам в бизнес-логике приложения.
## Почему дублируются записи с одним orderId?
**1. Повторные запросы от клиента.** Если пользователь несколько раз нажимает кнопку оплаты или браузер выполняет автоматический повтор запроса (retry), платёжная система получает несколько обращений с одним и тем же orderId. Ощадбанк в этом случае либо возвращает уже существующую ссылку на оплату, либо фиксирует каждый запрос отдельной записью в журнале.
**2. Механизм повторных попыток на стороне сервера.** Многие серверные фреймворки и очереди задач (например, RabbitMQ, Kafka, Celery) автоматически повторяют задачу при отсутствии подтверждения. Если обработчик не получил ответ от API Ощадбанка вовремя, он инициирует повторный вызов с тем же orderId.
**3. Асинхронные webhook-уведомления.** Ощадбанк может отправлять несколько уведомлений об одном и том же событии (например, «транзакция в обработке», «транзакция подтверждена»). Каждое из них попадает в лог с одним orderId, но разным статусом.
**4. Отсутствие идемпотентности в коде.** Если на стороне приложения не реализована проверка уникальности orderId перед созданием новой записи, каждый входящий запрос записывается заново.
## Как правильно отслеживать статус транзакции по времени (PlanConnectLater)?
Концепция **PlanConnectLater** предполагает отложенную проверку статуса транзакции — когда вместо синхронного ожидания ответа система планирует повторный опрос через определённый интервал времени.
**Рекомендуемый алгоритм:**
1. **Сохраняйте время создания ссылки.** При генерации платёжной ссылки фиксируйте `created_at` и `expires_at` для каждого orderId.
2. **Используйте уникальный индекс на orderId** в базе данных, чтобы исключить физическое дублирование записей.
3. **Планируйте отложенные задачи.** После создания транзакции добавляйте задачу в планировщик (cron, Celery beat, pg_cron) с проверкой статуса через 5, 15 и 60 минут.
4. **Реализуйте идемпотентную обработку webhook.** Перед записью нового статуса проверяйте, не является ли входящее событие более старым, чем последнее сохранённое состояние (сравнивайте `updated_at`).
5. **Логируйте все изменения статуса** с временными метками: `PENDING → PROCESSING → SUCCESS/FAILED`. Это позволит построить полный timeline транзакции.
6. **Используйте API проверки статуса Ощадбанка** (`/api/v1/merchant/order/status`) с передачей orderId для получения актуального состояния вместо доверия только webhook.
## Итог
Дублирование orderId в логах — это нормальное явление при асинхронной обработке платежей, но его необходимо контролировать. Ключ к надёжному мониторингу — идемпотентность обработчиков, временны́е метки на каждом изменении статуса и плановые отложенные проверки (PlanConnectLater), которые гарантируют актуальность данных даже при потере webhook-уведомлений.
