Saltar a contenido

ADR 028: Perfil UBL Cortex y hooks de documento

Estado

Aceptado — 2026-07

Relacionado con ADR 017, ADR 021, ADR 023 y ADR 024.

Contexto

Los plugins de negocio (billing, clients, payments, sales, store, ledger) modelan hoy entidades ad hoc en JSON o tablas propias sin contrato de intercambio compartido. Para integración entre plugins, exportación y adaptadores nacionales (p. ej. DIAN en Colombia) hace falta un estándar de documentos de negocio independiente del regulador.

UBL 2.1 (OASIS Universal Business Language) define facturas, notas crédito, órdenes y partes (Party) en XML. DIAN y otros entes consumen perfiles UBL; no son el estándar.

Complemento futuro para actores y contactos: schema.org (Person, Organization, Event) y vCard 4.0 para import/export de contactos.

Decisión

Capas

Capa Paquete Responsabilidad
Contrato UBL cortex-ubl (ubl/cortex_ubl/) Modelos Pydantic del perfil, nombres de hooks, validación
Runtime hooks cortex_framework.hooks HookManager: apply_filters, do_action
Pipeline cortex_framework.ubl UblDocumentPipeline, serialización XML subset
Persistencia Plugins (billing_*) Tablas propias; columna ubl_snapshot JSONB
Adaptadores Plugins opcionales (dian-adapter) Perfil nacional, firma, envío

core y cortex-ubl no importan framework ni plugins.

Perfil Cortex UBL (fase 1)

Subset documentado; no UBL 2.1 completo.

Tipo UBL Plugin dueño Fase
Invoice billing 1
CreditNote billing 1.1
Order sales / store 2
Party / CustomerParty clients 2

Invoice mínimo: ID, IssueDate, DocumentCurrencyCode, AccountingSupplierParty, AccountingCustomerParty, InvoiceLine[], TaxTotal, LegalMonetaryTotal, CustomizationID (vacío en core; perfiles nacionales en adaptadores).

Hooks de documento (filters vs actions)

Hook Tipo Uso
ubl.invoice.before_build action Preparar contexto
ubl.invoice.after_build filter Mutar InvoiceDocument tras construcción
ubl.invoice.before_validate action
ubl.invoice.on_calculate_taxes filter Impuestos, descuentos
ubl.invoice.after_calculate_taxes action
ubl.invoice.before_serialize action
ubl.invoice.after_serialize filter Ajustar XML/string
ubl.invoice.issued action Puente a billing.invoice.issued (EventDispatcher)

Los filters mutan el documento en cadena con prioridad. Los actions no sustituyen a EventDispatcher para hechos públicos cross-plugin.

Vocabulario document_type

Término Dominio Plugin
IdentityDocumentType CC, NIT, pasaporte clients
FiscalDocumentType FV, NC billing
LedgerDocumentType FV, CE, NC contable ledger

No unificar tablas; unificar semántica en ADR y mapeos UBL.

schema.org y vCard (fase 2)

  • Party interno mapeable a schema:Organization / schema:Person.
  • Export vCard 4.0 desde clients.
  • Eventos de dominio con payload inspirado en schema:Event donde aplique.

Fase 1: AccountingCustomerParty con party_id opcional + snapshot textual.

DIAN y adaptadores nacionales

Fuera del núcleo. Plugin opcional escucha billing.invoice.issued, aplica CustomizationID Colombia, firma y envía XML. El estándar de negocio permanece UBL.

IO provisional (broadcast y mail)

  • Broadcast: Broadcaster + WebSocket propio; puente a io.ws; escala con Redis pub/sub (ADR 009). Pusher solo como driver opcional, no default.
  • Notifications: canal mail vía NotificationManager; plugins no abren SMTP directo.

Consecuencias

  • billing expone GET .../ubl y POST .../export además del CRUD actual.
  • Plugins registran register_ubl_hooks en bootstrap.
  • Tests TDD en ubl/tests, framework/tests, plugins/billing/tests.

Referencias