Рахунки-фактури та квитанції мають один вхід. Як уникнути змішування двох структур?
Один інтерфейс отримує як рахунки-фактури, так і квитанції, і легко писати великі об’єкти за допомогою «всі поля необов’язкові». Такий предмет може вмістити що завгодно, але складно сказати, що саме він отримав. Було б зрозуміліше зберегти два окремих контракти та вибрати один із них із явним полем типу.
Рахунки-фактури та квитанції часто поміщаються в один інтерфейс для обробки, але якщо для їх отримання використовується лише широкий об’єкт із «усі поля необов’язкові», він може вмістити будь-який вхід, але не може визначити, який документ отримано. Ця стаття призначена для розробників і бізнес-персоналу, яким потрібно розробити інтерфейс отримання документів або підтримувати правила перевірки схеми 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, щоб тип внесеного документа був чітко видимий. Перевірка гілок, зворотний зв'язок на помилки та експорт невідомих типів також слід проектувати разом.
Досвід зараз: завантажте документ, щоб почати переклад, зберігаючи оригінальне форматування


