# Integración Perú SUNAT

## SEE – Sistemas del Contribuyente

Este proyecto implementa emisión desde los sistemas del contribuyente y se conecta directamente a SUNAT. Cada tenant resuelve RUC, razón social, usuario/Clave SOL, certificado, password del certificado, series, correlativos, configuración tributaria y ambiente. No existe una configuración global única como diseño de producción.

## Ambientes

### MOCK

Funciona sin red ni secretos: genera modelo, XML, firma autofirmada temporal, valida firma/XSD, crea ZIP/SOAP y CDR simulado. Su estado final es `MOCK_VALIDATED`; nunca representa aceptación tributaria y la CDR contiene `MOCK - NO VÁLIDO TRIBUTARIAMENTE`.

### BETA

Usa el endpoint oficial BETA y autenticación `RUC + MODDATOS`. El password se configura como secreto. `npm run sunat:test:beta` está fuera de CI, requiere `SUNAT_RUN_BETA_TESTS=true` y emite únicamente dos facturas secuenciales PEN/USD.

Una CDR BETA código `0` se conserva como `ACCEPTED`, pero `tributaryValidity` sólo puede ser `true` en producción.

### Producción

Usa `RUC + usuarioSOL` y Clave SOL para WS-Security; el certificado y su clave privada firman el XML. Son credenciales distintas. El runtime exige MongoDB/S3 o equivalentes durables, gestor de secretos explícito, JWT tenant y secreto del portal. Además se exige `SUNAT_ALLOW_REAL_EMISSION=true` para impedir emisiones accidentales desde tests o desarrollo.

## Contrato JSON y validación

Zod valida la solicitud antes de reservar/empaquetar. El controlador nunca construye XML. El emisor se inyecta desde configuración confiable y `decimal.js` calcula importes con `ROUND_HALF_UP`; los campos monetarios se serializan como strings.

Catálogos de documento, identidad, moneda, unidad, afectación IGV, operación, leyendas y motivos de notas están centralizados. La metadata `SUNAT_RULESET` identifica reglas, fecha, URL y SHA-256.

## Documentos

- `01`: factura UBL 2.1, `sendBill` síncrono.
- `03`: boleta UBL 2.1; no usa `sendBill`, espera Resumen Diario.
- `07` y `08`: notas UBL 2.1 con referencia obligatoria y motivo de catálogo.
- `RC`: Resumen Diario, `sendSummary` + ticket + `getStatus`; condiciones `1` (emitir), `3` (anular) y `4` (anular en el día).
- `RA`: Comunicación de Baja, mismo flujo asíncrono.

Factura incluye precio de venta tipo `01`, valor unitario sin tributos, forma de pago `Contado` o crédito/cuotas, domicilio fiscal con código de establecimiento anexo, impuestos y totales. También soporta detracción general `1001` para facturas PEN y USD con catálogo 54, cuenta del Banco de la Nación, catálogo 59, porcentaje, monto calculado con Decimal y leyenda `2006`. En USD el consumidor debe informar el tipo de cambio promedio ponderado venta SBS y su fecha legalmente aplicable (nacimiento de la obligación tributaria o depósito, la que ocurra primero; si no hubo publicación, el último publicado); la detracción se convierte y expresa siempre en PEN. Los casos especializados `1002` (recursos hidrobiológicos) y `1004` (transporte de carga), además de ISC, ICBPER, percepciones, anticipos y exportación avanzada, permanecen fuera del alcance anunciado.

Las notas de crédito y débito están implementadas mediante `POST /credit-notes` y `POST /debit-notes`. Se generan en UBL 2.1, se firman, validan contra XSD y referencian obligatoriamente un comprobante existente del mismo tenant, ambiente, cliente y moneda. Las notas sobre facturas usan `FCxx`/`FDxx` y `sendBill`; las asociadas a boletas usan `BCxx`/`BDxx` y esperan Resumen Diario.

## Certificados y firma

Se admiten PFX, P12 y PEM. El loader normaliza certificado, clave privada, serial, issuer, subject y vigencias. Estados: `VALID`, `EXPIRING`, `EXPIRED`, `INVALID`.

La firma usa XMLDSig enveloped sobre el documento completo, C14N, RSA-SHA256 y digest SHA-256. Luego se verifica localmente, se valida el XML firmado contra los XSD oficiales y recién se crea el ZIP. Certificados, claves y passwords nunca entran en logs ni archivos temporales del pipeline.

## CDR y estados

HTTP 200 no equivale a aceptación. La CDR determina `ACCEPTED`, `ACCEPTED_WITH_OBSERVATIONS` o `REJECTED`. Los tickets distinguen `PROCESSING` (`98`), error (`99`) y final con CDR.

La máquina conserva historial desde `DRAFT`, `GENERATED`, `VALIDATED`, `SIGNED`, `ZIPPED`, `SENDING` y `SENT`, hasta un estado final o ambiguo. Cada transmisión registra operación, intento, duración, HTTP y error sanitizado.

El worker durable reclama con lease tickets `PROCESSING`/`UNKNOWN`, aplica backoff y continúa después de reinicios. Una baja rechazada restaura el estado tributario previo del comprobante en lugar de convertirlo erróneamente en rechazado.

## Idempotencia y correlativos

Cada POST exige `Idempotency-Key`. Si se repite, retorna el mismo registro. Los correlativos son atómicos por tenant, país, tipo y serie. Un timeout no reserva otro número ni dispara un reenvío ciego; primero se intenta reconciliar con consulta CDR.

## Artefactos e integridad

Por documento se conserva JSON canónico, XML sin firma, XML firmado, ZIP, CDR ZIP/XML y CDR normalizada. Cada artefacto incluye SHA-256. `LocalArtifactStorage` sirve desarrollo y `S3ArtifactStorage` usa AWS SDK v3.

## Seguridad multitenant

Todos los repositorios filtran por `tenantId`; índices únicos también lo incluyen. En producción se valida un Bearer JWT HMAC con `tenantId` y `sub`; un `X-Tenant-Id` falsificado no cambia el contexto. La base almacena sólo referencias a secretos. Logs estructurados enmascaran RUC y eliminan claves con nombres sensibles.

Las notas buscan el comprobante afectado y validan tenant, ambiente, RUC, estado, moneda y cliente antes de reservar el correlativo. En producción también se controla que cada serie esté autorizada y se rechazan el RUC BETA y el usuario `MODDATOS`.

## PDF y portal del receptor

El PDF es una representación del mismo dominio canónico e incluye QR nivel Q con RUC, tipo, serie, número, IGV, total, fecha, documento del receptor y `DigestValue` del XML firmado. `PublicDocumentAccess` emite tokens aleatorios revocables, guarda sólo su HMAC y concede por defecto 366 días de lectura/descarga de PDF y XML.

## Operación

```bash
npm test
npm run sunat:test:mock
npm run sunat:generate:test-certificate
npm run sunat:test:beta
npm run sunat:test:beta:matrix
npm run sunat:test:beta:voided
```

`GET /internal/health/sunat` valida configuración, certificado y capacidad de generar UBL 2.1 en memoria, sin reservar correlativo, persistir ni transmitir. `GET /internal/metrics` expone contadores y latencia Prometheus.

## Resultado BETA del 25-08-2026

SUNAT aceptó con CDR código `0` dos facturas de prueba, enviadas secuencialmente:

- `F001-3978204`, PEN, total 118.00.
- `F001-3978205`, USD, total 118.00.

El informe y todos los artefactos están bajo `test/.generated/beta`. Son comprobantes del ambiente BETA y no tienen efectos tributarios de producción.

La reejecución final de la matriz ampliada, hecha con el código entregado, obtuvo CDR código `0` para:

- Factura `F001-77777648`.
- Nota de crédito de factura `FC01-77777648`.
- Nota de débito de factura `FD01-77777648`.
- Boleta `B001-77777648`, nota de crédito `BC01-77777648` y nota de débito `BD01-77777648`, incluidas en `RC-20260825-37648` aceptado.
- En una prueba independiente para no reenviar una RA de resultado de transporte ambiguo, SUNAT aceptó `RA-20260825-19471`; la factura auxiliar `F099-77849471` terminó en `VOIDED`.

Los seis PDFs y el reporte consolidado están bajo `output/pdf/beta-matrix/20260825170937646`; el reporte de baja está bajo `output/pdf/beta-matrix/ra-20260825171049469`. Los envíos fueron secuenciales, sin concurrencia ni carga. Las ejecuciones BETA no tienen validez tributaria de producción.

## Paso a producción

1. Verificar requisitos SEE del Contribuyente y calidad de emisor.
2. Crear la configuración del tenant con RUC/razón social/series.
3. Guardar Clave SOL, certificado y password mediante referencias `aws-sm:` u otro `SecretProvider` inyectado.
4. Instalar certificado válido de la empresa y verificar RUC/vigencia.
5. Ejecutar MOCK y una validación BETA controlada.
6. Configurar MongoDB, S3, JWT tenant, portal privado y worker asíncrono.
7. Habilitar `SUNAT_ALLOW_REAL_EMISSION=true` sólo en el despliegue autorizado; los endpoints oficiales no se sobrescriben por defecto.
8. Emitir una única factura real controlada y verificar CDR, QR, portal, conciliación y contabilidad antes del rollout.
9. Monitorear CDR, errores de transporte, certificados próximos a vencer y documentos `UNKNOWN`/`PROCESSING`.

Las fuentes DOC-01 a DOC-16 y las decisiones de compatibilidad están enumeradas en [FUENTES.md](FUENTES.md).

Para ejemplos visuales de consumo, JSON y respuestas, abrir [consumo-sunat-directo.html](consumo-sunat-directo.html).
