# HALLAZGOS — Esquemas oficiales AEAT VERI\*FACTU

> **Origen:** ficheros descargados en `C:\Users\NEOMUX\Desktop\OTROS\aeat-esquemas\` y **parseados con script Python + `xml.etree.ElementTree`** (no lectura a ojo). Todo lo marcado ✅ sale literalmente de un XSD/WSDL, citando el fichero. Fecha del análisis: **2026-08-12**.
>
> Ficheros analizados: `SistemaFacturacion.wsdl` · `SuministroInformacion.xsd` (el grande, contiene todos los tipos) · `SuministroLR.xsd` · `ConsultaLR.xsd` · `RespuestaSuministro.xsd` · `RespuestaConsultaLR.xsd` · `EventosSIF.xsd`.
>
> **Marcas:** ✅ verificado contra XSD/WSDL · 📄 dato del esquema sin implicación de diseño · ⚠️ pendiente o a vigilar · ❗ error detectado en el documento maestro que hay que corregir.

---

## 0. LO QUE CAMBIA RESPECTO A LO QUE CREÍAMOS

Sí hay discrepancias. Cuatro son correcciones de contenido (❗) y el resto son precisiones que el documento maestro no podía tener porque no había parseado el esquema.

### ❗ Errores del documento maestro que hay que corregir

| # | Lo que decía el `.md` | Lo que dice el XSD | Impacto |
|---|---|---|---|
| **1** | `OperacionExenta` (L10) = **E1–E6**, con la glosa "arts. 20, 21, 22, 23/24, 25, otros" (§15 y Anexo A.C) | `OperacionExentaType` declara **8 valores: E1…E8** — `SuministroInformacion.xsd`. Y el documento de validaciones v1.2.2 (apdos. 5.2 y 15.5) aclara que **el significado de cada código depende del impuesto**: con `Impuesto`=`01` (IVA) o vacío vale la lista L10 = **E1–E6**; con `Impuesto`=`03` (**IGIC**) valen además **E7 y E8**, y E1–E6 significan **otra cosa** (arts. de la Ley 20/1991 y 19/1994); con `Impuesto`=`02` (IPSI) E1–E6 significan una tercera cosa (Ley 8/1991) | **Corrección doble.** (a) La lista del `.md` es la de **IVA**, no la lista completa — un validador con E1–E6 fijos rechazaría facturas IGIC válidas. (b) La glosa "arts. 20, 21, 22…" **sólo vale para IVA**; presentarla como el significado universal del código es engañoso. Para esta agencia (IVA peninsular) el efecto práctico es nulo, pero el binding no debe cerrar el enum a 6 |
| **2** | `ClaveRegimen`: sin verificar; sólo se citaban las claves **14/15** para pagos anticipados | `IdOperacionesTrascendenciaTributariaType` = **18 valores con huecos: 01–11, 14, 15, 17, 18, 19, 20, 21**. **No existen 12, 13 ni 16** | Cierra el punto que estaba SIN VERIFICAR. Los huecos son reales, no un error de transcripción. El XSD no documenta los significados (sin `documentation` en ninguna enumeración) |
| **3** | Implícito: `RechazoPrevio` como indicador S/N | En `RegistroAlta` es `RechazoPrevioType` = **N, S, X** (tres valores). En `RegistroAnulacion` es `RechazoPrevioAnulacionType` = **S, N** (dos). **Son dos tipos distintos con el mismo nombre de elemento** | Trampa de binding. El `X` está documentado en el XSD: registro que existe en el SIF pero nunca se remitió a la AEAT; el propio XSD advierte que *"no deberían existir operaciones de alta (N,X), por lo que no se admiten"* |
| **4** | Anexo A.D: ⚠️ *"en los ejemplos XML de la AEAT el namespace es `.../tike/cont/ws/` (sin V1.0)… implementar el namespace tal como aparece en los ejemplos"* | Confirmado y **ya no es una peculiaridad observada en ejemplos**: el `targetNamespace` de **todos** los XSD y del WSDL descargados es `https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/…` — **sin `V1.0`** | La ⚠️ pasa a ✅. La URL física de descarga lleva `tikeV1.0`; el namespace declarado dentro del fichero, no. Es el fichero oficial el que lo dice, no una inferencia |

### ✅ Lo que se confirma exactamente como estaba

- `TipoFactura` = **F1, F2, R1, R2, R3, R4, R5, F3** (8 valores, en ese orden en el XSD). Coincide con lo que el proyecto daba por bueno.
- `CalificacionOperacion` = **S1, S2, N1, N2**, con los literales exactos que ya constaban.
- `IDType` de `IDOtro` = **02–07**, la lista empieza en 02, **no existe 01**. Confirmado.
- `TipoRectificativa` = **S** (`SUSTITUTIVA`) e **I** (`INCREMENTAL`). Coincide con "S/I"; nótese que el literal del XSD para `I` es *INCREMENTAL*, no "por diferencia" (la doc del elemento sí dice "por sustitución o por diferencia").
- `TipoHuella` = **un solo valor, `01` = SHA-256**. Confirmado.
- `TiempoEsperaEnvio` existe con ese nombre exacto en la respuesta y es numérico → confirma la corrección del 2026-08-12 (no `MinutosEsperaEnvio`).
- `PrimerRegistro` admite **únicamente el valor `S`** → confirma el Anexo A.A.
- `ConsultaFactuSistemaFacturacion` **sólo existe en el binding VERI\*FACTU**, no en el de requerimiento. Confirmado en el WSDL.
- Máximo **1.000 registros por envío** y **10.000 por respuesta de consulta** con `ClavePaginacion`. Confirmado en los XSD (`maxOccurs`), no sólo en la Orden.
- `ds:Signature` es `minOccurs="0"` → el esquema **no** obliga a firmar. Coherente con la decisión de no implementar XAdES en VERI\*FACTU.

### ⚠️ Precisiones nuevas que el documento no recogía (no son errores, pero cambian el binding)

| # | Hallazgo | Por qué importa |
|---|---|---|
| **5** | **`IDVersion` NO va en la `Cabecera`.** `CabeceraType` sólo tiene `ObligadoEmision`, `Representante`, `RemisionVoluntaria`, `RemisionRequerimiento`. `IDVersion` es el **primer elemento de cada `RegistroAlta`/`RegistroAnulacion`** | Error de binding clásico. La cabecera **de consulta** (`CabeceraConsultaSf`) sí lleva `IDVersion` — no confundirlas |
| **6** | **Dos formatos de fecha conviviendo en el mismo registro.** Todas las fechas son `sf:fecha` = `string` con patrón **`DD-MM-YYYY`**, salvo `FechaHoraHusoGenRegistro`, que es **`xs:dateTime`** (ISO 8601 con huso). Existe además un tipo `Timestamp` (`DD-MM-YYYY hh:mm:ss`) que **no se usa** en alta/anulación | Si el serializador aplica ISO a todo, la AEAT rechaza. Coherente con el vector de prueba de la huella: `FechaExpedicionFactura=01-01-2024` y `FechaHoraHusoGenRegistro=2024-01-01T19:20:30+01:00` |
| **7** | **`Desglose` admite como máximo 12 `DetalleDesglose`** (`maxOccurs="12"`), y `Desglose` es **obligatorio** | El `Desglose` es el **desglose fiscal** (por impuesto/calificación/tipo), **no las líneas de la factura**. Con 12 combinaciones sobra para esta agencia, pero el límite es duro |
| **8** | Dentro de `DetalleDesglose`, `CalificacionOperacion` y `OperacionExenta` forman un **`<choice>` obligatorio**: hay que informar **exactamente uno de los dos, siempre** | El `.md` decía "mutuamente excluyentes", correcto, pero no que uno de ellos es obligatorio en cada línea de desglose |
| **9** | **`ClaveRegimen` es opcional** (`minOccurs="0"`), igual que `Impuesto` | Del XSD no se deduce cuándo es obligatorio; eso lo fija el documento de validaciones |
| **10** | **`Destinatarios` es opcional** y admite hasta **1.000** `IDDestinatario` | Coherente con F2 / facturas sin identificación del destinatario |
| **11** | **Tres enumeraciones de estado casi homónimas y distintas**: `EstadoRegistro` de suministro (`Correcto`/`AceptadoConErrores`/`Incorrecto`), `EstadoRegistroDuplicado` (`Correcta`/`AceptadaConErrores`/`Anulada` — **en femenino**) y `EstadoRegistro` de consulta (`Correcto`/`AceptadoConErrores`/**`Anulado`**) | Tres tipos con nombres solapados en tres ficheros. Un binding que reutilice un solo enum se rompe |
| **12** | **Asimetría en `NumSerieFactura`**: en `IDFactura` es `TextoIDFacturaType` (**minLength 1**, maxLength 60); en `Encadenamiento/RegistroAnterior` es `TextMax60Type` (**sin mínimo**, maxLength 60) | Real, está en el XSD. No asumir el mismo tipo en ambos sitios |
| **13** | `SuministroInformacion.xsd` **importa el esquema XMLDSig por URL remota**: `http://www.w3.org/TR/xmldsig-core/xmldsig-core-schema.xsd` | La generación del binding (wsimport/xsd.exe/zeep) **fallará o se colgará sin red**, o si w3.org está lento. Bajar el `xmldsig-core-schema.xsd` en local y redirigir el `schemaLocation` con un catálogo |
| **14** | El WSDL importa los XSD con **`schemaLocation` relativo** (`SuministroInformacion.xsd`, etc.) | Los 6 ficheros deben estar en la **misma carpeta** al generar el binding. Ya lo están |
| **15** | Hay **8 endpoints, no 4**: 4 puertos del servicio `sfVerifactu` + 4 del servicio `sfRequerimiento` | El `.md` listaba los 4 de VERI\*FACTU, que es lo correcto para este proyecto. Se deja constancia de los otros 4 para que nadie los confunda |
| **16** | `RegistroAnulacion` **no lleva importes ni `NombreRazonEmisor`**: sólo identificación, quién lo generó, encadenamiento, sistema informático, fecha-hora y huella | Coherente con la fórmula de huella de anulación del Anexo A.A |

### ❗ Y lo que cambia por el documento de validaciones v1.2.2 (ver apartados 11 y 12)

| # | Hallazgo | Impacto |
|---|---|---|
| **17** | **El rechazo completo por estructura o por error sintáctico en la cabecera llega como `SoapFault`**, no como respuesta con `EstadoEnvio=Incorrecto` (apdo. 4.1) | El cliente SOAP debe tratar dos vías de error, no una. El WSDL no declara ningún `wsdl:fault`, así que el fault no viene tipado |
| **18** | ❗ **Con `CalificacionOperacion` = `N1` o `N2` e IVA, los campos `TipoImpositivo`, `CuotaRepercutida`, `TipoRecargoEquivalencia` y `CuotaRecargoEquivalencia` NO se pueden informar** (apdo. 15.4) | **Afecta de lleno a la casuística de §15**: los servicios a empresas extranjeras van a `N2`, y esos cuatro campos deben ir **ausentes del XML**, no a cero. Un serializador que emita `<CuotaRepercutida>0</CuotaRepercutida>` provoca rechazo |
| **19** | ❗ **`ClaveRegimen` es opcional en el XSD pero obligatoria en la validación** siempre que `Impuesto` sea `01`, `02`, `03` o esté vacío (código **1245**, apdo. 15.6) | Es decir: **siempre obligatoria en la práctica** para esta agencia. Con IVA debe pertenecer a la lista L8A |
| **20** | **`RechazoPrevio=X` es el mecanismo de "alta sin registro previo"** — el alta no tiene campo `SinRegistroPrevio`, sólo lo tiene la anulación (anexo 6) | Explica el valor `X` del XSD |
| **21** | ⚠️ **Un alta de subsanación sobre una factura ya anulada la REACTIVA** (consecuencia "OK (5)" del anexo 6) | Un reintento ciego puede *desanular* una factura. Refuerza la regla de §11 de no reenviar sin consultar antes |
| **22** | **`IDType=07` (No censado) exige `CodigoPais=ES`**; con `CodigoPais=ES` sólo se admite `IDType` `03` o `07`; con `IDType=02` (NIF-IVA) el `TipoFactura` sólo puede ser `F1`, `F3`, `R1`–`R4` (apdo. 13) | Relevante para clientes extranjeros, el caso habitual de la agencia |
| **23** | **Tipos impositivos de IVA admitidos con `S1`: 0; 2; 4; 5; 7,5; 10; 21**, con ventanas temporales para 5, 2 y 7,5 (apdo. 15.1) | Se puede validar en local antes de enviar |

---

## 1. WSDL — `SistemaFacturacion.wsdl` ✅

**`targetNamespace`:** `https://www2.agenciatributaria.gob.es/static_files/common/internet/dep/aplicaciones/es/aeat/tike/cont/ws/SistemaFacturacion.wsdl` — **`tike`, sin `V1.0`**.

### Mensajes

| `wsdl:message` | `part` → `element` | Namespace del elemento |
|---|---|---|
| `EntradaRegFactuSistemaFacturacion` | `sfLR:RegFactuSistemaFacturacion` | `…/tike/cont/ws/SuministroLR.xsd` |
| `EntradaConsultaFactuSistemaFacturacion` | `sfLRC:ConsultaFactuSistemaFacturacion` | `…/tike/cont/ws/ConsultaLR.xsd` |
| `RespuestaRegFactuSistemaFacturacion` | `sfR:RespuestaRegFactuSistemaFacturacion` | `…/tike/cont/ws/RespuestaSuministro.xsd` |
| `RespuestaConsultaFactuSistemaFacturacion` | `sfLRRC:RespuestaConsultaFactuSistemaFacturacion` | `…/tike/cont/ws/RespuestaConsultaLR.xsd` |

### PortTypes y bindings

| PortType | Binding | Operaciones | Estilo |
|---|---|---|---|
| `sfPortTypeVerifactu` | `sfVerifactu` | `RegFactuSistemaFacturacion`, `ConsultaFactuSistemaFacturacion` | `document` / `literal` / `http://schemas.xmlsoap.org/soap/http` |
| `sfPortTypePorRequerimiento` | `sfRequerimiento` | **sólo** `RegFactuSistemaFacturacion` | ídem |

✅ **`soapAction` está VACÍO** (`<soap:operation soapAction=""/>`) en **las tres** operaciones de los dos bindings. Confirmado literalmente en el fichero (líneas 44, 53 y 65). El cliente SOAP debe enviar la cabecera HTTP `SOAPAction: ""` — algunas librerías la omiten o inventan una, y eso rompe la llamada.

⚠️ **No hay `wsdl:fault` declarado en ninguna operación**, pero eso **no** significa que no haya faults. El documento de validaciones v1.2.2 (apdo. 4.1) es explícito: si la estructura no cumple el esquema o hay errores sintácticos **en la cabecera**, *"la respuesta se devolverá un mensaje de tipo «SoapFault»"*. Los errores de negocio por registro sí viajan dentro de la respuesta normal (`EstadoEnvio` / `EstadoRegistro`). **El cliente SOAP tiene que manejar las dos vías**: fault no tipado (envío entero perdido) y respuesta con estado parcial.

### Endpoints (8 puertos, 2 servicios)

**Servicio `sfVerifactu`** — *sistemas que emiten facturas verificables* (**el que usa este proyecto**):

| Puerto | Entorno | URL |
|---|---|---|
| `SistemaVerifactu` | Producción | `https://www1.agenciatributaria.gob.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP` |
| `SistemaVerifactuSello` | Producción, certificado de **sello** | `https://www10.agenciatributaria.gob.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP` |
| `SistemaVerifactuPruebas` | **Pruebas** | `https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP` |
| `SistemaVerifactuSelloPruebas` | Pruebas, certificado de **sello** | `https://prewww10.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP` |

**Servicio `sfRequerimiento`** — *sistemas NO verificables, remisión bajo requerimiento* (**no aplica a este proyecto**): mismos 4 hosts con path `…/SistemaFacturacion/RequerimientoSOAP`.

---

## 2. Raíz del envío y cabecera ✅

### `RegFactuSistemaFacturacion` — `SuministroLR.xsd`

| Elemento | Tipo | Ocurrencias |
|---|---|---|
| `Cabecera` | `sf:CabeceraType` | 1..1 |
| `RegistroFactura` | `sfLR:RegistroFacturaType` | **1..1000** |

`RegistroFacturaType` contiene un `<choice>`: `sf:RegistroAlta` **o** `sf:RegistroAnulacion`. ✅ Se pueden **mezclar altas y anulaciones en el mismo envío** (el choice es por cada `RegistroFactura`, no por lote).

### `CabeceraType` — `SuministroInformacion.xsd`

| Elemento | Tipo | Ocurr. | Restricciones |
|---|---|---|---|
| `ObligadoEmision` | `PersonaFisicaJuridicaESType` | **1..1** | |
| └ `NombreRazon` | `TextMax120Type` | 1..1 | maxLen 120 |
| └ `NIF` | `NIFType` | 1..1 | **length = 9 exacto** |
| `Representante` | `PersonaFisicaJuridicaESType` | 0..1 | mismos dos campos. Sólo si los registros los genera un representante/asesor |
| `RemisionVoluntaria` | *(complexType inline)* | 0..1 | |
| └ `FechaFinVeriFactu` | `fecha` | 0..1 | `DD-MM-YYYY` |
| └ `Incidencia` | `IncidenciaType` | 0..1 | `S` / `N` |
| `RemisionRequerimiento` | *(complexType inline)* | 0..1 | **no aplica a VERI\*FACTU** |
| └ `RefRequerimiento` | `TextMax18Type` | 1..1 | maxLen 18 |
| └ `FinRequerimiento` | `FinRequerimientoType` | 0..1 | `S` / `N` |

❗ **No hay `IDVersion` en la cabecera** — ver discrepancia #5.

📄 `ObligadoEmision` y `Representante` usan `PersonaFisicaJuridicaESType`: **NIF español obligatorio**, no admiten `IDOtro`.

---

## 3. `RegistroAlta` — estructura completa ✅

Tipo: `sf:RegistroFacturacionAltaType` en `SuministroInformacion.xsd`. **El orden de la tabla es el orden de la `<sequence>` y es obligatorio respetarlo.**

| # | Elemento | Tipo | Ocurr. | Restricción / valores |
|---|---|---|---|---|
| 1 | `IDVersion` | `VersionType` | **1..1** | enum de **1 valor: `1.0`** |
| 2 | `IDFactura` | `IDFacturaExpedidaType` | **1..1** | bloque |
| 2.1 | └ `IDEmisorFactura` | `NIFType` | 1..1 | length **9** |
| 2.2 | └ `NumSerieFactura` | `TextoIDFacturaType` | 1..1 | minLen **1**, maxLen **60** |
| 2.3 | └ `FechaExpedicionFactura` | `fecha` | 1..1 | length 10, patrón **`\d{2}-\d{2}-\d{4}`** (`DD-MM-YYYY`) |
| 3 | `RefExterna` | `TextMax60Type` | 0..1 | maxLen 60 — **campo libre del emisor, ideal para la clave de idempotencia del SIF** |
| 4 | `NombreRazonEmisor` | `TextMax120Type` | **1..1** | maxLen 120 |
| 5 | `Subsanacion` | `SubsanacionType` | 0..1 | `S` / `N` |
| 6 | `RechazoPrevio` | `RechazoPrevioType` | 0..1 | **`N` / `S` / `X`** ← ver discrepancia #3 |
| 7 | `TipoFactura` | `ClaveTipoFacturaType` | **1..1** | `F1 F2 R1 R2 R3 R4 R5 F3` |
| 8 | `TipoRectificativa` | `ClaveTipoRectificativaType` | 0..1 | `S` sustitutiva / `I` incremental |
| 9 | `FacturasRectificadas` | *(inline)* | 0..1 | |
| 9.1 | └ `IDFacturaRectificada` | `IDFacturaARType` | **1..1000** | `IDEmisorFactura` (9) + `NumSerieFactura` (1–60) + `FechaExpedicionFactura` (`DD-MM-YYYY`) |
| 10 | `FacturasSustituidas` | *(inline)* | 0..1 | |
| 10.1 | └ `IDFacturaSustituida` | `IDFacturaARType` | **1..1000** | misma estructura |
| 11 | `ImporteRectificacion` | `DesgloseRectificacionType` | 0..1 | *Desglose de base y cuota sustituida en rectificativas sustitutivas* |
| 11.1 | └ `BaseRectificada` | `ImporteSgn12.2Type` | **1..1** | `(+\|-)?\d{1,12}(\.\d{0,2})?` |
| 11.2 | └ `CuotaRectificada` | `ImporteSgn12.2Type` | **1..1** | ídem |
| 11.3 | └ `CuotaRecargoRectificado` | `ImporteSgn12.2Type` | 0..1 | ídem |
| 12 | `FechaOperacion` | `fecha` | 0..1 | `DD-MM-YYYY` |
| 13 | `DescripcionOperacion` | `TextMax500Type` | **1..1** | maxLen **500** |
| 14 | `FacturaSimplificadaArt7273` | `SimplificadaCualificadaType` | 0..1 | `S` / `N` |
| 15 | `FacturaSinIdentifDestinatarioArt61d` | `CompletaSinDestinatarioType` | 0..1 | `S` / `N` |
| 16 | `Macrodato` | `MacrodatoType` | 0..1 | `S` / `N` — factura por encima de un umbral |
| 17 | `EmitidaPorTerceroODestinatario` | `TercerosODestinatarioType` | 0..1 | `D` destinatario / `T` tercero |
| 18 | `Tercero` | `PersonaFisicaJuridicaType` | 0..1 | *Tercero que expide la factura y/o genera el registro de alta* |
| 18.1 | └ `NombreRazon` | `TextMax120Type` | 1..1 | maxLen 120 |
| 18.2 | └ **choice**: `NIF` \| `IDOtro` | | 1..1 | `NIF` length 9 · `IDOtro` = `CodigoPais` (0..1, ISO-3166-1 alfa-2, 246 valores) + `IDType` (1..1, **02–07**) + `ID` (1..1, maxLen 20) |
| 19 | `Destinatarios` | *(inline)* | **0..1** | *Contraparte de la operación. Cliente* |
| 19.1 | └ `IDDestinatario` | `PersonaFisicaJuridicaType` | **1..1000** | `NombreRazon` + choice `NIF` \| `IDOtro` (idéntico a 18) |
| 20 | `Cupon` | `CuponType` | 0..1 | `S` / `N` |
| 21 | `Desglose` | `DesgloseType` | **1..1** | |
| 21.1 | └ `DetalleDesglose` | `DetalleType` | **1..12** | ← límite duro, ver tabla siguiente |
| 22 | `CuotaTotal` | `ImporteSgn12.2Type` | **1..1** | `(+\|-)?\d{1,12}(\.\d{0,2})?` — **entra en la huella** |
| 23 | `ImporteTotal` | `ImporteSgn12.2Type` | **1..1** | ídem — **entra en la huella** |
| 24 | `Encadenamiento` | *(inline, choice)* | **1..1** | ver bloque abajo |
| 25 | `SistemaInformatico` | `SistemaInformaticoType` | **1..1** | ver bloque abajo |
| 26 | `FechaHoraHusoGenRegistro` | **`xs:dateTime`** | **1..1** | **ISO 8601 con huso** (`2024-01-01T19:20:30+01:00`) — **entra en la huella** |
| 27 | `NumRegistroAcuerdoFacturacion` | `TextMax15Type` | 0..1 | maxLen 15 |
| 28 | `IdAcuerdoSistemaInformatico` | `TextMax16Type` | 0..1 | maxLen 16 |
| 29 | `TipoHuella` | `TipoHuellaType` | **1..1** | enum de 1 valor: **`01` = SHA-256** |
| 30 | `Huella` | `TextMax64Type` | **1..1** | maxLen **64** → hex mayúsculas de 64 caracteres |
| 31 | `ds:Signature` | *(XMLDSig)* | **0..1** | **opcional** — no obligatorio por esquema |

### 3.1 `DetalleDesglose` (`DetalleType`) — 1..12 ✅

| # | Elemento | Tipo | Ocurr. | Valores / patrón |
|---|---|---|---|---|
| 1 | `Impuesto` | `ImpuestoType` | 0..1 | `01` IVA · `02` IPSI Ceuta y Melilla · `03` IGIC · `05` Otros — **no existe `04`** |
| 2 | `ClaveRegimen` | `IdOperacionesTrascendenciaTributariaType` | 0..1 | **`01 02 03 04 05 06 07 08 09 10 11 14 15 17 18 19 20 21`** (sin 12, 13, 16) |
| 3 | **choice obligatorio** | | **1..1** | exactamente uno de los dos: |
| 3a | └ `CalificacionOperacion` | `CalificacionOperacionType` | | `S1` sujeta y no exenta sin ISP · `S2` sujeta y no exenta con ISP · `N1` no sujeta art. 7, 14, otros · `N2` no sujeta por reglas de localización |
| 3b | └ `OperacionExenta` | `OperacionExentaType` | | **`E1 E2 E3 E4 E5 E6 E7 E8`** ← 8 valores, sin documentación en el XSD |
| 4 | `TipoImpositivo` | `Tipo2.2Type` | 0..1 | `\d{1,3}(\.\d{0,2})?` — **sin signo** |
| 5 | `BaseImponibleOimporteNoSujeto` | `ImporteSgn12.2Type` | **1..1** | `(+\|-)?\d{1,12}(\.\d{0,2})?` |
| 6 | `BaseImponibleACoste` | `ImporteSgn12.2Type` | 0..1 | ídem |
| 7 | `CuotaRepercutida` | `ImporteSgn12.2Type` | 0..1 | ídem |
| 8 | `TipoRecargoEquivalencia` | `Tipo2.2Type` | 0..1 | sin signo |
| 9 | `CuotaRecargoEquivalencia` | `ImporteSgn12.2Type` | 0..1 | ídem |

**Único campo obligatorio del detalle además del choice: `BaseImponibleOimporteNoSujeto`.**

### 3.2 `Encadenamiento` — cómo se expresa el primer registro ✅

`Encadenamiento` es **obligatorio** (`1..1`) y contiene un **`<choice>`** de dos ramas. **No es un flag más un bloque: son alternativas excluyentes.**

```xml
<!-- Primer registro de la cadena -->
<Encadenamiento>
  <PrimerRegistro>S</PrimerRegistro>   <!-- PrimerRegistroCadenaType: enum de UN solo valor, "S" -->
</Encadenamiento>

<!-- Resto de registros -->
<Encadenamiento>
  <RegistroAnterior>
    <IDEmisorFactura>…</IDEmisorFactura>            <!-- NIFType, length 9 -->
    <NumSerieFactura>…</NumSerieFactura>            <!-- TextMax60Type (sin minLength) -->
    <FechaExpedicionFactura>DD-MM-YYYY</FechaExpedicionFactura>
    <Huella>…</Huella>                              <!-- TextMax64Type -->
  </RegistroAnterior>
</Encadenamiento>
```

✅ Confirma el Anexo A.A: `PrimerRegistro` sólo admite `S`; **no existe un valor `N`**. La ausencia del primer registro se expresa poniendo la otra rama del choice, no un `N`.

### 3.3 `SistemaInformatico` (`SistemaInformaticoType`) ✅

**Los 9 campos son obligatorios** (salvo `CodigoPais` dentro de `IDOtro`). Este es el bloque que identifica al micro-SIF ante la AEAT.

| # | Elemento | Tipo | Ocurr. | Restricción |
|---|---|---|---|---|
| 1 | `NombreRazon` | `TextMax120Type` | 1..1 | maxLen 120 — productor del sistema |
| 2 | **choice**: `NIF` \| `IDOtro` | | 1..1 | `NIF` length 9 · `IDOtro` = `CodigoPais`(0..1) + `IDType`(02–07) + `ID`(maxLen 20) |
| 3 | `NombreSistemaInformatico` | `TextMax30Type` | 1..1 | **maxLen 30** |
| 4 | `IdSistemaInformatico` | `TextMax2Type` | 1..1 | **maxLen 2** ← dos caracteres, elegidos por el productor |
| 5 | `Version` | `TextMax50Type` | 1..1 | maxLen 50 |
| 6 | `NumeroInstalacion` | `TextMax100Type` | 1..1 | maxLen 100 |
| 7 | `TipoUsoPosibleSoloVerifactu` | `SiNoType` | 1..1 | `S` / `N` → **para este proyecto: `S`** |
| 8 | `TipoUsoPosibleMultiOT` | `SiNoType` | 1..1 | `S` / `N` → **`N`** (un solo obligado tributario) |
| 9 | `IndicadorMultiplesOT` | `SiNoType` | 1..1 | `S` / `N` → **`N`** |

📄 Existe una variante `SistemaInformaticoConsultaType` (usada como filtro de consulta) donde casi todo pasa a `minOccurs="0"` salvo `NombreRazon`, el choice de identificación, `IdSistemaInformatico` y `NumeroInstalacion`. **No confundirla con la del registro.**

---

## 4. `RegistroAnulacion` — estructura completa ✅

Tipo: `sf:RegistroFacturacionAnulacionType` en `SuministroInformacion.xsd`. **13 elementos**, frente a los 31 del alta.

| # | Elemento | Tipo | Ocurr. | Restricción / valores |
|---|---|---|---|---|
| 1 | `IDVersion` | `VersionType` | **1..1** | `1.0` |
| 2 | `IDFactura` | **`IDFacturaExpedidaBajaType`** | **1..1** | ← **tipo distinto al del alta, con nombres de campo distintos** |
| 2.1 | └ `IDEmisorFacturaAnulada` | `NIFType` | 1..1 | length 9 |
| 2.2 | └ `NumSerieFacturaAnulada` | `TextoIDFacturaType` | 1..1 | minLen 1, maxLen 60 |
| 2.3 | └ `FechaExpedicionFacturaAnulada` | `fecha` | 1..1 | `DD-MM-YYYY` |
| 3 | `RefExterna` | `TextMax60Type` | 0..1 | maxLen 60 |
| 4 | `SinRegistroPrevio` | `SinRegistroPrevioType` | 0..1 | `S` / `N` |
| 5 | `RechazoPrevio` | **`RechazoPrevioAnulacionType`** | 0..1 | **`S` / `N`** (aquí **no** hay `X`) |
| 6 | `GeneradoPor` | `GeneradoPorType` | 0..1 | `E` expedidor · `D` destinatario · `T` tercero |
| 7 | `Generador` | `PersonaFisicaJuridicaType` | 0..1 | `NombreRazon` + choice `NIF` \| `IDOtro` |
| 8 | `Encadenamiento` | *(inline, choice)* | **1..1** | idéntico al del alta: `PrimerRegistro`=`S` \| `RegistroAnterior` |
| 9 | `SistemaInformatico` | `SistemaInformaticoType` | **1..1** | idéntico al del alta (9 campos obligatorios) |
| 10 | `FechaHoraHusoGenRegistro` | **`xs:dateTime`** | **1..1** | ISO 8601 con huso |
| 11 | `TipoHuella` | `TipoHuellaType` | **1..1** | `01` = SHA-256 |
| 12 | `Huella` | `TextMax64Type` | **1..1** | maxLen 64 |
| 13 | `ds:Signature` | *(XMLDSig)* | **0..1** | opcional |

✅ Los nombres `IDEmisorFacturaAnulada` / `NumSerieFacturaAnulada` / `FechaExpedicionFacturaAnulada` confirman literalmente la fórmula de huella de anulación del Anexo A.A, y que el campo horario se llama `FechaHoraHusoGenRegistro` (no `…GenEvento`).

---

## 5. Respuesta al envío — `RespuestaSuministro.xsd` ✅

Elemento raíz: `RespuestaRegFactuSistemaFacturacion`, tipo `RespuestaRegFactuSistemaFacturacionType`, que **extiende** `RespuestaBaseType`. En XSD `complexContent/extension` la secuencia heredada va **antes**, así que el orden real de los hijos es:

| # | Elemento | Tipo | Ocurr. | Notas del XSD |
|---|---|---|---|---|
| 1 | **`CSV`** | `xs:string` | **0..1** | *"CSV asociado al envío generado por AEAT. **Sólo se genera si no hay rechazo del envío**"*. 📄 **Sin límite de longitud declarado** |
| 2 | `DatosPresentacion` | `DatosPresentacionType` | 0..1 | *"Sólo se genera si no hay rechazo del envío"* |
| 2.1 | └ `NIFPresentador` | `NIFType` | 1..1 | length 9 |
| 2.2 | └ `TimestampPresentacion` | `xs:dateTime` | 1..1 | |
| 3 | `Cabecera` | `CabeceraType` | **1..1** | *"Se devuelve la cabecera que se incluyó en el envío"* |
| 4 | **`TiempoEsperaEnvio`** | `Tipo6Type` | **1..1** | patrón `\d{0,4}` → **máximo 4 dígitos** (≤ 9999). Tipado como **string**, no como entero |
| 5 | **`EstadoEnvio`** | `EstadoEnvioType` | **1..1** | ver enum abajo |
| 6 | `RespuestaLinea` | `RespuestaExpedidaType` | **0..1000** | *"Estado detallado de cada línea del suministro"* |

### `RespuestaLinea` (`RespuestaExpedidaType`)

| # | Elemento | Tipo | Ocurr. | Notas |
|---|---|---|---|---|
| 1 | `IDFactura` | `IDFacturaExpedidaType` | 1..1 | `IDEmisorFactura` + `NumSerieFactura` + `FechaExpedicionFactura` — **siempre en formato de alta**, incluso al responder a una anulación |
| 2 | `Operacion` | `OperacionType` | 1..1 | `TipoOperacion` (**`Alta`** / **`Anulacion`**) + `Subsanacion` (0..1) + `RechazoPrevio` (0..1) + `SinRegistroPrevio` (0..1) |
| 3 | `RefExterna` | `TextMax60Type` | 0..1 | ✅ **la AEAT devuelve la `RefExterna` enviada** → mecanismo natural de correlación con la factura de XTRF |
| 4 | **`EstadoRegistro`** | `EstadoRegistroType` | 1..1 | ver enum abajo |
| 5 | **`CodigoErrorRegistro`** | `ErrorDetalleType` | **0..1** | `restriction base="integer"` — **entero sin más restricción, sin lista de valores en el XSD** |
| 6 | **`DescripcionErrorRegistro`** | `TextMax1500Type` | **0..1** | **maxLen 1500** |
| 7 | `RegistroDuplicado` | `RegistroDuplicadoType` | 0..1 | *"Sólo en el caso de que se rechace el registro por duplicado"* |
| 7.1 | └ `IdPeticionRegistroDuplicado` | `TextMax20Type` | 1..1 | `IdPeticion` del registro ya almacenado |
| 7.2 | └ `EstadoRegistroDuplicado` | `EstadoRegistroSFType` | 1..1 | `Correcta` / `AceptadaConErrores` / `Anulada` |
| 7.3 | └ `CodigoErrorRegistro` | `ErrorDetalleType` | 0..1 | del registro duplicado ya almacenado |
| 7.4 | └ `DescripcionErrorRegistro` | `TextMax500Type` | 0..1 | **maxLen 500 aquí, 1500 en el nivel superior** |

**Dónde vienen los tres datos que preguntaba el proyecto:**

- **`CSV`** → nivel superior de la respuesta, **uno por envío**, no por factura. Sólo si el envío no se rechaza en bloque.
- **`CodigoErrorRegistro`** y **`DescripcionErrorRegistro`** → dentro de cada **`RespuestaLinea`**, es decir **por registro**, no por envío. Y otra pareja homónima dentro de `RegistroDuplicado`, que se refiere al registro *previamente almacenado*, no al que se acaba de enviar.

### Enumeraciones de estado

| Tipo | Valores | Documentación literal del XSD |
|---|---|---|
| **`EstadoEnvioType`** | `Correcto` | Correcto |
| | `ParcialmenteCorrecto` | Parcialmente correcto. Ver detalle de errores |
| | `Incorrecto` | Incorrecto |
| **`EstadoRegistroType`** (suministro) | `Correcto` · `AceptadoConErrores` · `Incorrecto` | "Aceptado con Errores. Ver detalle del error" |
| **`EstadoRegistroSFType`** (duplicado) | `Correcta` · `AceptadaConErrores` · `Anulada` | **en femenino** |
| **`EstadoRegistroType`** (`RespuestaConsultaLR.xsd`) | `Correcto` · `AceptadoConErrores` · **`Anulado`** | tercer valor distinto |

📄 Regla de composición documentada en el propio XSD: cabecera y **todos** los registros correctos → `Correcto`; cabecera correcta y **todos** los registros incorrectos → `Incorrecto`; cabecera correcta y **al menos uno** incorrecto → `ParcialmenteCorrecto`.

---

## 6. Consulta — `ConsultaLR.xsd` / `RespuestaConsultaLR.xsd` 📄

Sólo disponible en el binding VERI\*FACTU. Resumen para el binding:

- **Petición** `ConsultaFactuSistemaFacturacion` = `Cabecera` (`CabeceraConsultaSf`: **`IDVersion`** + choice `ObligadoEmision` \| `Destinatario` + `IndicadorRepresentante` opcional, único valor `S`) + `FiltroConsulta` + `DatosAdicionalesRespuesta` (opcional).
- **`FiltroConsulta`** (`LRFiltroRegFacturacionType`): `PeriodoImputacion` (**obligatorio**: `Ejercicio` `YYYY` + `Periodo` `01`–`12`), `NumSerieFactura`, `Contraparte`, `FechaExpedicionFactura` (fecha suelta **o** rango `Desde`/`Hasta`), `SistemaInformatico`, `RefExterna`, `ClavePaginacion` — todos opcionales salvo el periodo.
- **`DatosAdicionalesRespuesta`**: `MostrarNombreRazonEmisor` y `MostrarSistemaInformatico` (`S`/`N`); el XSD avisa de que ponerlos a `S` **aumenta el tiempo de respuesta**.
- **Respuesta**: hasta **10.000** `RegistroRespuestaConsultaFactuSistemaFacturacion` + `ClavePaginacion` (0..1) + `IndicadorPaginacion` (`S`/`N`) + `ResultadoConsulta` (`ConDatos` / `SinDatos`). ✅ Confirma el límite de 10.000 y el mecanismo de paginación del Anexo A.D.
- La respuesta de consulta añade campos que **no** existen en el registro de alta: `TimestampUltimaModificacion` (`xs:dateTime`), `NifRepresentante`, `FechaFinVeriFactu`, `Incidencia`, y `DatosPresentacion2Type` (que sí incluye **`IdPeticion`**, `TextMax20Type`).

---

## 7. `EventosSIF.xsd` 📄 — fuera de alcance, se documenta por completitud

El registro de eventos **no aplica** a un SIF exclusivamente VERI\*FACTU (art. 3 Orden HAC/1177/2024). Se deja constancia de que el XSD existe y declara dos listas cerradas por si el SIF pasara alguna vez a ser dual:

- **`TipoEventoType`** — 11 valores: `01` inicio funcionamiento como NO VERI\*FACTU · `02` fin · `03` lanzamiento detección de anomalías en registros de facturación · `04` detección de anomalías en facturación · `05` lanzamiento detección en registros de evento · `06` detección en eventos · `07` restauración de copia de seguridad · `08` exportación de registros de facturación · `09` exportación de registros de evento · `10` registro resumen de eventos · `90` otros voluntarios.
- **`TipoAnomaliaType`** — 16 valores (`01`–`15` y `90`) sobre integridad (huella/firma) y trazabilidad (cadena de registro, cadena de huella, fechas).

---

## 8. Versión de los esquemas ⚠️

**No hay número de versión de fichero en ningún XSD ni en el WSDL.** Lo único que hay:

- ✅ **`IDVersion` = `1.0`** (`VersionType`, enumeración de un solo valor) dentro de cada `RegistroAlta`, `RegistroAnulacion`, cabecera de consulta y registro de evento. Es la única versión declarada, y es **la versión del formato del registro**, no del fichero.
- 📄 La ruta física de descarga incluye `tikeV1.0`, pero eso es la URL, no el namespace.
- 📄 Los únicos comentarios de los ficheros son marcas del editor (`XMLSpy v2019 sp1` / `v2009 sp1`, "por AEAT / Puesto de Trabajo / PC Corporativo"). No hay fecha ni changelog.

⚠️ **Consecuencia práctica:** no hay forma de detectar desde los propios ficheros si la AEAT publica una revisión. Hay que vigilar la página de información técnica o comparar hashes de los ficheros periódicamente.

---

## 9. Catálogo de tipos simples reutilizables (para el binding) ✅

| Tipo | Base | Restricción |
|---|---|---|
| `NIFType` | string | **length = 9 exacto** (no maxLength) |
| `fecha` | string | length 10, `\d{2}-\d{2}-\d{4}` → **`DD-MM-YYYY`** |
| `Timestamp` | string | length 19, `DD-MM-YYYY hh:mm:ss` — **no usado en alta/anulación** |
| `TextoIDFacturaType` | string | minLen 1, maxLen 60 |
| `ImporteSgn12.2Type` | string | `(\+\|-)?\d{1,12}(\.\d{0,2})?` — **punto decimal, signo opcional, hasta 2 decimales** |
| `ImporteSgn14.2Type` | string | `(\+\|-)?\d{1,14}(\.\d{0,2})?` — declarado pero **no usado** en alta/anulación |
| `Tipo2.2Type` | string | `\d{1,3}(\.\d{0,2})?` — **sin signo** (tipos impositivos) |
| `Tipo6Type` | string | `\d{0,4}` — usado por `TiempoEsperaEnvio` (nombre engañoso) |
| `YearType` | string | length 4, `\d{4}` |
| `ErrorDetalleType` | **integer** | sin más restricción |
| `TextMaxNType` | string | maxLen N — se declaran N = 1, 2, 15, 16, 18, 20, 25, 30, 34, 40, 50, 60, 64, 65, 70, 100, 120, 150, 250, 500, 1500 |

⚠️ **Todos los importes son `string` con patrón, no `decimal`.** El binding no debe mapearlos a `BigDecimal` sin un adaptador que serialice con punto y sin separador de miles, o el XML dejará de validar. Lo mismo con las fechas: son `string`, no `xs:date`.

---

## 10. Checklist para generar el binding SOAP

1. Copiar `xmldsig-core-schema.xsd` en local y redirigir el `schemaLocation` remoto de `SuministroInformacion.xsd` (línea 3) con un catálogo XML — si no, la generación depende de w3.org. ⚠️
2. Generar desde `SistemaFacturacion.wsdl` con los 6 XSD en la misma carpeta.
3. Usar el binding/puerto **`sfVerifactu` / `SistemaVerifactuPruebas`** para la fase 1, y `SistemaVerifactu` para producción.
4. Forzar la cabecera HTTP **`SOAPAction: ""`** (vacía, pero presente). ✅
5. Namespaces del mensaje: `…/tike/cont/ws/SuministroLR.xsd` para la raíz y `…/tike/cont/ws/SuministroInformacion.xsd` para los registros. **Sin `V1.0`.** ✅
6. Adaptadores de serialización: importes `string` con punto decimal; fechas `DD-MM-YYYY`; `FechaHoraHusoGenRegistro` en `xs:dateTime` con huso.
7. Respetar el orden de `<sequence>` al construir el XML: **el esquema es posicional**, no un mapa de campos.
8. `Huella` en **hexadecimal mayúsculas de 64 caracteres**, `TipoHuella` = `01`.
9. Leer `TiempoEsperaEnvio` de **cada** respuesta y obedecerlo.
10. Correlacionar la respuesta con la factura de XTRF por **`RefExterna`** (la AEAT la devuelve tal cual en `RespuestaLinea`).

---

## 11. Documento de validaciones y códigos de error ✅ — CONSEGUIDO

Sí se localizó y descargó. **Dos ficheros**, ambos verificados en disco (el PDF empieza por `%PDF-1.7`, no es una página de error):

| Fichero | Ruta | Tamaño | Origen |
|---|---|---|---|
| `Validaciones_Errores_VERIFACTU_1.2.2.pdf` | `C:\Users\NEOMUX\Desktop\OTROS\aeat-esquemas\` | 659 KB, **28 páginas** | Sede AEAT / Portal de Desarrolladores |
| `errores.properties` | ídem | 25 KB, **latin-1 (no UTF-8)** | `https://prewww2.aeat.es/static_files/…/tikeV1.0/cont/ws/errores.properties` — el recurso estático que el propio PDF cita en su apdo. 4.4 |

**Versión del documento: 1.2.2, de 08/04/2026** (verificado en el histórico de revisiones de las páginas 1–3, no en el nombre del fichero). Título oficial: *"Validaciones — Sistemas Informáticos de Facturación y Sistemas VERI\*FACTU"*, Departamento de Informática Tributaria.

### Recuento total: **247 códigos**, en tres categorías

| Categoría (literal del fichero) | Nº | Rango de códigos | Efecto |
|---|---|---|---|
| Códigos que provocan el **rechazo del envío completo** | **44** | `4102`–`4145` aprox. | Se pierde el envío entero |
| Códigos que provocan el **rechazo de la factura** (o de la petición completa si el error está en la cabecera) | **193** | `1100`–`1299`, `3000`–`3002` | `EstadoRegistro` = `Incorrecto` |
| Códigos que producen la **aceptación del registro** (posteriormente deben ser subsanados) | **10** | `2000`–`2009` | `EstadoRegistro` = `AceptadoConErrores` |

### Los 10 códigos "aceptado con errores" — **la lista completa, y la más importante para el diseño del SIF** ✅

Son los únicos errores que **no** rechazan el registro. Reproducidos literalmente:

| Código | Descripción |
|---|---|
| **2000** | El cálculo de la huella suministrada es incorrecta. |
| **2001** | El NIF del bloque Destinatarios no está identificado en el censo de la AEAT. |
| **2002** | La longitud de huella del registro anterior no cumple con las especificaciones. |
| **2003** | El contenido de la huella del registro anterior no cumple con las especificaciones. |
| **2004** | El valor del campo FechaHoraHusoGenRegistro debe ser la fecha actual del sistema de la AEAT, admitiéndose un margen de error de: |
| **2005** | El campo ImporteTotal tiene un valor incorrecto para el valor de los campos BaseImponibleOimporteNoSujeto, CuotaRepercutida y CuotaRecargoEquivalencia suministrados. |
| **2006** | El campo CuotaTotal tiene un valor incorrecto para el valor de los campos CuotaRepercutida y CuotaRecargoEquivalencia suministrados. |
| **2007** | No debe informarse como primer registro, existen facturas emitidas con el obligado emisión y el sistema informático actual. |
| **2008** | El valor de la huella del registro anterior debe ser diferente a la huella del registro actual. |
| **2009** | Si el campo Impuesto tiene valor IPSI(02) el campo ClaveRegimen debe de estar cumplimentado. |

✅ **El 2000 confirma el Anexo A.A**: una huella mal calculada deja el registro *aceptado con errores*, no rechazado.
⚠️ **El 2007 es una alarma de diseño directa:** si el SIF vuelve a marcar `PrimerRegistro=S` cuando la AEAT ya tiene registros de ese SIF+NIF, la AEAT lo acepta *con error* y hay que subsanar. Es exactamente el fallo que produciría una reinstalación o una pérdida del estado de la cadena. Merece un test y una alerta propia.
📄 El apdo. 4.3.1 aclara que **2009 y 2004 están exceptuados de la obligación de subsanar**; los otros ocho sí hay que subsanarlos.

### Muestra representativa de los otros 237

**Rechazo del envío completo (cabecera / estructura) — 44 códigos, muestra:**

| Código | Descripción |
|---|---|
| 4102 | El XML no cumple el esquema. Falta informar campo obligatorio. |
| 4103 | Se ha producido un error inesperado al parsear el XML. |
| **4104** | Error en la cabecera: el valor del campo NIF del bloque ObligadoEmision no está identificado. ← *el código que el proyecto ya había visto de pasada* |
| 4105 | Error en la cabecera: el valor del campo NIF del bloque Representante no está identificado. |
| 4106 | El formato de fecha es incorrecto. |
| 4107 | El NIF no está identificado en el censo de la AEAT. |
| 4109 | El formato del NIF es incorrecto. |
| 4112 | El titular del certificado debe ser Obligado Emisión, Colaborador Social, Apoderado o Sucesor. |
| 4113 | El XML no cumple con el esquema: se ha superado el límite permitido de registros para el bloque. |
| **4114** | El XML no cumple con el esquema: se ha superado el límite máximo permitido de facturas a registrar. ← *el tope de 1.000* |
| 4119 | Error al informar caracteres cuya codificación no es UTF-8. |
| 4120 | Error en la cabecera: el valor del campo FechaFinVeriFactu es incorrecto, debe ser 31-12-20XX, donde XX corresponde con el año actual o el anterior. |
| 4126 | Error en la cabecera: el campo RefRequerimiento solo debe informarse en remisiones al endpoint del servicio de contestación a requerimientos. |
| 4127 | Error en la cabecera: la remisión voluntaria solo debe informarse en sistemas VERIFACTU. |
| 4130 | Error en la cabecera: el campo FinRequerimiento solo debe informarse en sistemas No VERIFACTU. |

**Rechazo de la factura — 193 códigos, muestra de los estructurales, de encadenamiento y de duplicados:**

| Código | Descripción |
|---|---|
| 1100 | Valor o tipo incorrecto del campo. |
| 1104 | El valor del campo NumSerieFactura es incorrecto. |
| 1105 | El valor del campo FechaExpedicionFactura es incorrecto. |
| **1108** | El NIF del IDEmisorFactura debe ser el mismo que el NIF del ObligadoEmision. |
| **1180** | Error en el bloque de Encadenamiento. |
| 1182 | El valor del campo OperacionExenta es incorrecto. |
| **1195** | Al menos uno de los dos campos OperacionExenta o CalificacionOperacion deben estar informados. |
| **1196** | OperacionExenta o CalificacionOperacion no pueden ser ambos informados ya que son excluyentes entre sí. |
| 1245 | Si el campo Impuesto está vacío o tiene valor IVA(01) o IPSI(02) o IGIC(03) el campo ClaveRegimen debe de estar cumplimentado. |
| 1246 | El valor del campo ClaveRegimen es incorrecto. |
| 1247 | El valor del campo TipoHuella es incorrecto. |
| 1262 | La longitud de huella no cumple con las especificaciones. |
| **3000** | Registro de facturación duplicado. |
| **3001** | El registro de facturación ya ha sido dado de baja. |
| **3002** | No existe el registro de facturación. |

✅ **1195 y 1196 confirman el `<choice>` del XSD**: uno de los dos, exactamente uno, siempre.
⚠️ **1245 corrige un matiz**: el XSD marca `ClaveRegimen` como `minOccurs="0"`, pero la validación de negocio la hace **obligatoria** siempre que `Impuesto` sea 01, 02, 03 o esté vacío — es decir, en la práctica **siempre** para esta agencia. *Opcional en el esquema, obligatorio en la validación.*

### Hallazgos del documento de validaciones con impacto directo en el diseño

1. ❗ **El rechazo completo por estructura o cabecera llega como `SoapFault`** (apdo. 4.1), no como respuesta con `EstadoEnvio=Incorrecto`. Hay que tratar las dos vías.
2. ✅ **Subsanación:** se hace remitiendo **un nuevo registro de alta con el mismo identificador de factura** y `Subsanacion=S`. No hay operación distinta. Aplica a errores admisibles, a registros rechazados y a datos incorrectos detectados después (apdo. 4.3.1). Sólo cuando el caso **no** exija emitir una rectificativa.
3. ✅ **Tipos impositivos admitidos** para `Impuesto`=IVA y `CalificacionOperacion`=`S1`: **0; 2; 4; 5; 7,5; 10 y 21**, con ventanas temporales para el 5, el 2 y el 7,5 (apdo. 15.1). Un validador local puede comprobarlo antes de enviar.
4. ✅ Si `CalificacionOperacion` es **`S2`** (inversión del sujeto pasivo): `TipoImpositivo`=0 y `CuotaRepercutida`=0 **obligatorios**, no vacíos ni ausentes. Si es **`N1`/`N2`** con IVA: `TipoImpositivo`, `CuotaRepercutida`, `TipoRecargoEquivalencia` y `CuotaRecargoEquivalencia` **no se pueden informar** (apdo. 15.4). ⚠️ **Esto afecta directamente a la casuística de §15 del documento maestro** (servicios a empresas de otros países → `N2`): esos cuatro campos deben quedar **ausentes**, no a cero.
5. ✅ Si `OperacionExenta` está cumplimentado, esos mismos cuatro campos tampoco se pueden informar (apdo. 15.5).
6. ✅ `IDType`=`07` (No censado) exige `CodigoPais`=`ES`; con `CodigoPais`=`ES` sólo se admite `IDType` `03` o `07`; con `IDType`=`02` (NIF-IVA) el `TipoFactura` debe ser `F1`, `F3`, `R1`, `R2`, `R3` o `R4` (apdo. 13). ⚠️ **Relevante para clientes extranjeros**, el caso habitual de esta agencia.
7. ✅ `Cupon` sólo puede valer `S` si `TipoFactura` es `R5` o `R1`.
8. ✅ El anexo 6 del PDF (págs. 26–28) contiene los **cuadros de operativas de alta y anulación admisibles**. Es el material que el proyecto tenía anotado como "Excel de casuísticas (Alta / Alta por rechazo / Subsanación / Anulación)" y que estaba en otro sitio. **Ya está aquí** — transcrito en el apartado 12.

---

## 12. Operativas de alta y anulación admisibles ✅

Fuente: `Validaciones_Errores_VERIFACTU_1.2.2.pdf`, anexo 6, páginas 26–28. Esto es **la tabla de combinaciones válidas** de los flags del registro: ni `Subsanacion`, ni `RechazoPrevio`, ni `SinRegistroPrevio` son libres.

### 12.1 Alta — 6 operativas

| Operativa | `Subsanacion` | `RechazoPrevio` | Cuándo se usa | Tipo SIF |
|---|---|---|---|---|
| **ALTA** (habitual) | no informar **o** `N` | no informar **o** `N` | Alta inicial. El registro **no debe existir** en el SIF ni en la AEAT | VERI\*FACTU y NO VERI\*FACTU |
| **ALTA POR RECHAZO** | `S` | **`X`** | El alta inicial **fue rechazada** por la AEAT, así que la clave única **no existe** allí | sólo VERI\*FACTU |
| **ALTA DE SUBSANACIÓN** | `S` | no informar **o** `N` | Subsanación habitual de un registro **ya remitido y aceptado** | VERI\*FACTU y NO VERI\*FACTU |
| **ALTA POR RECHAZO DE SUBSANACIÓN** | `S` | **`S`** | El registro existe en la AEAT y **la subsanación posterior fue rechazada** | sólo VERI\*FACTU |
| **ALTA DE SUBSANACIÓN SIN REGISTRO PREVIO** | `S` | **`X`** | El registro existe en el SIF pero **nunca llegó a la AEAT** (p. ej. paso de NO VERI\*FACTU a VERI\*FACTU) | VERI\*FACTU; NO VERI\*FACTU opcional |
| **ALTA POR RECHAZO DE SUBSANACIÓN SIN REGISTRO PREVIO** | `S` | **`X`** | Igual que la anterior, pero además su subsanación fue rechazada | sólo VERI\*FACTU |

📄 **Nota:** `RegistroAlta` **no tiene** campo `SinRegistroPrevio` (sólo lo tiene la anulación). En las altas, el caso "sin registro previo" se expresa con **`RechazoPrevio=X`**. Eso explica el valor `X` que el XSD documenta y que el `.md` no recogía.

**Consecuencias según la situación en la AEAT** (leyenda del propio anexo):

| Operativa enviada | No existe registro | Existe registro de **alta** | Existe registro de **anulación** |
|---|---|---|---|
| ALTA / ALTA POR RECHAZO | **OK (1)** se admite | ERROR (2) | ERROR (2) |
| ALTA DE SUBSANACIÓN (y su variante por rechazo) | ERROR (3) | **OK (4)** sustituye completamente | **OK (5)** *reactiva* el registro anulado y lo sustituye |
| ALTA … SIN REGISTRO PREVIO | **OK (1)** | ERROR (2) | ERROR (2) |

- **ERROR (2)** = no puede recibirse un alta de esas características existiendo ya cualquier registro de esa factura.
- **ERROR (3)** = debería existir ya un registro para esa factura; si es por una secuencia de envío incorrecta, **basta reenviar** una vez haya entrado el registro previo.
- ⚠️ **OK (5) es un hallazgo importante**: un **alta de subsanación sobre una factura anulada la REACTIVA**, la vuelve a dejar de alta y en vigor. Un reintento ciego puede *desanular* una factura. Refuerza la regla ya existente de "no reenviar a ciegas sin `ConsultaFactuSistemaFacturacion`".

### 12.2 Anulación — 4 operativas

| Operativa | `SinRegistroPrevio` | `RechazoPrevio` | Cuándo | Tipo SIF |
|---|---|---|---|---|
| **ANULACIÓN** (habitual) | no informar **o** `N` | no informar **o** `N` | El registro **debe existir** en SIF y AEAT | VERI\*FACTU y NO VERI\*FACTU |
| **ANULACIÓN POR RECHAZO** | no informar **o** `N` | **`S`** | La anulación previa **fue rechazada**; la clave sí existe en la AEAT | sólo VERI\*FACTU |
| **ANULACIÓN SIN REGISTRO PREVIO** | **`S`** | no informar **o** `N` | El registro existe en el SIF pero **no en la AEAT** | VERI\*FACTU; NO VERI\*FACTU opcional |
| **ANULACIÓN POR RECHAZO SIN REGISTRO PREVIO** | **`S`** | **`S`** | Igual, y además el intento anterior fue rechazado | sólo VERI\*FACTU |

| Operativa enviada | No existe registro | Existe registro de **alta** | Existe registro de **anulación** |
|---|---|---|---|
| ANULACIÓN / ANULACIÓN POR RECHAZO | ERROR (6) | **OK (7)** anula el alta | **OK (8)** anula la anulación dejando los nuevos datos |
| ANULACIÓN SIN REGISTRO PREVIO (y variante) | **OK (9)** crea el registro de anulación | ERROR (10) | ERROR (10) |

- **ERROR (6)** = debería existir un registro previo de esa factura.
- **ERROR (10)** = en una anulación *sin registro previo* no puede haber en la AEAT **ningún** registro de esa factura, ni de alta ni de anulación.

✅ **Para este proyecto (VERI\*FACTU puro, sin histórico anterior), las únicas operativas que se van a usar son: ALTA, ALTA POR RECHAZO, ALTA DE SUBSANACIÓN y ANULACIÓN.** Las variantes "sin registro previo" sólo tienen sentido si se migrara desde un SIF NO VERI\*FACTU, que no es el caso.
