Faturas e recibos compartilham a mesma entrada. Como evitar misturar as duas estruturas?
Uma interface recebe faturas e recibos e é fácil escrever objetos grandes com "todos os campos opcionais". Tal objeto pode conter qualquer coisa, mas é difícil dizer exatamente o que foi recebido. Seria mais claro manter dois contratos separados e selecionar um deles com o campo de tipo explícito.
Faturas e recibos são frequentemente colocados na mesma interface para processamento, mas se apenas um objeto amplo com "todos os campos opcionais" for usado para recebê-los, ele poderá acomodar qualquer entrada, mas não poderá dizer que tipo de documento será recebido. Este artigo é destinado a desenvolvedores e profissionais de negócios que precisam projetar uma interface de recebimento de documentos ou manter regras de validação do esquema JSON. Depois de ler isto, você aprenderá como manter dois contratos independentes, selecionar um com um campo de tipo explícito e lidar com conflitos de ramificação e tipos desconhecidos.
Os exemplos neste artigo utilizam amostras sintéticas para demonstrar métodos de processamento. O código foi verificado com exemplos em um ambiente isolado, mas isso não é garantia de todos os arquivos reais ou do desempenho do produto. Antes de processar documentos importantes, guarde os originais e revise-os de acordo com os limites e itens de aceitação do texto.
Como lidar com a entrada compartilhada de faturas e recibos? Conclusão de uma frase
Ao receber dois documentos do mesmo portal, fica mais claro manter dois contratos separados e utilizar o campo obrigatório kind para selecionar um deles, ao invés de utilizar um objeto amplo que possa conter tudo.
| sua situação | Práticas recomendadas | razão |
|---|---|---|
| A mesma interface precisa receber faturas e recibos | Mantenha dois contratos separados, selecionados com o campo de tipo obrigatório | Um objeto grande com todos os campos opcionais pode conter qualquer coisa, mas é difícil explicar o que é recebido. |
| Organize filiais com oneOf | Cada branch usa const para corrigir o tipo | oneOf requer que exatamente uma ramificação seja correspondida. A sobreposição de campos de ramificação causará falha na entrada legal. |
| Insira tipo ausente ou conflito de campo | Retornar uma mensagem de erro clara mostrando campos e fontes conflitantes | Mostrar apenas "sem correspondência" não pode ajudar a localizar o problema |
| O classificador não consegue distinguir entre tipos de documentos | Retenha o status desconhecido e entre na fila independente para ser classificado | Escolher uma filial aleatoriamente só produzirá um falso"sucesso" |
| Verificação de estrutura aprovada | Isso não significa que a classificação esteja correta, nem que os documentos sejam autênticos. | A confiança na classificação, a verificação da estrutura e a autenticidade do negócio são três níveis diferentes |
Por que você não pode usar um objeto amplo?
Risco de tornar todos os campos opcionais
Quando uma interface aceita faturas e recibos, é fácil escrever objetos grandes com"todos os campos opcionais". Tal objeto pode de fato receber uma variedade de insumos, mas ao custo de:
- É impossível saber pela estrutura qual documento é recebido.
- Os itens obrigatórios e opcionais dos dois documentos se misturam e as regras de verificação ficam cada vez mais confusas.
- Quando ocorre um erro, é difícil explicar exatamente onde a entrada não é a esperada.
Seria mais claro manter dois contratos separados e selecionar um deles com um campo de tipo explícito.
oneOf não é qualquer um
Ramos sobrepostos causarão falha na entrada legal.
oneOf requer que a entrada corresponda exatamente a uma ramificação. Se ambas as ramificações passarem ao mesmo tempo, a verificação geral falhará.
Se as ramificações contiverem apenas alguns campos opcionais, é provável que se sobreponham significativamente. Neste momento, a contribuição jurídica não passa na verificação.
Use kind e const para eliminar sobreposição
Usar o campo kind obrigatório mais o valor fixo de const pode estabelecer limites claros entre filiais e eliminar tais sobreposições antecipadamente.
Para obter mais detalhes sobre as regras de combinação, consulte Regras de combinação do esquema JSON.
Um protocolo de descarregamento executável
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"})
Este é um registro de exemplo simplificado e não um modelo de campo completo de uma fatura real. O código demonstra a seleção de ramificações e a rejeição de campos redundantes. A taxa de imposto, cabeçalho e valor precisam ser definidos separadamente.
Se a empresa permitir campos adicionais, os namespaces para esses campos deverão ser explicitados, em vez de cancelar silenciosamente todas as restrições.
Não exiba apenas"sem correspondência"na mensagem de erro
Apenas "incompatibilidade" é exibida e nem os usuários nem os mantenedores sabem onde está o problema. A tabela a seguir lista vários recursos de entrada comuns e métodos de feedback correspondentes:
| Recursos de entrada | Dúvidas reais | Sugestões e comentários |
|---|---|---|
| tipo está faltando | Não foi possível selecionar o protocolo | Forneça o tipo de documento |
| Conflitos de tipo com campo numérico | As duas estruturas são misturadas | Mostrar campos e fontes conflitantes |
| String vazia de número | A chave existe, mas não tem valor | Olhe novamente para a área numerada |
| tipo desconhecido | Não abrangido pelo acordo atual | Entre na fila de espera independente |
Tipos indeterminados também precisam de uma saída
Se o classificador não conseguir distinguir entre faturas e recebimentos, ele deverá deixar o estado desconhecido em vez de escolher um ramo aleatório para adivinhar o"sucesso".
Existem três níveis diferentes aqui que precisam ser analisados separadamente:
- Confiança da classificação: quão confiante é o sistema ao julgar o tipo de documento.
- Verificação da Estrutura: Se o insumo está em conformidade com o contrato selecionado.
- Autenticidade Comercial: Se o documento em si é autêntico e válido.
A aprovação na verificação estrutural não pode provar que a classificação está correta, nem pode provar que o documento é autêntico.
O tipo de documento também deve ser mantido no processo de tradução
O mesmo campo pode precisar usar termos diferentes em documentos diferentes. Ao usar a terminologia e os fluxos de trabalho de revisão bilíngues do OmniDoc, fornecer o tipo de documento junto com a lista de entrega ajuda os revisores a compreender o contexto dos números e valores.
Não deixe que um objeto JSON amplo apague essas diferenças.
📊 Comparação principal
| prática | Você pode esclarecer o tipo de documento? | Comportamento quando as ramificações se sobrepõem | Lidando com tipos desconhecidos |
|---|---|---|---|
| Um objeto amplo com todos os campos opcionais | É difícil explicar o que recebi. | Não aplicável, sem limites de ramificação entre os campos | Facilmente engolido por uma ampla variedade de objetos e difícil de detectar |
| Dois contratos independentes + tipo exigido | Seleção explícita via campo kind | Use const para corrigir o valor e reduzir a sobreposição | Mantenha o status desconhecido e entre na fila para ser classificado |
🎯 Qual método é adequado para você?
Se você precisar receber faturas e recibos
Mantenha dois contratos separados e torne kind um campo obrigatório.
Se os campos da sua filial se sobrepõem muito
Corrija kind com const em cada filial para evitar que entradas legais correspondam a várias filiais ao mesmo tempo.
Se o seu sistema permitir campos adicionais
Primeiro esclareça o namespace dos campos adicionais e depois decida como relaxar as restrições.
Se o seu classificador não estiver confiante o suficiente
Deixe o status desconhecido, envie o documento para a fila para classificação e não selecione uma filial à força.
❓ Perguntas frequentes (FAQ)
1. Por que não usar apenas um objeto com todos os campos opcionais?
Tal objeto pode conter qualquer coisa, mas é difícil dizer exatamente o que foi recebido.
2. Por que oneOf falha na contribuição jurídica?
oneOf requer a correspondência de exatamente uma ramificação. Se ambas as ramificações passarem ao mesmo tempo, a verificação geral falhará. Essa situação pode ocorrer facilmente quando os campos de ramificação se sobrepõem muito.
3. O que você deve prestar atenção ao permitir campos adicionais?
O namespace de campos adicionais deve ser explicitado em vez de cancelar silenciosamente todas as restrições.
4. O que devo fazer se o classificador não conseguir determinar o tipo de documento?
Mantenha o estado desconhecido e entre em uma fila independente para ser classificado. Não selecione um ramo aleatoriamente para obter sucesso.
5. Se a verificação da estrutura for aprovada, isso significa que o documento é autêntico?
não pode. A confiança na classificação, a verificação da estrutura e a autenticidade do negócio são três níveis diferentes. A aprovação da estrutura não pode provar que o documento é autêntico.
📝 Resumo
Ao colocar faturas e recibos na mesma entrada, mantenha dois contratos separados e selecione-os com o campo kind obrigatório para que o tipo de documento inserido fique claramente visível. Verificação de ramificação, feedback de erro e saídas de tipo desconhecido também devem ser projetadas em conjunto.
Experimente agora: carregue o documento para iniciar a tradução, mantendo o layout original


