101 lines
2.7 KiB
Markdown
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.
|