diff --git a/documentacion/api.md b/documentacion/api.md index 5f4365c..90ddda5 100644 --- a/documentacion/api.md +++ b/documentacion/api.md @@ -73,23 +73,43 @@ Registra y valida un certificado digital. --- +### Formatos Disponibles +``` +GET /api/v1/formats +``` +Lista los formatos de entrada soportados. La API detecta automáticamente el formato del JSON recibido. + +**Response:** +```json +{ + "formats": ["dolibarr", "native"] +} +``` + +--- + ### Alta de Factura ``` POST /api/v1/facturas ``` -Registra una factura en VeriFactu. No requiere token (el certificado se selecciona internamente o usa el primero disponible). +Registra una factura en VeriFactu. El formato de entrada se detecta automáticamente (no requiere parámetro). -**Request:** +**Formato nativo (por defecto):** ```json { "tipo": "alta", "factura": { "emisor_nif": "53950250R", + "emisor_nombre": "EMPRESA EJEMPLO SL", "num_serie": "FV2026/001", "fecha_expedicion": "17-04-2026", "tipo_factura": "F1", "descripcion": "Factura de prueba", - "IVA": [ + "destinatario": { + "nombre": "CLIENTE SL", + "nif": "B98765432" + }, + "iva": [ {"base": 100.00, "cuota": 21.00, "tipo": 21.0} ], "importe_total": 121.00 @@ -102,6 +122,38 @@ Registra una factura en VeriFactu. No requiere token (el certificado se seleccio } ``` +**Formato Dolibarr BFF:** +```json +{ + "invoice": { + "number": "FA2024/001", + "date": "2024-09-13T00:00:00Z", + "totalHt": 100.00, + "totalTax": 21.00, + "total": 121.00, + "notePublic": "Factura de prueba", + "lines": [ + {"description": "Servicio", "quantity": 1, "unitPrice": 100, "taxRate": 21, "total": 121.00} + ] + }, + "client": { + "name": "CLIENTE SL", + "vatNumber": "B98765432" + }, + "emisor": { + "nif": "53950250R", + "nombre": "EMPRESA EJEMPLO SL" + }, + "sistema": { + "nombre": "Mi Sistema", + "nif_proveedor": "53950250R", + "version": "1.0" + } +} +``` + +Ver [formatos.md](formatos.md) para detalles de cada formato y cómo añadir nuevos. + **Response (AEAT disponible):** ```json { diff --git a/documentacion/arqui.md b/documentacion/arqui.md index ca289cc..5c0be5d 100644 --- a/documentacion/arqui.md +++ b/documentacion/arqui.md @@ -17,6 +17,10 @@ ### 2. Business Logic (`internal/`) - **factura.go**: Servicio de facturas (alta, anulación) +- **formats/**: Sistema de formatos de entrada con detección automática + - **registry.go**: Registro y auto-detección de formatos + - **native/**: Formato nativo de la API + - **dolibarr/**: Formato compatible con Dolibarr BFF - **transformer.go**: Transformación JSON → datos de factura - **hash.go**: Cálculo de hash encadenado - **models.go**: Modelos y validación de entrada @@ -38,10 +42,10 @@ Request HTTP JSON Input │ ▼ -ValidateInput() ──▶ ValidationError[] +TransformAuto() ──▶ Detecta formato (native, dolibarr, ...) │ ▼ -TransformToInvoiceData() +Transformer.Transform() ──▶ TransformResult │ ▼ CalculateHash(prevHash) diff --git a/documentacion/formato_datos.md b/documentacion/formato_datos.md index 3441e5e..57c9578 100644 --- a/documentacion/formato_datos.md +++ b/documentacion/formato_datos.md @@ -16,10 +16,12 @@ ## Fechas -Formato: `dd-mm-yyyy` +Formato nativo: `dd-mm-yyyy` Ejemplo: `17-04-2026` +El formato Dolibarr acepta fechas ISO 8601 (`2024-09-13T00:00:00Z`) que se convierten automáticamente. + ## Tipos de Factura | Código | Descripción | @@ -55,33 +57,9 @@ Cada entrada de IVA: | ClaveRegimen | Clave de régimen (01=general) | | Calificacion | Calificación (S1=sin inversa) | -## Ejemplo Completo +## Formatos de Entrada -```json -{ - "tipo": "alta", - "factura": { - "emisor_nif": "53950250R", - "num_serie": "FV2026/001", - "fecha_expedicion": "17-04-2026", - "tipo_factura": "F1", - "descripcion": "Factura de prueba", - "iva": [ - { - "base": 100.00, - "cuota": 21.00, - "tipo": 21.0 - } - ], - "importe_total": 121.00 - }, - "sistema": { - "nombre": "Mi ERP", - "nif_proveedor": "53950250R", - "version": "1.0" - } -} -``` +La API detecta automáticamente el formato. Ver [formatos.md](formatos.md) para la lista completa y cómo añadir nuevos. ## Hash Encadenado diff --git a/documentacion/formatos.md b/documentacion/formatos.md new file mode 100644 index 0000000..e15c289 --- /dev/null +++ b/documentacion/formatos.md @@ -0,0 +1,132 @@ +# Formatos de Entrada + +La API detecta automáticamente el formato de entrada. No hay que indicarlo. + +## Endpoint + +``` +POST /api/v1/facturas → Formato detectado automáticamente +GET /api/v1/formats → Lista formatos soportados +``` + +--- + +## Formato: `native` + +Formato propio de la API. Se detecta por la presencia del campo `factura`. + +```json +{ + "tipo": "alta", + "factura": { + "emisor_nif": "A12345678", + "emisor_nombre": "EMPRESA EJEMPLO SL", + "num_serie": "2024-001", + "fecha_expedicion": "13-09-2024", + "tipo_factura": "F1", + "descripcion": "Servicios de consultoría", + "destinatario": { + "nombre": "CLIENTE SL", + "nif": "B98765432" + }, + "iva": [ + {"base": 100.00, "cuota": 21.00, "tipo": 21.00} + ], + "importe_total": 121.00 + }, + "sistema": { + "nombre": "Mi Software", + "nif_proveedor": "A12345678", + "version": "1.0.0" + } +} +``` + +--- + +## Formato: `dolibarr` + +Compatible con el BFF de Dolibarr. Se detecta por la presencia del campo `invoice`. Agrupa automáticamente las líneas por tipo de IVA. + +```json +{ + "invoice": { + "number": "FA2024/001", + "date": "2024-09-13T00:00:00Z", + "totalHt": 100.00, + "totalTax": 21.00, + "total": 121.00, + "notePublic": "Servicios de consultoría", + "lines": [ + {"description": "Servicio A", "quantity": 1, "unitPrice": 60, "taxRate": 21, "total": 72.60}, + {"description": "Servicio B", "quantity": 1, "unitPrice": 40, "taxRate": 21, "total": 48.40} + ] + }, + "client": { + "name": "CLIENTE SL", + "vatNumber": "B98765432" + }, + "emisor": { + "nif": "A12345678", + "nombre": "EMPRESA EJEMPLO SL" + }, + "sistema": { + "nombre": "Mi Software", + "nif_proveedor": "A12345678", + "version": "1.0.0" + } +} +``` + +### Mapeo Dolibarr → VeriFactu + +| Dolibarr | VeriFactu | +|---|---| +| `invoice.number` | `num_serie` | +| `invoice.date` | `fecha_expedicion` (convierte ISO → dd-mm-yyyy) | +| `invoice.notePublic` | `descripcion` | +| `lines[].taxRate` | agrupa por tipo → `iva[].tipo` | +| `lines[].total` | calcula `base = total / (1 + rate/100)`, `cuota = total - base` | +| `client.name` | `destinatario.nombre` | +| `client.vatNumber` | `destinatario.nif` | +| `invoice.total` | `importe_total` | +| `emisor.nif` | `emisor_nif` | +| `emisor.nombre` | `emisor_nombre` | + +--- + +## Añadir un nuevo formato + +1. Crear carpeta `internal/formats/miformato/format.go` +2. Implementar la interfaz `formats.Transformer`: + +```go +package miformato + +import ( + "encoding/json" + "VerifactuMidAPI/internal/formats" +) + +func init() { + formats.Register(&Transformer{}) +} + +type Transformer struct{} + +func (t *Transformer) Name() string { return "miformato" } + +func (t *Transformer) Transform(raw json.RawMessage) (*formats.TransformResult, error) { + // Parsear JSON de entrada + // Validar + // Devolver TransformResult +} +``` + +3. Importar en `main.go`: + +```go +import _ "VerifactuMidAPI/internal/formats/miformato" +``` + +La detección es automática: el primer formato que pueda parsear el JSON se usa.