ubl-star: la factura electrónica es el XML, no el PDF

csalcedodatabi Power BI Herramientas Factura electrónica
Tres tarjetas unidas por flechas: el XML UBL 2.1 de una factura, el comando ubl-star model que lo lee de una carpeta y escribe en ./modelo, y el esquema estrella resultante con fact_factura, fact_factura_linea, dim_proveedor, dim_item y dim_fecha

En resumen — Donde la factura electrónica es obligatoria, el documento legal no es el PDF: es el XML. ubl-star lee ese XML UBL 2.1 — de la DIAN en Colombia o de PEPPOL en Europa — y escribe un esquema estrella en Parquet o CSV listo para Power BI. Sin OCR, sin modelo, en tu máquina. Es una librería, una CLI y un plugin de Claude Code, MIT, y el plugin está publicado en el directorio de Anthropic.

Todo el mundo está leyendo la foto

La mayor parte del esfuerzo de la industria en facturas va a leer el PDF: OCR, layout, modelos de visión, plantillas por proveedor. Es trabajo real y difícil. Pero en muchos países se está resolviendo un problema que ya venía resuelto en el adjunto.

En Colombia la factura se emite en XML UBL 2.1, firmada y validada por la DIAN antes de llegar a quien la recibe. En Europa, PEPPOL usa el mismo UBL 2.1 para la factura electrónica entre países. El PDF es la representación gráfica: una foto del original.

Leer el XML no es una optimización. Es leer la fuente: precisión total, cero OCR, cero tokens, cero modelo.

Un parser para las dos jurisdicciones

Lo que cambia entre la DIAN y PEPPOL son las extensiones y los campos fiscales, no la estructura del documento. Esa es la tesis del proyecto, y las facturas de prueba de PEPPOL la confirmaron con matices: PEPPOL guarda algunos datos en otra ruta que el estándar también admite — el vencimiento en cbc:DueDate, el IVA en PartyTaxScheme, el artículo en cbc:Name —. El parser lee cada una de esas rutas en un orden fijo, y cada ruta sale del estándar, no de una suposición.

Y si un campo no está en el XML, no está. Se reporta ausente; no se inventa.

De un buzón de facturas a seis tablas

De la carpeta de adjuntos al modelo
pip install "git+https://github.com/CSalcedoDataBI/[email protected]"
ubl-star model ./buzon-de-facturas --salida ./modelo

ubl-star model acepta archivos .xml o .zip, o carpetas enteras. Abre el ZIP del adjunto, localiza el XML y escribe:

ArchivoQué es
dim_proveedorun emisor por id fiscal
dim_itemun artículo por código y descripción
dim_fechacalendario de años completos, sirve como tabla de fechas de Power BI
fact_facturaun documento: totales, impuestos, vencimiento, medio de pago y si cuadra
fact_factura_lineauna línea: cantidad, precio, importe
fact_factura_impuestoun tributo de un documento (IVA, INC, ICA…): base e impuesto
rechazados.csvcada archivo que no entró, con el motivo

Tres detalles que ahorran tiempo en Power BI:

  • Las notas crédito llevan signo = -1, así que el neto es SUM(importe * signo). Lee facturas, notas crédito y notas débito.
  • Una factura que llega dos veces — en el ZIP y suelta — cuenta una sola vez; la copia queda en rechazados.csv.
  • Por pantalla solo salen conteos, nunca datos de las facturas.

Con --formato csv escribe CSV en lugar de Parquet. Los campos, los tipos y las reglas de nulos están en un contrato de salida versionado, anclado por tests, para que otra herramienta que lea otra fuente pueda entregar exactamente el mismo modelo.

El plugin: que Claude no escriba su propio parser

La carpeta plugin/ del repositorio es un plugin de Claude Code con una sola skill, leer-facturas-ubl. Le dices a Claude «convierte estas facturas de la DIAN en tablas para Power BI» o «¿cuánto IVA hay en esta carpeta?», y Claude llama a la CLI de ubl-star en lugar de improvisar un parser.

Instalación del plugin
/plugin marketplace add CSalcedoDataBI/ubl-star
/plugin install ubl-star@ubl-star

Necesita uv (o pip), git y Python 3.11 o superior. También está publicado en el directorio de plugins de Anthropic, desde la versión 0.2.7.

Lo que hace en tu máquina, tal como lo declara el README:

  • Ejecuta la CLI fijada a una versión exacta, con uvx.
  • Descarga, solo la primera vez, ese paquete desde GitHub y sus dependencias desde PyPI.
  • No envía nada a ningún servicio. El parseo es local. Lo único que sale es lo que Claude lee de la salida, y por eso la skill entrega archivos y agregados en vez de volcar filas con nombres, NIT o cédulas.

¿El plugin cambia algo? Medido

El repositorio mide el plugin con y sin él sobre facturas sintéticas, tres corridas por caso:

CasoCon pluginSin plugin
De un ZIP de la DIAN a tablas para Power BI1.000.00
IVA neto, restando las notas crédito1.000.33
Un PDF escaneado queda fuera de alcance1.001.00
Claude no escribe un parser propio1.000.33

Ninguna factura real entra al repositorio

Las facturas de prueba son sintéticas, generadas por código, y un hook bloquea cualquier documento fuera de la carpeta de fixtures. Es la única regla del proyecto que no se negocia: ni en un commit ni adjunta a un issue.

Lo que no es

  • No lee PDF, escaneos ni fotos. La lectura óptica es otro problema, con otro costo, otra tasa de error y otra forma de auditarse. Mezclar los dos caminos es lo que hace que un extractor de facturas no se pueda verificar.
  • No emite ni firma facturas.
  • No está en PyPI todavía. Hoy se instala desde una etiqueta de GitHub.

Están probados los perfiles DIAN y PEPPOL BIS 3.0 / EN 16931, cada uno con factura y nota crédito (y nota débito en la DIAN).

→ github.com/CSalcedoDataBI/ubl-star · Todos los plugins: Plugins para agentes

¿Te resultó útil este artículo?

Tu apoyo me permite seguir creando contenido de calidad.

¡Contáctame!