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çãoPráticas recomendadasrazão
A mesma interface precisa receber faturas e recibosMantenha dois contratos separados, selecionados com o campo de tipo obrigatórioUm objeto grande com todos os campos opcionais pode conter qualquer coisa, mas é difícil explicar o que é recebido.
Organize filiais com oneOfCada branch usa const para corrigir o tipooneOf 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 campoRetornar uma mensagem de erro clara mostrando campos e fontes conflitantesMostrar apenas "sem correspondência" não pode ajudar a localizar o problema
O classificador não consegue distinguir entre tipos de documentosRetenha o status desconhecido e entre na fila independente para ser classificadoEscolher uma filial aleatoriamente só produzirá um falso"sucesso"
Verificação de estrutura aprovadaIsso 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 entradaDúvidas reaisSugestões e comentários
tipo está faltandoNão foi possível selecionar o protocoloForneça o tipo de documento
Conflitos de tipo com campo numéricoAs duas estruturas são misturadasMostrar campos e fontes conflitantes
String vazia de númeroA chave existe, mas não tem valorOlhe novamente para a área numerada
tipo desconhecidoNão abrangido pelo acordo atualEntre 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áticaVocê pode esclarecer o tipo de documento?Comportamento quando as ramificações se sobrepõemLidando 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 camposFacilmente engolido por uma ampla variedade de objetos e difícil de detectar
Dois contratos independentes + tipo exigidoSeleção explícita via campo kindUse const para corrigir o valor e reduzir a sobreposiçãoMantenha 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

Atualizado em 2026-11-15