FactuGES_ERP/docs/customer-invoices/proforma-issuance-readiness-contract.md
david 080dcaaa61 feat: implement GetProformaIssuanceReadiness use case and associated controller
- Add GetProformaIssuanceReadinessUseCase to check proforma issuance readiness.
- Create GetProformaIssuanceReadinessController to handle requests and responses.
- Introduce request and response DTOs for proforma issuance readiness.
- Develop tests for the use case and controller to ensure functionality.
- Implement adapter and hooks for integrating issuance readiness in the web application.
- Create UI components for displaying issuance readiness alerts and help popover.
- Add utility functions for translating blocker messages and details.
2026-08-18 23:03:04 +02:00

101 lines
2.7 KiB
Markdown

# Contrato de readiness de emisión de proformas
## Objetivo
La readiness de emisión es una lectura informativa del estado persistido de una proforma.
Su propósito es responder:
```txt
¿Puede emitirse esta proforma ahora mismo?
```
No sustituye la validación transaccional final de:
```txt
PUT /proformas/:id/issue
```
La emisión sigue revalidando siempre en backend para cubrir concurrencia y cambios entre consulta y submit.
## Endpoint vigente
```http
GET /proformas/:proforma_id/issuance-readiness
```
Comportamiento:
```txt
- 200 cuando la proforma existe dentro del scope de company
- 200 aunque can_issue sea false
- blockers con códigos estables orientados a frontend
- sin textos i18n en backend
```
No se expone readiness completa en el listado de proformas para evitar N+1 HTTP y resolución externa por fila.
## Contrato HTTP
```json
{
"can_issue": false,
"blockers": [
{ "code": "missing_operation_date" },
{ "code": "missing_description" }
]
}
```
## Códigos públicos
| Code | Significado |
| ---- | ----------- |
| `already_issued` | La proforma ya tiene emisión materializada o enlazada. |
| `invalid_status` | El estado actual no permite emitir; hoy debe estar aprobada. |
| `missing_description` | Falta la descripción obligatoria para emitir. |
| `missing_operation_date` | Falta la fecha de operación. |
| `incomplete_recipient` | Faltan datos fiscales mínimos del destinatario. |
| `missing_items` | No existen líneas de detalle persistidas. |
| `missing_payment_method` | Falta la forma de pago. |
| `missing_tax_regime` | Falta el régimen fiscal. |
| `payment_method_unavailable` | La referencia company-scoped de forma de pago no se puede resolver. |
| `payment_method_inactive` | La forma de pago resuelta existe, pero está inactiva. |
## Fuente de verdad
La semántica se reparte de forma explícita pero sin duplicar reglas:
```txt
Proforma.getIssuanceBlockers()
-> blockers internos de dominio
Proforma.validateCanBeIssued()
-> consume el primer blocker compatible con el contrato legacy de error
ProformaIssuanceReadinessChecker
-> añade blockers externos dependientes de catálogos
```
Esto permite:
```txt
readiness
-> enumerar blockers útiles
issue
-> seguir fallando de forma autoritativa
```
## Semántica importante en frontend
- La readiness representa el estado guardado en backend.
- Los cambios no guardados del editor no alteran este read model.
- Tras guardar, cambiar estado o emitir, la query de readiness debe invalidarse.
## Pendientes fuera de esta fase
- exponer readiness en listado sin introducir N+1;
- migrar la ruta legacy de emisión de `PUT` a un contrato nuevo si se aprueba;
- deep-link o focus directo al campo bloqueado desde frontend.