ubl-star: la factura electrónica es el XML, no el PDF
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
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:
| Archivo | Qué es |
|---|---|
dim_proveedor | un emisor por id fiscal |
dim_item | un artículo por código y descripción |
dim_fecha | calendario de años completos, sirve como tabla de fechas de Power BI |
fact_factura | un documento: totales, impuestos, vencimiento, medio de pago y si cuadra |
fact_factura_linea | una línea: cantidad, precio, importe |
fact_factura_impuesto | un tributo de un documento (IVA, INC, ICA…): base e impuesto |
rechazados.csv | cada 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 esSUM(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.
/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:
| Caso | Con plugin | Sin plugin |
|---|---|---|
| De un ZIP de la DIAN a tablas para Power BI | 1.00 | 0.00 |
| IVA neto, restando las notas crédito | 1.00 | 0.33 |
| Un PDF escaneado queda fuera de alcance | 1.00 | 1.00 |
| Claude no escribe un parser propio | 1.00 | 0.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.