Plantillas Typst
Cada PDF de factura que genera uninvoice.app parte de una maquetación fija (cabecera, destinatario, líneas, totales, desglose de impuestos, código QR) más dos fragmentos que controlas tú:
| Fragmento | Dónde aparece |
|---|---|
| Bloque post factura | Justo debajo de la tabla de totales, antes de las cuentas de pago. Normalmente, instrucciones de pago, condiciones o una nota de agradecimiento. |
| Pie de página | Al final de todas las páginas, centrado y en letra pequeña (8pt). Normalmente, un aviso legal o datos registrales. |
Ambos fragmentos se escriben en Typst, un lenguaje de composición tipográfica moderno. Esta página explica qué puedes escribir en ellos; los valores que puedes insertar se explican en Marcadores.
Dónde se configuran los fragmentos
- Para toda la empresa: en la tarjeta Configuración de facturas de la página Empresa. Se aplican a todas las facturas que emitas.
- Por destinatario: en la plantilla de factura personalizada del formulario de un cliente. Se aplican solo a las facturas emitidas a ese cliente.
Los dos niveles se combinan de forma distinta:
- La personalización del bloque post factura no descarta el bloque de la
empresa. El bloque de la empresa se te entrega como una función,
#post_invoice_original(), que llamas donde quieras, así que un destinatario puede añadir una sección encima o debajo de las instrucciones de pago habituales sin tener que copiarlas. - La personalización del pie de página sustituye por completo al pie de la empresa. Si quieres conservar su contenido, repítelo en la personalización.
Los fragmentos efectivos se congelan en cada factura al crearla, igual que los datos de la empresa y del destinatario. Editar una plantilla nunca cambia una factura ya creada: un documento emitido se conserva exactamente tal y como se generó.
Typst en un minuto
Un fragmento es simple marcado Typst: el texto es texto y # cambia a
código: una llamada a función, una variable o una expresión de control de
flujo.
El pago vence a los 30 días.
*Transferencia bancaria* a #ph("payment_recipient"), indicando #ph("payment_concept").
#text(size: 9pt, fill: gray)[Gracias por tu confianza.]
Puntos de entrada útiles en la referencia de Typst:
| Lo que quieres hacer | Referencia de Typst |
|---|---|
Reglas de marcado (*negrita*, _cursiva_, listas, escapes) | Syntax |
| Tamaño, grosor, color, fuente | text |
| Espacio vertical / horizontal | v, h |
| Centrar, alinear a la derecha, sangrar un bloque | align, block |
| Columnas de contenido | grid |
| Una tabla de datos con bordes | table |
| Listas con viñetas y numeradas | list, enum |
| Enlaces | link |
| Líneas, cajas, colores | line, rect, rgb |
Variables, if, bucles, arrays | Scripting |
Funciones disponibles en tus fragmentos
Además de Typst estándar, uninvoice.app define un pequeño conjunto de funciones ligadas a la factura que se está generando.
ph("clave"): el valor de un marcador
Devuelve el valor de un marcador integrado o personalizado, o una cadena vacía cuando la factura no tiene valor para esa clave. Como nunca falla, las secciones opcionales desaparecen limpiamente:
#if ph("purchase_order") != "" [
Pedido de compra: #ph("purchase_order")
]
La lista completa de claves está en Marcadores.
total_numeric: el total como número
El total de la factura en unidades mayores (euros, no céntimos) como número, para poder operar con él. Todo lo demás es texto.
fx_rate(desde, hasta) y convert(desde, hasta, importe): conversión de divisas
fx_rate devuelve el tipo unitario de un par de divisas; convert multiplica un
importe por ese tipo. Ambas devuelven none cuando la factura no tiene tipo para
ese par, así que protege el bloque:
#let usd = convert("EUR", "USD", total_numeric)
#if usd != none [
Equivalente: #calc.round(usd, digits: 2) USD
(1 EUR = #fx_rate("EUR", "USD") USD)
]
uninvoice.app analiza tus fragmentos en busca de estas llamadas antes de
generar el PDF para obtener los tipos y congelarlos en la factura. Solo
encuentra códigos literales: convert("EUR", "USD", …) funciona,
convert(base, cotizada, …) no: un código calculado se resuelve a none sin
avisar.
Los tipos proceden de los tipos de referencia del Banco Central Europeo, que cubren unas 30 divisas. Puedes introducir un tipo a mano al crear la factura; lo que siga faltando se obtiene al emitirla y se congela en ella, de modo que una conversión ya generada nunca cambia. Si un par necesario no se puede resolver (una divisa no cubierta, o el proveedor de tipos inaccesible), la emisión falla y la factura sigue siendo un borrador en lugar de mostrar un importe en blanco.
post_invoice_original(): el bloque post factura de la empresa
Solo tiene sentido en una personalización del bloque post factura por destinatario: genera el bloque de la empresa. En cualquier otro sitio no genera nada, así que llamarla siempre es seguro.
Esta factura se acoge al acuerdo marco #ph("agreement_ref").
#post_invoice_original()
#text(size: 8pt)[Envía el justificante de pago a [email protected].]
Lo que un fragmento no puede hacer
El generador está deliberadamente aislado: la misma entrada produce siempre el mismo PDF, en cualquier máquina.
- Sin paquetes ni importaciones externas.
#import "@preview/…"e#includede otros archivos no están disponibles. - Sin archivos externos. No se pueden cargar imágenes, fuentes ni datos desde disco o una URL; solo están disponibles los datos de la propia factura.
- Las fuentes son las incluidas:
Helvetica Neue(la del documento),UbuntuyUbuntu Mono. Cualquier otra familia recurre a una alternativa. - No hay "hoy".
datetime.today()está fijado a una fecha constante para que la generación sea reproducible; usaph("invoice_created_at")para la fecha de la factura. - Un fragmento que no compila rompe el PDF de todas las facturas que lo llevan. Como los fragmentos se congelan por factura, una plantilla rota afecta a las facturas creadas mientras estaba vigente, no a las anteriores.
Crea una factura en borrador para el destinatario y descarga su PDF. Los
borradores se generan exactamente por la misma vía (con una marca de agua
DRAFT), así que es la forma más rápida de comprobar que un fragmento compila y
se ve bien.
Dónde no se generan los fragmentos
El bloque post factura se omite en las proformas y en las facturas cuyos datos de pago están suprimidos (por ejemplo, una factura ya cobrada con tarjeta), porque ambas pedirían un pago que no debe hacerse. El pie de página aparece en todos los documentos.