Счета-фактуры и квитанции имеют один и тот же вход. Как избежать смешивания двух структур?
Один интерфейс получает как счета, так и квитанции, и легко писать большие объекты, где «все поля необязательны». Такой объект может содержать что угодно, но что именно он получен, сказать сложно. Было бы проще сохранить два отдельных контракта и выбрать один из них с явным полем типа.
— oneOf требует сопоставления ровно одной ветки, и одновременное прохождение двух ветвей также будет расценено как неудача.
- Когда тип документа невозможно различить, его следует оставить в неизвестном статусе и внести в независимую очередь для классификации, а не выбирать ветви случайным образом.
- Прохождение структурной проверки не может доказать правильность классификации и подлинность документа.
Счета-фактуры и квитанции часто помещаются в один и тот же интерфейс для обработки, но если для их получения используется только широкий объект со «всеми необязательными полями», он может вместить любые входные данные, но не может сказать, какой тип документа получен. Эта статья предназначена для разработчиков и бизнес-персонала, которым необходимо разработать интерфейс получения документов или поддерживать правила проверки схемы JSON. Прочитав это, вы узнаете, как сохранить два независимых контракта, выбрать один с явным полем типа и обрабатывать конфликты ветвей и неизвестные типы.
В примерах в этой статье используются синтетические образцы для демонстрации методов обработки. Код проверен на примерах в изолированной среде, но это не является гарантией работоспособности всех реальных файлов или продукта. Перед обработкой важных документов, пожалуйста, сохраните оригиналы и просмотрите их по границам и пунктам приема в тексте.
Как быть с общим входом счетов и квитанций? Вывод в одно предложение
При получении двух документов с одного портала удобнее хранить два отдельных контракта и использовать обязательное поле kind для выбора одного из них, а не использовать широкий объект, который может содержать все.
| твоя ситуация | Рекомендуемые практики | причина |
|---|---|---|
| Для получения счетов и квитанций необходим один и тот же интерфейс. | Сохраняйте два отдельных контракта, выбранных с помощью поля необходимого типа. | Большой объект со всеми необязательными полями может содержать что угодно, но сложно объяснить, что получено. |
| Организуйте филиалы с помощью oneOf | Каждая ветка использует const для исправления вида. | oneOf требует сопоставления ровно одной ветки. Перекрытие полей ветвей приведет к сбою допустимого ввода. |
| Отсутствует тип ввода или конфликт полей. | Вернуть четкое сообщение об ошибке, показывающее конфликтующие поля и источники. | Только отображение «нет совпадений» не может помочь обнаружить проблему. |
| Классификатор не может различать типы документов | Сохраните неизвестный статус и войдите в независимую очередь для классификации. | Случайный выбор ветки приведет только к фальшивому «успеху». |
| Проверка структуры пройдена | Это не означает, что классификация правильная, и не означает, что документы подлинные. | Достоверность классификации, проверка структуры и деловая подлинность — это три разных уровня. |
Почему нельзя использовать широкий объект?
Риск сделать все поля необязательными
Когда интерфейс принимает как счета, так и квитанции, легко писать большие объекты со словами «все поля необязательны». Такой объект действительно может получать различные входные данные, но за счет:
- По структуре невозможно определить, какой документ получен.
- Обязательные и необязательные пункты двух документов перемешиваются между собой, а правила проверки становятся все более размытыми.
- При возникновении ошибки сложно объяснить, где именно ввод не соответствует ожиданиям.
Было бы проще сохранить два отдельных контракта и выбрать один из них с явным полем типа.
OneOf — это не просто один из них
Перекрывающиеся ветви могут привести к действительным сбоям ввода
oneOf требует, чтобы вход совпадал ровно с одной ветвью. Если обе ветви проходят одновременно, общая валидация также провалится.
Если ветвь содержит лишь несколько необязательных полей, они, скорее всего, будут сильно пересекаться. На этом этапе легитимный ввод фактически не проходит проверку.
Используйте вид и конст, чтобы устранить пересечение
Используя необходимое поле kind плюс const для фиксации значений, можно установить чёткие границы между ветвями и заранее устранить такие пересечения.
Для получения дополнительной информации о правилах комбинации см. Правила комбинации JSON-схемы.
Исполняемый протокол отклонения
from jsonschema import Draft202012Validator
def branch(kind, identity):
return {
"type": "object", "additionalProperties": False,
"required": ["kind", identity],
"properties": {"kind": {"const": kind},
identity: {"type": "string", "minLength": 1}}
}
schema = {"oneOf": [branch("invoice", "invoice_number"),
branch("receipt", "receipt_number")]}
v = Draft202012Validator(schema)
valid = lambda x: not list(v.iter_errors(x))
assert valid({"kind": "invoice", "invoice_number": "I-1"})
assert valid({"kind": "receipt", "receipt_number": "R-1"})
assert not valid({"kind": "invoice", "receipt_number": "R-1"})
assert not valid({"kind": "receipt", "receipt_number": ""})
assert not valid({"kind": "invoice", "invoice_number": "I-1",
"receipt_number": "R-1"})
assert not valid({"kind": "unknown"})
Это упрощённый пример записи, а не полная модель реального счета. Код демонстрирует выбор ветвей и отклонение избыточных полей; налоговые ставки, заголовки и суммы необходимо определять отдельно.
Если бизнес допускает дополнительные поля, пространства имён для этих полей должны быть чётко определены, а не тихо снимать все ограничения.
Не просто показывайте сообщения об ошибках «несоответствие»
Отображается только «несоответствие», и ни пользователи, ни обслуживающий персонал не могут знать, в чём заключается проблема. В таблице ниже перечислены несколько распространённых функций ввода и соответствующие им методы обратной связи:
| Входные функции | Реальные сомнения | Предлагайте обратную связь |
|---|---|---|
| Вид дефицита | Не могу выбрать соглашение | Пожалуйста, укажите тип документа |
| Конфликт типовых и числовых полей | Обе конструкции смешаны | Отображать противоречивые поля и их источники |
| Пронумерованные пустые строки | Ключ существует, но не имеет ценности | Оглядываясь назад на нумерованную область |
| Неизвестный тип | Текущее соглашение не охватывает это | Войдите в независимую очередь для классификации |
Неопределённым типам тоже нужен выход
Если классификатор не может отличить счета от чеков, статус неизвестности следует сохранять, а не случайно выбирать ветку для «успеха».
Здесь есть три разных уровня, которые необходимо рассматривать отдельно:
- Категорическая уверенность: Насколько уверенно система оценивает типы документов.
- Проверка структуры: Введите, выполнен ли выбранный контракт.
- Бизнес-аутентичность: Являются ли сами документы подлинными и действительными.
Структурная проверка не может быть обратно доказана как верность, так же как и не может доказать подлинность документа.
Тип документа также должен сохраняться в процессе перевода
Одна и та же область может требовать разной терминологии в разных документах. При использовании терминологии OmniDoc и билингвальных рабочих процессов рецензирования предоставление типов документов с расписаниями помогает рецензентам понять контекст количества и суммы.
Не позволяйте широкому JSON-объекту стереть эти различия.
📊 Сравнение ядра
| Метод | Можно ли чётко определить тип документа? | Проявления при пересечении ветвей | Обработка неизвестных типов |
|---|---|---|---|
| Широкие объекты с опциональными полями | Трудно объяснить, что именно было получено | Не применимо; между полями нет границ ветвей | Легко проглатываемый широкими целями и едва заметный |
| Два независимых контракта + обязательный вид | Чётко выбирайте с помощью поля вида | Используйте const для фиксации значений и уменьшения пересечения | Оставьте статус неизвестного и зарегистрируйтесь в очередь для сортировки |
🎯 Какой способ тебе подходит?
Если вам нужно одновременно получать и счета, и чеки
Ведите два отдельных контракта и укажите kind как обязательное поле.
Если ваши поля ветвей сильно пересекаются
Исправьте kind с const в каждой ветке, чтобы избежать совпадения легитимных входов с несколькими ветвлениями одновременно.
Если ваша система допускает дополнительные поля
Сначала уточните пространство имён дополнительного поля, затем решите, как ослабить ограничения.
Если ваш классификатор недостаточно уверен
Сохраняйте статус неизвестности и отправляйте документы в очередь для сортировки; не выбирайте ветки насильственно.
❓ Часто задаваемые вопросы (FAQ)
1. Почему бы просто не использовать объект, где все поля необязательны?
Такой партнёр может подделать что угодно, но сложно понять, что именно он получает.
2. Почему oneOf приводит к ошибке действительной записи?
oneOf требует точного соответствия ветви. Если обе ветви проходят одновременно, общая проверка провалится. Эта ситуация, скорее всего, возникает, когда ветвления полей сильно перекрываются.
3. На что следует обращать внимание, разрешая дополнительные поля?
Пространство имён для дополнительного поля должно быть чётко определено, а не тихо устранять все ограничения.
4. Что если классификатор не может определить тип документа?
Сохраняйте статус неизвестности и вводите независимую очередь для классификации; не выбирайте ветку случайным образом для сборки успешной ветки.
5. Подтверждает ли прохождение структурной проверки подлинность документов?
Нет. Секретность классификации, структурная проверка и бизнес-аутентичность — это три отдельных уровня; структурная проверка не может доказать подлинность документов.
📝 Краткое содержание
При размещении счетов и чеков в одной записи ведите два отдельных контракта и выбирайте их с помощью нужного поля kind, чтобы тип введённого документа был чётко виден. Верификация ветвей, обратная связь по ошибкам и экспорт неизвестных типов также должны проектироваться вместе.
Опыт сейчас: загрузите документ, чтобы начать перевод, сохраняя оригинальное форматирование


