Facturas y recibos comparten la misma entrada. ¿Cómo evitar mezclar las dos estructuras?
Una interfaz recibe facturas y recibos, y es fácil escribir objetos grandes con "todos los campos opcionales". Un objeto así puede contener cualquier cosa, pero es difícil decir exactamente qué se recibe. Sería más claro mantener dos contratos separados y seleccionar uno de ellos con el campo de tipo explícito.
Las facturas y los recibos a menudo se colocan en la misma interfaz para su procesamiento, pero si solo se usa un objeto amplio con "todos los campos opcionales" para recibirlos, puede acomodar cualquier entrada, pero no puede decir qué tipo de documento se recibe. Este artículo está dirigido a desarrolladores y personal empresarial que necesitan diseñar una interfaz de recepción de documentos o mantener reglas de validación de esquemas JSON. Después de leer esto, aprenderá cómo mantener dos contratos independientes, seleccionar uno con un campo de tipo explícito y manejar conflictos de rama y tipos desconocidos.
Los ejemplos de este artículo utilizan muestras sintéticas para demostrar los métodos de procesamiento. El código se ha verificado con ejemplos en un entorno aislado, pero esto no es garantía de todos los archivos reales ni del rendimiento del producto. Antes de procesar documentos importantes, conserve los originales y revíselos de acuerdo con los límites y elementos de aceptación del texto.
¿Cómo afrontar la entrada compartida de facturas y recibos? Conclusión de una frase
Al recibir dos documentos del mismo portal, es más claro mantener dos contratos separados y usar el campo kind requerido para seleccionar uno de ellos, en lugar de usar un objeto amplio que pueda contener todo.
| tu situación | Prácticas recomendadas | razón |
|---|---|---|
| La misma interfaz necesita recibir facturas y recibos. | Mantenga dos contratos separados, seleccionados con el campo de tipo requerido | Un objeto grande con todos los campos opcionales puede contener cualquier cosa, pero es difícil explicar lo que se recibe. |
| Organizar sucursales con oneOf | Cada rama usa const para arreglar el tipo. | oneOf requiere que coincida exactamente una rama. La superposición de campos de rama hará que la entrada legal falle. |
| Tipo de entrada faltante o conflicto de campo | Devuelve un mensaje de error claro que muestra campos y fuentes en conflicto | Mostrar únicamente "no coincide" no puede ayudar a localizar el problema |
| El clasificador no puede distinguir entre tipos de documentos | Conservar el estado desconocido e ingresar a la cola independiente para ser clasificado | Elegir una sucursal al azar solo producirá un "éxito" falso |
| Verificación de estructura aprobada | No significa que la clasificación sea correcta, ni tampoco que los documentos sean auténticos. | La confianza en la clasificación, la verificación de la estructura y la autenticidad empresarial son tres niveles diferentes. |
¿Por qué no puedes usar un objeto amplio?
Riesgo de hacer que todos los campos sean opcionales
Cuando una interfaz acepta facturas y recibos, es fácil escribir objetos grandes con "todos los campos opcionales". De hecho, un objeto de este tipo puede recibir una variedad de entradas, pero a costa de:
- Es imposible saber por la estructura qué documento se recibe.
- Los elementos obligatorios y opcionales de los dos documentos se mezclan entre sí y las reglas de verificación son cada vez más confusas.
- Cuando ocurre un error, es difícil explicar exactamente dónde la entrada no es la esperada.
Sería más claro mantener dos contratos separados y seleccionar uno de ellos con un campo de tipo explícito.
oneOf no es uno cualquiera
La superposición de ramas hará que la entrada legal falle.
oneOf requiere que la entrada coincida exactamente con una rama. Si ambas ramas pasan al mismo tiempo, la verificación general fallará.
Si las ramas contienen sólo unos pocos campos opcionales, es probable que se superpongan significativamente. En este momento, los datos legales no pasan la verificación.
Utilice tipo y constante para eliminar la superposición
El uso del campo kind requerido más el valor fijo de const puede establecer límites claros entre ramas y eliminar dichas superposiciones de antemano.
Para obtener más detalles sobre las reglas de combinación, consulte Reglas de combinación de esquemas JSON.
Un protocolo de descarga ejecutable
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 es un registro de ejemplo simplificado y no es un modelo de campo completo de una factura real. El código demuestra la selección de ramas y el rechazo de campos redundantes. La tasa impositiva, el encabezado y el monto deben definirse por separado.
Si la empresa permite campos adicionales, los espacios de nombres para estos campos deben hacerse explícitos en lugar de cancelar silenciosamente todas las restricciones.
No muestres simplemente "no hay coincidencia" en el mensaje de error
Sólo se muestra "no coincide" y ni los usuarios ni los mantenedores saben dónde radica el problema. La siguiente tabla enumera varias características de entrada comunes y los métodos de retroalimentación correspondientes:
| Características de entrada | Dudas reales | Sugiere comentarios |
|---|---|---|
| Una especie de deficiencia | No se puede elegir el acuerdo | Por favor, proporcione el tipo de documento |
| Conflicto entre los campos de tipo y número | Las dos estructuras se mezclan | Mostrar campos en conflicto y sus fuentes |
| Cadenas vacías numeradas | La clave existe pero no tiene valor | Mirando atrás al área numerada |
| Tipo desconocido | El acuerdo actual no cubre esto | Entra en la cola independiente para ser clasificado |
Los tipos inciertos también necesitan una salida
Si el clasificador no puede distinguir entre facturas y recibos, el estado desconocido debe mantenerse en lugar de seleccionar aleatoriamente una sucursal para lograr un "éxito".
Aquí hay tres niveles diferentes que deben considerarse por separado:
- Confianza en categorías: Qué confianza tiene el sistema al juzgar los tipos de documentos.
- Verificación de estructura: Introduce si se cumple el contrato seleccionado.
- Autenticidad empresarial: Si los documentos en sí son auténticos y válidos.
La verificación estructural no puede demostrarse a la inversa como correcta, ni puede demostrar que el documento sea genuino.
El tipo de documento también debe mantenerse en el proceso de traducción
El mismo campo puede requerir terminología diferente en distintos documentos. Al utilizar terminología OmniDoc y flujos de trabajo bilingües de revisiones, proporcionar tipos de documentos con listas de entrega ayuda a los revisores a entender el contexto del número y la cantidad.
No dejes que un objeto JSON amplio borre estas diferencias.
📊 Comparación de núcleos
| Método | ¿Se puede definir claramente el tipo de documento? | Manifestaciones cuando las ramas se solapan | Manejo de tipos desconocidos |
|---|---|---|---|
| Objetos amplios con todos los campos opcionales | Es difícil explicar qué se recibió | No aplicable; no existen límites de rama entre campos | Fácil de tragar por objetivos anchos y difícil de notar |
| Dos contratos independientes + tipo requerido | Selecciona claramente usando el campo kind | Utiliza const para fijar valores y reducir la superposición | Deja el estado desconocido y entra en la cola para ser ordenado |
🎯 ¿Qué método te conviene?
Si necesitas recibir tanto facturas como recibos al mismo tiempo
Mantén dos contratos separados y establece kind como campo obligatorio.
Si tus campos de rama se solapan extensamente
Arregla kind con const en cada rama para evitar que la entrada legítima coincida con múltiples ramas simultáneamente.
Si tu sistema permite campos adicionales
Primero, aclarar el espacio de nombres del campo adicional y luego decidir cómo relajar las restricciones.
Si tu clasificador no está lo suficientemente seguro
Conserva el estado desconocido y envía documentos a la cola para que los ordenen; no selecciones sucursales a la fuerza.
❓ Preguntas frecuentes (FAQ)
1. ¿Por qué no usar simplemente un objeto donde todos los campos sean opcionales?
Una pareja así puede fingir cualquier cosa, pero es difícil saber exactamente qué recibe.
2. ¿Por qué OneOf causa un fallo válido de entrada?
oneOf requiere que empareje exactamente una rama. Si ambas ramas pasan simultáneamente, la comprobación general fallará. Esta situación es probable que ocurra cuando los campos de ramificación se solapan extensamente.
3. ¿A qué deberías prestar atención al permitir campos adicionales?
El espacio de nombres para el campo adicional debe estar claramente definido, en lugar de eliminar silenciosamente todas las restricciones.
4. ¿Qué pasa si el clasificador no puede determinar el tipo de documento?
Mantener el estado desconocido y entrar en una cola independiente para ser clasificada; no seleccione aleatoriamente una rama para ensamblar una rama exitosa.
5. ¿Aprobar la verificación estructural demuestra la autenticidad de los documentos?
No. La confianza en la clasificación, la verificación estructural y la autenticidad empresarial son tres niveles distintos; la verificación estructural no puede demostrar la autenticidad de los documentos.
📝 Resumen
Al colocar facturas y recibos en la misma entrada, guarda dos contratos separados y seleccionalos usando el campo kind requerido, haciendo que el tipo de documento introducido sea claramente visible. También deben diseñarse conjuntamente la verificación de ramas, la retroalimentación de errores y las exportaciones de tipos desconocidos.
Experiencia ahora: Sube tu documento para empezar a traducir, conservando el formato original


