nullInvoice es un microservicio Spring Boot para la generación y gestión automatizada de facturas con plantillas HTML totalmente personalizables, diseñado para integrarse con tiendas en línea y plataformas SaaS.
Las empresas usan nullInvoice para la generación de facturas después de finalizar las ventas. Los proveedores se configuran una sola vez desde la interfaz web, luego su aplicación llama a la API REST para generar facturas conformes bajo demanda.
Cómo funciona:
- Configuración: Configure proveedores en la UI con datos de la empresa, locale, moneda, tasas de impuestos, branding personalizado y plantillas de facturas
- Autenticación: Genere claves API desde el Panel de administrador para un acceso seguro a la API REST
- Integración: Su tienda en línea/SaaS realiza llamadas autenticadas a
/api/v1/invoices/generateusando el ID del proveedor - Generación: Las facturas se crean a partir de plantillas HTML totalmente personalizables y se devuelven como JSON o PDF con metadatos en los encabezados
- Entrega: Su aplicación recibe la factura y puede reenviarla al cliente o almacenarla para sus registros
┌─────────────────┐
│ Cliente │
│ finaliza │
│ la compra │
└────────┬────────┘
│
▼
┌─────────────────────────────────────────┐
│ Su plataforma de tienda/SaaS │
│ ───────────────────────────────────── │
│ 1. Procesar el pago │
│ 2. Emitir comprobante digital │
│ (requerido) │
│ 3. ¿Cliente solicita factura? ──────┐ │
└──────────────────────────────────────┼──┘
│
│ Llamada API
▼
┌──────────────────────────────┐
│ Servicio nullInvoice │
│ ────────────────────────── │
│ POST /api/v1/invoices/ │
│ generate │
│ │
│ - Valida ID del proveedor │
│ - Aplica plantilla │
│ - Guarda snapshot HTML │
│ - Genera PDF │
│ - Devuelve la factura │
└──────────────┬───────────────┘
│
│ Respuesta (JSON o PDF)
▼
┌──────────────────────────────────────────┐
│ Su plataforma de tienda/SaaS │
│ ────────────────────────────────────── │
│ - Recibe metadatos JSON O archivo PDF │
│ - Guarda el número de factura │
│ para registro │
│ - Envía PDF al cliente por correo │
└──────────────────────────────────────────┘
Plantillas totalmente personalizables
- Las facturas se basan en plantillas HTML definidas por el usuario con CSS en línea
- Las plantillas admiten más de 30 marcadores de posición para proveedor, cliente y datos financieros
- Las plantillas predeterminadas por proveedor permiten branding distinto por unidad de negocio
Inmutabilidad de documentos
- Cada factura almacena un snapshot del HTML procesado al momento de la generación
- Los cambios en la plantilla no afectan a las facturas ya generadas
- Las facturas pueden regenerarse de forma consistente desde el snapshot guardado
- Los permisos de la base de datos impiden eliminar registros de facturas (cumplimiento financiero)
Preparado para multi-tenant
- Configure múltiples proveedores con ajustes independientes (locale, moneda, numeración, branding)
- Los consumidores de la API especifican el ID del proveedor para generar facturas en distintas entidades de negocio
Entrega flexible
- Devuelve metadatos de la factura como JSON para archivo (
response_type: number) - Devuelve PDF directamente con metadatos en los encabezados para entrega inmediata (
response_type: pdf) - Recupere PDFs más tarde en
/api/v1/invoices/{invoiceNumber}/pdf
Documentación OpenAPI
- Documentación API interactiva en
/swagger - Especificación OpenAPI JSON en
/openapi - Ejemplos completos de solicitudes/respuestas y funcionalidad "try-it-out"
nullInvoice incluye autenticación integrada (inicio de sesión de UI basado en sesión + autenticación con clave API para endpoints REST). Si bien esto ofrece seguridad por defecto, la aplicación está pensada para despliegues en redes internas/privadas.
Despliegue recomendado:
- Detrás de un firewall o VPN
- Dentro de una red privada accesible solo por sus aplicaciones de confianza
- Con HTTPS/TLS habilitado para todas las conexiones
- Detrás de un reverse proxy con limitación de tasa configurada
Para despliegues en producción se requieren medidas de seguridad adicionales:
- Habilitar HTTPS/TLS
- Configurar limitación de tasa a nivel de reverse proxy
- Usar contraseñas de administrador seguras
- Rotar claves API regularmente
- Mantener las claves API en un gestor seguro de secretos (HashiCorp Vault, AWS Secrets Manager, etc.)
Consulte la sección Seguridad y mejores prácticas para una lista completa de producción.
nullInvoice es una tubería de generación de facturas diseñada para crear, almacenar y entregar documentos de facturas. No:
- Hace seguimiento de pagos o estado de pago más allá de las banderas básicas "unpaid/issued"
- Gestiona cuentas por cobrar o por pagar
- Genera reportes financieros o balances
- Se integra con sistemas contables (libros mayores, diarios, etc.)
- Maneja contabilidad, conciliación o declaraciones fiscales
Para una gestión financiera completa, integre nullInvoice con un sistema contable dedicado. Use este servicio para generar documentos de facturas y luego impórtelos en su software contable para seguimiento y cumplimiento.
- Java 21, Spring Boot 3.5.3
- MariaDB + JPA
- Thymeleaf (UI)
- OpenHTMLToPDF (PDFBox)
- OpenAPI en
/openapi, Swagger UI en/swagger
Para despliegue con Docker (recomendado):
- Docker
- Docker Compose
Para desarrollo local:
- Java 21 (JDK - Eclipse Temurin u OpenJDK)
- Maven 3.9+
- MariaDB 10.5+ (o MySQL 8.0+)
- Binario standalone de Tailwind CSS (para construir CSS - desde GitHub releases)
Crear la base de datos:
CREATE DATABASE nullinvoice CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Crear un usuario de aplicación dedicado con permisos restringidos:
CREATE USER 'nullinvoice'@'localhost' IDENTIFIED BY 'your_secure_password';
-- Otorgar permisos para operaciones normales y migraciones de esquema
GRANT SELECT, INSERT, UPDATE ON nullinvoice.* TO 'nullinvoice'@'localhost';
GRANT CREATE, ALTER, INDEX, REFERENCES ON nullinvoice.* TO 'nullinvoice'@'localhost';
FLUSH PRIVILEGES;Para acceso remoto, ajuste el host:
CREATE USER 'nullinvoice'@'%' IDENTIFIED BY 'your_secure_password';
GRANT SELECT, INSERT, UPDATE ON nullinvoice.* TO 'nullinvoice'@'%';
GRANT CREATE, ALTER, INDEX, REFERENCES ON nullinvoice.* TO 'nullinvoice'@'%';
FLUSH PRIVILEGES;Importante: ¿Por qué estos permisos restringidos?
Las facturas son documentos financieros inmutables que nunca deben eliminarse una vez creadas. El usuario de la aplicación está intencionalmente restringido y no puede:
DELETE- no puede eliminar registrosDROP- no puede eliminar tablas ni la base de datosTRUNCATE- no puede vaciar tablasGRANT- no puede otorgar permisos a otros
Esto garantiza la integridad de los datos y el cumplimiento de los requisitos de conservación de registros financieros. El permiso UPDATE se concede para cambios de estado (p. ej., marcar facturas como pagadas) y soft delete en registros de partes.
- El esquema de base de datos se gestiona con migraciones Flyway
- Esquema inicial:
nullInvoice/src/main/resources/db/migration/V1__initial_schema.sql - El esquema se crea/actualiza automáticamente al iniciar la aplicación
- El modo DDL de Hibernate está configurado en
none(Flyway gestiona todos los cambios de esquema)
Se proporciona un archivo de configuración de ejemplo en .env.example. Cópielo a .env y ajuste los valores para su entorno.
Variables de entorno (valores predeterminados entre paréntesis):
TZ- REQUERIDO zona horaria del sistema (Europe/Sofia)APP_PORT(8080)DB_HOST(localhost)DB_PORT(3306)DB_USER(nullinvoice)DB_PASSWORD(vacío)DB_NAME(nullinvoice)DB_PARAMS- REQUERIDO parámetros JDBC agregados a la URL de conexión
DEBE configurar la zona horaria en DOS lugares:
TZvariable de entorno - establece la zona horaria del sistema/aplicaciónserverTimezoneparámetro enDB_PARAMS- establece la zona horaria de la conexión a la base de datos
Ambos valores DEBEN coincidir con la zona horaria del servidor de base de datos para que las fechas/horas se interpreten y almacenen correctamente.
Configuración de ejemplo:
TZ=Europe/Sofia
DB_PARAMS=?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Europe/SofiaZonas horarias comunes: UTC, Europe/London, America/New_York, Asia/Tokyo. Consulte la lista completa.
Las zonas horarias desalineadas causarán fechas y marcas de tiempo incorrectas en las facturas.
En el primer inicio, la aplicación redirige a /setup para crear la cuenta de administrador inicial. Esto es obligatorio antes de acceder a cualquier otra funcionalidad.
Para restablecer y crear una nueva cuenta de administrador (recuperación de emergencia):
- Detenga la aplicación
- Trunque las tablas
usersyapi_keysen la base de datos - Reinicie la aplicación
- Complete nuevamente el flujo de
/setup
Recomendaciones de seguridad:
- Use una contraseña fuerte para la cuenta de administrador
- Establezca una pista de contraseña (opcional pero recomendado)
- Genere claves API separadas para distintos entornos (dev, staging, prod)
- Revoque las claves API no utilizadas
Arquitectura de autenticación:
- Acceso a UI: Autenticación basada en sesión con form login
- Acceso a API: Autenticación Bearer token sin estado (claves API)
- Contraseñas: BCrypt con 10 rondas
- Claves API: Formato UUID, hasheadas con BCrypt, se muestran solo una vez al generarlas
Duración de la sesión:
Por defecto, las sesiones de UI expiran después de 30 minutos de inactividad (predeterminado de Spring Boot/Tomcat). Los usuarios serán automáticamente desconectados y redirigidos a la página de inicio de sesión.
Para personalizar la duración de la sesión, agregue lo siguiente a nullInvoice/src/main/resources/application.yml:
server:
servlet:
session:
timeout: 60m # Opciones: 15m, 30m, 1h, 2h, etc.Valores de timeout comunes:
15m- 15 minutos (seguridad más estricta)30m- 30 minutos (predeterminado)1h- 1 hora (comodidad para usuarios activos)8h- 8 horas (extendido para sesiones largas)
Lista de verificación para producción:
- Habilitar HTTPS/TLS para todas las conexiones
- Usar contraseñas de administrador fuertes
- Generar claves API separadas por aplicación/entorno
- Implementar detrás de firewall o VPN
- Configurar limitación de tasa en el reverse proxy
- Configurar logging y monitoreo
- Revisar regularmente el uso de claves API (timestamp de último uso)
- Revocar inmediatamente claves API no usadas o comprometidas
- Mantener claves API en variables de entorno, nunca en el código
- Usar un gestor seguro de secretos (HashiCorp Vault, AWS Secrets Manager, etc.)
Protección CSRF:
- Habilitada para todos los formularios de UI
- Deshabilitada para endpoints API (auth Bearer sin estado)
Seguridad en el primer inicio:
- La aplicación no se puede usar hasta crear una cuenta de administrador vía
/setup - La página de configuración solo es accesible cuando no existe un administrador
- Tras la configuración, se requiere inicio de sesión para toda la funcionalidad
Imágenes oficiales de Docker: Hay imágenes preconstruidas disponibles en Docker Hub. Busque la imagen oficial de nullInvoice para omitir el paso de build.
Construir sin caché:
docker compose build --no-cacheLevantar el stack:
docker compose up -dDetener el stack:
docker compose down-
Asegúrese de tener una instancia de MariaDB en ejecución y cree la base de datos. Ver Configuración de la base de datos
-
Construir Tailwind CSS (requerido antes del primer inicio):
./build-tailwind.sh
-
Construir el proyecto con Maven:
cd nullInvoice mvn clean package -
Iniciar la aplicación:
java -jar target/nullinvoice-0.0.1-SNAPSHOT.jar
El proyecto fue construido con NetBeans y puede abrirse como proyecto Maven con el plugin de Spring Boot.
Configurar variables de entorno en NetBeans:
Opción 1 - Vía IDE:
- Clic derecho en el proyecto >> Properties
- Ir a Actions >> Run
- Establecer variables de entorno:
APP_PORT,DB_NAME,DB_USER,DB_PASSWORD
Opción 2 - Editar directamente:
- Modifique
nbactions.xmlen la raíz del proyecto
En el primer acceso, será redirigido a /setup para crear la cuenta de administrador inicial:
- Navegue a
http://localhost:8080(o su URL configurada) - Será redirigido automáticamente a
/setup - Cree una cuenta de administrador con nombre de usuario, contraseña y pista opcional
- Después del setup, será redirigido a
/login
Iniciar sesión:
- Acceda a la página de inicio de sesión en
/login - Use las credenciales de administrador que creó
- La pista de contraseña está disponible mediante el icono de información (si está configurada)
Panel de administrador: Después de iniciar sesión, acceda al panel de administrador desde el menú de usuario:
- Cambiar contraseña de administrador
- Generar claves API para acceso a la API REST
- Revocar claves API
- Ver uso de claves API (timestamp de último uso)
Requisitos previos:
- Configuración inicial completada (cuenta de administrador creada)
- Inicio de sesión con credenciales de administrador
Antes de poder generar facturas vía API, debe configurar al menos un proveedor en la interfaz web. Los proveedores definen datos de la empresa, locale, moneda, tasas de impuestos, branding personalizado (a través de plantillas) y la numeración de facturas para la generación.
-
Inicie sesión en la interfaz web en
http://localhost:8080(o su puerto configurado) -
Vaya a Proveedores
-
Cree un nuevo proveedor con los datos de la empresa
-
Configure locale, moneda y ajustes de impuestos
-
Configure preferencias de numeración de facturas (prefijo, relleno)
-
Anote el ID del proveedor para la integración API
-
Genere una clave API desde Administrador > Claves API para acceso a la API REST
Para ejemplos de configuración de proveedores, vea example-images - en-us para un ejemplo de EE. UU. o no UE; y eu-de para un ejemplo de la UE.
Una vez configurado, puede establecer una plantilla XHTML y usar el ID del proveedor (mostrado en el menú Editar proveedor) para realizar llamadas a /api/v1/invoices/generate.
- Administrar proveedores y clientes con soft delete y comprobaciones de unicidad.
- Crear y administrar plantillas de facturas con branding personalizado, con un predeterminado global y predeterminados por proveedor.
- Generar facturas con snapshots HTML guardados en el registro de la factura.
- Renderizar facturas a PDF bajo demanda.
- Buscar y ordenar facturas por número, fecha, cliente, proveedor y estado.
- Gestionar el estado de la factura como
unpaidoissued(pagada/final).
- Los valores de estado son
unpaidyissued.issuedse considera pagada y final. - La creación de facturas vía API siempre resulta en estado
issued, y la API no acepta override de estado. - La creación de facturas vía UI puede marcar una factura como
unpaidsolo cuando se establece una fecha de vencimiento. - Las facturas impagas pueden marcarse como
issueddesde la página de detalles de la factura. - Las facturas emitidas no pueden revertirse a
unpaid.
/invoices/newcrea facturas usando el proveedor seleccionado desde la cookie (si existe).- El interruptor de impagada está deshabilitado hasta que se proporciona una fecha de vencimiento.
/invoicesadmite filtrado por proveedor (dropdown) y búsqueda por número, fecha o cliente. La búsqueda por fecha acepta ISO (YYYY-MM-DD) odd.MM.yyyy.- La lista de facturas permite ordenar por estado; ordenar por estado alterna el orden de
unpaidyissued. /invoices/{invoiceNumber}muestra estado, totales, vista previa HTML guardada y ofrece una acción de una sola vía "Marcar como pagada" para facturas impagas.
- Proveedores: configure primero los datos del proveedor. El perfil del proveedor define locale, moneda, numeración de facturas y tasa de impuesto predeterminada.
- Plantillas: cree una plantilla de branding y establezca un predeterminado. Use un predeterminado global o uno por proveedor para sobrescribir el global.
- Clientes (opcional): puede agregar clientes manualmente, pero la generación de facturas también crea/actualiza clientes a partir de los datos ingresados.
- Seleccionar proveedor activo: elija un proveedor predeterminado en la UI, lo que establece una cookie usada en la creación de facturas.
- ID de proveedor para la API: abra un proveedor en modo edición y use el ID mostrado en la esquina superior izquierda.
- Facturas: liste, busque y filtre facturas; abra una factura para revisar detalles y marcar facturas impagas como emitidas/pagadas.
- Generar factura: ingrese datos del cliente o busque un cliente existente, agregue partidas y establezca impuestos por partida. Si una partida omite el impuesto, se aplica la tasa predeterminada del proveedor.
- Descuentos y notas: ingrese un descuento fijo o use la calculadora de % de descuento; agregue notas y genere la factura para ver la página de resumen.
La generación de facturas usa un bloqueo de escritura pesimista en el registro del proveedor para evitar condiciones de carrera al calcular el siguiente número de factura. Esto bloquea solicitudes concurrentes para el mismo proveedor hasta asignar el número.
Autenticación requerida: Todos los endpoints de la API requieren:
- Bearer token en el encabezado
Authorization(recomendado para integraciones) - Sesión activa (si inició sesión en la interfaz web)
Genere una clave API en el panel de administrador y agréguela en el encabezado Authorization:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoicesSi inició sesión en la interfaz web, su sesión se usa automáticamente para las solicitudes de la API.
Generar una clave API:
- Inicie sesión en la interfaz web
- Navegue a Administrador (menú de usuario)
- Desplácese a la sección "Claves API"
- Ingrese una descripción opcional y haga clic en "Generar clave"
- Copie la clave de inmediato - no se mostrará nuevamente
- La clave se muestra en formato
Authorization: Bearer {key}
Notas de seguridad:
- Las claves API se almacenan hasheadas en la base de datos (BCrypt)
- Las claves se pueden revocar en cualquier momento desde el panel de administrador
- Se registra el timestamp de último uso para cada clave
- Genere claves separadas para distintas aplicaciones/entornos
POST /api/v1/invoices/generate
Autenticación requerida - incluya el Bearer token en el encabezado Authorization.
- Requiere
supplier_idyclient. response_typeadmitenumber(predeterminado) opdf.number: devuelve JSON solo con metadatos de la facturapdf: devuelve el PDF directamente con metadatos en los encabezados de respuesta
- El estado siempre es
issuedpara facturas generadas por la API.
Ejemplo de solicitud (cliente existente por id):
curl -X POST http://localhost:8080/api/v1/invoices/generate \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"response_type": "number",
"supplier_id": 1,
"client": { "id": 42 },
"items": [
{ "description": "Consulting", "quantity": 1, "unit_price": 1000, "tax_rate": 0.2 }
],
"issue_date": "2026-01-16",
"due_date": "2026-01-30",
"currency_code": "EUR",
"notes": "Thank you"
}'Ejemplo de solicitud (nuevos datos de cliente):
curl -X POST http://localhost:8080/api/v1/invoices/generate \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"response_type": "number",
"supplier_id": 1,
"client": {
"name": "Client Co",
"addressLine1": "2 Side St",
"city": "Burgas",
"country": "BG",
"taxId": "123",
"vatId": "BG123"
},
"items": [
{ "description": "Consulting", "quantity": 1, "unit_price": 1000, "tax_rate": 0.2 }
]
}'Ejemplo de respuesta (response_type: number):
{
"status": "issued",
"message": "invoice generated",
"invoiceNumber": "INV-000001",
"issueDate": "2026-01-16"
}Ejemplo de solicitud (response_type: pdf para descarga directa de PDF):
curl -X POST http://localhost:8080/api/v1/invoices/generate \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"response_type": "pdf",
"supplier_id": 1,
"client": {
"name": "Client Co",
"addressLine1": "2 Side St",
"city": "Plovdiv",
"country": "BG",
"taxId": "123",
"vatId": "BG123"
},
"items": [
{ "description": "Consulting", "quantity": 1, "unit_price": 1000, "tax_rate": 0.2 }
]
}' \
-o invoice.pdf -iEjemplo de respuesta (response_type: pdf):
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="INV-000001.pdf"
X-Invoice-Number: INV-000001
X-Invoice-Status: issued
X-Invoice-Issue-Date: 2026-01-16
[PDF binary data]
La respuesta PDF incluye metadatos de la factura en encabezados personalizados (X-Invoice-Number, X-Invoice-Status, X-Invoice-Issue-Date), lo que permite a su aplicación guardar los detalles de la factura mientras recibe el PDF directamente.
GET /api/v1/invoices
Autenticación requerida - incluya el Bearer token en el encabezado Authorization.
- Filtro opcional:
status=unpaidostatus=issued
Ejemplo de solicitud:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoices?status=unpaidEjemplo de respuesta (filtrado):
[
{ "invoiceNumber": "INV-000002", "status": "unpaid" }
]Autenticación requerida - incluya el Bearer token en el encabezado Authorization.
Obtener metadatos de la factura:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoices/INV-000001Descargar PDF de la factura:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoices/INV-000001/pdf \
-o invoice.pdfAutenticación requerida - incluya el Bearer token en el encabezado Authorization.
GET /api/v1/parties/client?taxId=...&vatId=...(requiere uno de taxId/vatId)GET /api/v1/parties/clients/search?q=...(mínimo 2 caracteres)GET /api/v1/parties/suppliers
Ejemplo:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/parties/suppliersGET /api/v1/health(sin autenticación)
- Las plantillas viven en
invoice_templatesy deben incluir contenido HTML. - La generación de facturas requiere una plantilla predeterminada efectiva (por proveedor o global).
- Los proveedores pueden reemplazar el predeterminado global con un predeterminado específico.
- Las facturas generadas almacenan un snapshot HTML para re-renderizado consistente.
- Los PDFs se renderizan desde el snapshot HTML guardado cuando está disponible.
Las plantillas deben usar formato XHTML para un renderizado correcto del PDF:
- Incluir declaración XML:
<?xml version="1.0" encoding="UTF-8"?> - Usar namespace XHTML:
<html xmlns="http://www.w3.org/1999/xhtml"> - Todo el CSS debe ser en línea dentro de un
<style>en la sección<head> - No se admiten hojas de estilo externas para la generación de PDF
Hay plantillas de ejemplo en el directorio templates/ en 6 idiomas (EN, BG, IT, ES, DE, RU).
Las plantillas usan variables {{placeholder}}. Si un marcador no está presente en una plantilla, esos datos no se renderizarán en la factura final. El servicio no valida qué marcadores están presentes o ausentes.
Marcadores compatibles:
{{invoiceNumber}}{{issueDate}}{{dueDateRow}}(fila<div>completa o vacía){{supplierName}}{{supplierAddressLine1}}{{supplierAddressLine2Row}}(fila<div>completa o vacía){{supplierCityRegionPostal}}{{supplierCountry}}{{supplierTaxIdRow}}(fila<div>completa o vacía){{supplierVatIdRow}}(fila<div>completa o vacía){{supplierEmailRow}}(fila<div>completa o vacía){{supplierPhoneRow}}(fila<div>completa o vacía){{clientName}}{{clientAddressLine1}}{{clientAddressLine2Row}}(fila<div>completa o vacía){{clientCityRegionPostal}}{{clientCountry}}{{clientTaxIdRow}}(fila<div>completa o vacía){{clientVatIdRow}}(fila<div>completa o vacía){{clientEmailRow}}(fila<div>completa o vacía){{clientPhoneRow}}(fila<div>completa o vacía){{itemsRows}}(filas<tr>renderizadas){{subtotal}}{{discountTotal}}{{taxTotal}}{{total}}{{notesSection}}(sección<div>completa o vacía)
Los PDFs se renderizan con OpenHTMLToPDF. La aplicación incluye la familia de fuentes DejaVu, que admite caracteres latinos, cirílicos, griegos y otros Unicode.
Usar las fuentes incluidas:
body {
font-family: "DejaVu Sans", sans-serif;
}Usar fuentes web personalizadas:
Las plantillas pueden cargar fuentes externas mediante @font-face en el <style> en línea. Asegúrese de que la fuente soporte el idioma de su plantilla (p. ej., cirílico para ruso/búlgaro, griego, etc.). Las fuentes DejaVu incluidas sirven como fallback si la fuente web no se carga.
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url('https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf') format('truetype');
}
body {
font-family: 'Roboto', 'DejaVu Sans', sans-serif;
}Fuentes incluidas disponibles:
| Font Family | Weights | Styles |
|---|---|---|
DejaVu Sans |
200 (extra-light), 400 (normal), 700 (bold) | normal, oblique |
DejaVu Sans Condensed |
400 (normal), 700 (bold) | normal, oblique |
DejaVu Sans Mono |
400 (normal), 700 (bold) | normal, oblique |
DejaVu Serif |
400 (normal), 700 (bold) | normal, italic |
DejaVu Serif Condensed |
400 (normal), 700 (bold) | normal, italic |
- Proveedores y clientes comparten la tabla
partiesy se distinguen porrole. - Soft delete oculta partes de las listas mientras preserva el historial de facturas.
- La configuración del proveedor puede sobrescribir locale, moneda, formato de fecha, prefijo de factura y relleno de dígitos.
default_tax_ratedel proveedor se aplica a partidas que omiten la tasa de impuesto.
- Los números de factura son por proveedor y usan
max(invoice_number_int) + 1. - El prefijo opcional y el relleno de dígitos se aplican desde la configuración del proveedor.
- Los códigos de moneda se validan contra ISO 4217.
Se incluye un script para stress test de la API de generación de facturas con solicitudes concurrentes.
Uso:
API_KEY=your_api_key ./integration-tests/gen-test.sh [SUPPLIER_ID] [COUNT] [BASE_URL]O pase la clave API como cuarto argumento:
./integration-tests/gen-test.sh [SUPPLIER_ID] [COUNT] [BASE_URL] [API_KEY]Parámetros:
SUPPLIER_ID- ID del proveedor para facturas de prueba (predeterminado: 1)COUNT- número de solicitudes concurrentes a generar (predeterminado: 20)BASE_URL- URL base de la aplicación (predeterminado: http://localhost:8080)API_KEY- su clave API (requerida, puede establecerse como variable de entorno)
Ejemplo:
API_KEY=abc123-your-key ./integration-tests/gen-test.sh 1 50 http://localhost:8080Esto dispara solicitudes concurrentes de generación de facturas para probar el bloqueo pesimista y el rendimiento general de la API bajo carga.
La UI utiliza Tailwind CSS, que debe reconstruirse cuando se realizan cambios en el CSS.
-
Descargue el binario standalone de Tailwind CSS desde GitHub releases
-
Coloque el binario en el directorio
twbin/(p. ej.,twbin/tailwindcss-linux-x64) -
Ejecute el script de build:
./build-tailwind.sh
Esto reconstruye nullInvoice/src/main/resources/static/css/tailwind.css desde el archivo fuente tailwind-src.css.
Para desarrollo rápido sin reconstruir Tailwind, descomente el script CDN en nullInvoice/src/main/resources/templates/fragments/head.html:
<script src="https://cdn.tailwindcss.com"></script>Recuerde reconstruir Tailwind CSS antes de desplegar en producción.
nullInvoice/src/main/java- código de la aplicaciónnullInvoice/src/main/resources/templates- plantillas UI (Thymeleaf)nullInvoice/src/main/resources/static- assets JS/CSSnullInvoice/src/main/resources/db/migration- migraciones Flywaytemplates/- plantillas de facturas de ejemplo en 6 idiomas (EN, BG, IT, ES, DE, RU)integration-tests/- scripts de pruebas de carga para generación de facturasbuild-tailwind.sh- script de conveniencia para construir Tailwind CSStwbin/- binario standalone de Tailwind CSS (descargar por separado)
Documentación API interactiva:
- Especificación OpenAPI JSON:
/openapi - Swagger UI:
/swagger
Acceso a Swagger UI:
- Inicie sesión en la interfaz web
- Haga clic en el menú de usuario > "Documentación API"
- O navegue directamente a
/swagger(requiere inicio de sesión)
Probar endpoints en Swagger:
- Haga clic en "Authorize" (icono de candado) en la parte superior derecha
- Ingrese su clave API (genérela en Administrador > Claves API si es necesario)
- Haga clic en "Authorize"
- Todas las solicitudes incluirán el Bearer token automáticamente
- Use "Try it out" para probar endpoints de forma interactiva
Nota: Swagger UI requiere autenticación y solo está disponible para administradores con sesión iniciada.
Idiomas de UI compatibles: La aplicación está completamente internacionalizada con bundles de mensajes:
- Inglés (EN) ✅
- Búlgaro (BG) ✅
- Alemán (DE) ✅
- Español (ES) ✅
- Italiano (IT) ✅
- Ruso (RU) ✅
Traducciones del README: Este README.md también está disponible en:
Traducción automática proporcionada por Google Gemini.
Plantillas de facturas: Se incluyen plantillas de ejemplo para los 6 idiomas anteriores (en el directorio templates/)
Soporte técnico para idiomas adicionales: La aplicación puede generar facturas en cualquier idioma con el soporte de fuentes adecuado:
- Árabe (EAU, Arabia Saudita, etc.) - soporte RTL vía CSS, se requieren plantillas y traducciones UI
- Asia oriental (chino, japonés, coreano) - fuentes Unicode compatibles, se requieren plantillas y traducciones UI
- Hebreo - soporte RTL vía CSS, se requieren plantillas y traducciones UI
- Cualquier otro idioma basado en Unicode
Agradecemos contribuciones para:
- 🌍 Traducciones UI (
messages_{lang}.propertiesennullInvoice/src/main/resources/) - 📄 Plantillas de facturas de ejemplo para su idioma/región (
templates/{lang}/) - 🎨 Recomendaciones de fuentes para un renderizado PDF óptimo en su idioma
- 📝 Mejoras y traducciones de documentación
La familia de fuentes DejaVu incluida proporciona amplia cobertura Unicode. Para idiomas que requieren fuentes específicas, use @font-face en plantillas de facturas para cargar webfonts con fallback a DejaVu.
Este proyecto está licenciado bajo la Elastic License 2.0 - consulte el archivo LICENSE para más detalles.
Copyright 2026 nullata
- Font Awesome Free:
nullInvoice/src/main/resources/static/fontawesome-free-7.1.0-web/LICENSE.txt - DejaVu Fonts:
nullInvoice/src/main/resources/fonts/LICENSE.txt