Короткий ответ: как предотвратить дублирование записей?
Присвойте каждой инспекционной работе неизменный исходный идентификатор; выполняйте передачу в ERP идемпотентно по этому идентификатору, принудительно обеспечьте уникальность в базе данных и связывайте с бухгалтерией только верифицированный целевой документ.
Недостаточно, чтобы интеграция работала только в нормальном режиме. При потере сетевого ответа, повторной доставке сообщения из очереди или получении одной работы двумя обработчиками результат также должен быть один клиент, один заказ и одна связь выставления счёта.
Почему возникает дублирование?
Короткий ответ: большинство дублей возникает не потому, что пользователь дважды нажал кнопку, а из-за неконтролируемого повтора в неопределённый момент, когда первый запрос завершился успешно, но его ответ был потерян.
Инспекционная система отправляет в ERP запрос на создание заказа. ERP создаёт запись, но соединение закрывается и интеграция не получает ответ. Если обработчик повторно отправит тот же запрос как новую операцию, может открыться второй заказ. Аналогичный риск наблюдается при доставке в очереди «как минимум один раз», параллельных обработчиках, ручном повторе после тайм-аута и пакетной синхронизации.
IETF RFC 9110 определяет идемпотентную операцию как операцию, при которой многократное применение одного и того же запроса оказывает то же целевое воздействие, что и одно применение. PUT обладает этим свойством; создание нового ресурса через POST требует дополнительной защиты. Технический проект не должен предполагать, что сеть доставляет сообщения ровно один раз.

Какой идентификатор должен быть владельцем записи?
Инспекционная работа, заказ ERP, бухгалтерская проводка и электронный документ — не один и тот же идентификатор. В начале цепочки должна быть неизменная UUID исходной работы ; идентификаторы, создаваемые другими системами, следует хранить отдельно как её соответствия.
| Идентификатор | Владелец | Когда возникает? | Использование |
|---|---|---|---|
| UUID исходной работы | Инспекционная система | При первом открытии работы | Неизменный ключ работы для всех передач и повторов |
| UUID события | Инспекционная система | При формировании версии, готовой к выставлению счёта | Сообщение очереди и контроль обработанных событий |
| ID клиента/заказа в ERP | ERP | При принятии целевой записи | Последующие обновления и запросы статуса |
| ID бухгалтерского документа | Бухгалтерская система | При создании черновика/записи документа | Финансовый жизненный цикл |
| UUID/номер электронного документа | Процесс электронного документооборота | При оформлении документа | Собственный технический идентификатор документа |
OASIS UBL 2.4 Invoice определяет ссылочные поля между счётом, заказом и другими документами. Руководство портала e-Fatura GİB также указывает, что счета с одинаковыми UUID и номером счёта не могут быть загружены повторно. Практический вывод состоит не в замене исходного инспекционного идентификатора номером электронного документа, а в хранении идентификаторов раздельно в двусторонней таблице соответствий.
Как формировать ключ идемпотентности?
Ключ не должен заново генерироваться случайно при каждом повторе; он должен оставаться одинаковым во всех попытках одной бизнес-операции. Пример области определения можно вывести из канонического объединения следующих частей:
tenant + hedef_sistem + işlem_türü + kaynak_iş_uuid + kaynak_sürümü
Важна версия источника. Повторная отправка той же версии отчёта должна возвращать существующий результат; если авторизованная редакция создаёт новое бизнес-воздействие, она должна быть отдельным событием с явным бизнес-правилом. Запись идемпотентности должна хранить рядом с ключом хеш полезной нагрузки, время первого появления, статус и идентификатор целевого ответа.
Актуальная справка API Stripe документирует, что после сбоя соединения запрос create/update можно безопасно повторить с тем же ключом идемпотентности, а если ключ тот же, но параметры изменились, запрос отклоняется. Это поведение, характерное для конкретного провайдера, полезно и как образец контракта для внутреннего ERP-адаптера: если тот же ключ приходит с другим клиентом, суммой или налоговым сопоставлением, не перезаписывайте молча; направьте конфликт на анализ.
Почему контроля на уровне приложения недостаточно?
При подходе «сначала проверь наличие, затем вставь» два обработчика одновременно могут увидеть отсутствие записи. Уникальность должна принудительно обеспечиваться и в базе данных.
В таблице связей интеграции создайте составное ограничение уникальности по tenant_id + target_system + document_type + source_job_uuid . Актуальная документация PostgreSQL по INSERT поясняет, что при наличии ограничения уникальности оператор ON CONFLICT позволяет атомарно выполнить вставку или обновление при конкурирующих запросах. Если бизнес-правило запрещает обновление, при конфликте верните ID существующей целевой записи; при расхождении данных остановите обработку и создайте запись для разбора.
UNIQUE (tenant_id, target_system, document_type, source_job_uuid)
aynı anahtar + aynı payload özeti -> mevcut sonucu döndür
aynı anahtar + farklı payload -> çakışma, otomatik belge açmaКак организовать Outbox и обработку очереди?
Если отдельно переводить инспекционный отчёт в состояние «готов к выставлению счёта» и записывать сообщение для ERP, операция может завершиться лишь частично. Состояние бизнес-процесса и событие интеграции следует фиксировать в одной локальной транзакции.
- Уполномоченный пользователь подтверждает версию отчёта и объём выставляемых услуг.
- Приложение в одной транзакции обновляет бизнес-состояние и добавляет запись Outbox с UUID события.
- Обработчик отправляет событие Outbox целевому адаптеру с неизменным ключом идемпотентности.
- При успешном ответе ID объекта в ERP и сведения об ответе сохраняются в таблице связей.
- Если подтверждение ACK потеряно, событие приходит повторно; потребитель распознаёт UUID события и бизнес-связь и возвращает существующий результат.
- Постоянную ошибку данных не следует помещать в цикл повторных попыток: её направляют на разбор или в очередь необрабатываемых сообщений, dead-letter.
Руководство Microsoft по Transactional Outbox рекомендует сохранять бизнес-объект и событие в одной транзакции. Руководство Service Bus поясняет, что из-за потери ACK и повторной доставки потребитель должен обеспечивать идемпотентность по MessageId или бизнес-идентификатору. Обнаружение дубликатов у отправителя не заменяет проверку уникальности у получателя.
Как безопасно сопоставлять клиентов, услуги и налоги?
Предотвращение дублей не сводится к техническим повторным попыткам. Повторное создание клиента из-за другого написания названия или выставление одной услуги под разными кодами также приводит к дублированию операций.
- Клиент: сопоставляйте записи в пределах организации по проверенному турецкому налоговому или личному идентификатору VKN/TCKN либо по ключу справочника клиентов; одного названия недостаточно.
- Услуга: свяжите метод контроля с утверждённым справочником номенклатуры или услуг ERP; не создавайте отсутствующий код автоматически из произвольного текста.
- Налоги и валюта: используйте версионируемое сопоставление со справочниками целевой системы; при отсутствующем или недопустимом соответствии остановите формирование документа.
- Сумма: зафиксируйте рассчитанные строки, скидки и налоги вместе с хешем исходной версии; изменения после утверждения проводите через новую ревизию.
- Полномочия: разграничьте роли создания клиентов, изменения сопоставлений и формирования финансовых документов, сохраняя отдельные аудиторские следы.
При неоднозначном сопоставлении нельзя автоматически выбирать «ближайший результат». Передачу следует приостановить до завершения проверки человеком; для решения сохранить автора, время, прежнее и новое значение и обоснование.
Как отслеживать состояние передачи?
Единственное поле «успешно/неуспешно» скрывает неопределённость. Модель состояний должна показывать, какой этап допускает повторное выполнение.
| Состояние | Значение | Допустимое действие |
|---|---|---|
| Подготовка | Проверяются сопоставления и данные запроса | Устранить недостающие или ошибочные данные |
| Готово к отправке | Идентификатор, версия и хеш данных запроса зафиксированы | Поместить в Outbox |
| Результат не определён | Истекло время ожидания, но операция могла выполниться в целевой системе | Запросить результат или повторить с тем же ключом |
| Передано | ID целевой записи и подтверждение ответа сохранены | Проверить состояние, не создавать копию |
| Требуется разбор | Конфликт ключа или ошибка сопоставления данных | Дождаться решения уполномоченного лица |
| Ожидается отмена или сторнирование | Необходима финансовая корректировка | Выполнить отдельную операцию по правилам целевой системы |
Удаление записи об успешной передаче с последующей повторной отправкой не является способом исправления. Если финансовый документ уже создан, отмена, возврат или сторнирование должны иметь собственный идентификатор и маршрут согласования.
Какие проверки должна выполнять сверка?
Ежедневная сверка должна сопоставлять записи исходной и целевой систем по идентификаторам, а не только подсчитывать ошибки в журнале.
- Задания, готовые к выставлению счёта, но не связанные с целевой записью.
- Несколько целевых документов, связанных с одним UUID исходного задания.
- Документы, присутствующие в целевой системе, но отсутствующие в исходной таблице связей.
- Записи, в которых исходная версия не соответствует хешу переданных данных.
- Попытки, остающиеся в неопределённом состоянии дольше установленного срока.
- Отсутствующие согласования или подтверждения ручных сопоставлений, отмен и сторнирований.
По результатам сверки нельзя автоматически удалять или массово объединять записи. Уполномоченному пользователю следует показать подозрительные записи, их идентификаторы в обеих системах и предлагаемое безопасное действие.
Как провести пилот интеграции VizyonTech?
Vizyon Periyodik и аналогичные инспекционные процессы при подключении к ERP следует проверять прежде всего на сбои, а затем — в штатном режиме. Испытайте двойное нажатие для одного задания, создание записи в ERP без ответа, получение одного сообщения двумя обработчиками, повторное использование ключа с другими данными, ошибочное сопоставление клиента и ревизию отчёта.
Критерий успеха пилота — не просто «интеграция работает». В каждом сценарии необходимо подтвердить число созданных целевых записей, наличие связи между источником и получателем, возврат того же результата при повторе, видимость неопределённого состояния и блокировку неразрешённых финансовых операций. Для сохранения цепочки решений по инспекционному отчёту также полезно изучить руководство по процессу электронной подписи вместе с проектируемой интеграцией.
Источники
- IETF — RFC 9110, семантика HTTP: идемпотентные методы (июнь 2022 года; дата обращения: 21 июля 2026 года).
- Stripe — Идемпотентные запросы, справочник API (актуальная онлайн-документация; дата обращения: 21 июля 2026 года).
- Microsoft Learn — Предотвращение потери сообщений и повторной обработки в Azure Service Bus (обновлено 29 июня 2026 года).
- Microsoft Learn — Реализация шаблона Transactional Outbox (2026 год; дата обращения: 21 июля 2026 года).
- PostgreSQL — INSERT и ON CONFLICT, актуальная документация (дата обращения: 21 июля 2026 года).
- OASIS — Обзор модели Invoice в UBL 2.4 (2024).
- Налоговая администрация Турции — Руководство пользователя портала электронных счетов v1.5 (ноябрь 2013 года; сведения о технических идентификаторах и правилах повторной загрузки, дата обращения: 21 июля 2026 года).
Правила полей и кодов ERP, бухгалтерского учёта и электронных документов необходимо дополнительно сверять с актуальной технической документацией используемого поставщика и финансовыми процедурами организации.