Uecko_ERP/docs/document-series/document-series-design.md

97 lines
4.3 KiB
Markdown

# Document Series Design
## Objetivo del módulo
`document-series` es un módulo propio porque la serie documental no es un catálogo estático: mantiene reglas de vigencia, flags de activación, defaults y estado transaccional de numeración.
## Por qué no vive en catalogs
Los catálogos del ERP resuelven valores de referencia. Aquí hay concurrencia, bloqueo de fila y mutación transaccional de `next_number`, así que el comportamiento es operativo y no meramente descriptivo.
## Por qué numeración y serie viven juntas
La numeración depende del estado de la serie:
- si está activa
- si está vigente
- si es la serie por defecto
- cuál es su prefijo, sufijo y padding
Separarlo introduciría doble escritura o lecturas no atómicas.
## Modelo conceptual
- `DocumentType`: tipo documental cerrado en V1
- `DocumentSeries`: agregado con configuración y contador
- `AssignedDocumentNumber`: resultado de asignación atómica
## Campos principales
- `companyId`, `branchId`
- `documentType`
- `code`, `name`, `description`
- `prefix`, `suffix`
- `nextNumber`, `padding`
- `validFrom`, `validTo`
- `isDefault`, `isActive`
## Reglas V1
- tipos soportados: `proforma`, `issued_invoice`
- no asigna si la serie está inactiva
- no asigna si la serie está fuera de vigencia
- default por empresa + tipo, con prioridad de `branch_id` cuando aplica
- formato de referencia: `prefix + padded(next_number) + suffix`
## Concurrencia
La asignación usa transacción obligatoria y bloqueo de fila con `LOCK.UPDATE` sobre `document_series`. El incremento de `next_number` se persiste dentro de la misma transacción y con comprobación optimista del valor previo para evitar dobles consumos.
## Integracion con customer-invoices
En V1:
- `issued-invoices` delega la asignacion de numero en `document-series`
- `proformas` delega la asignacion de referencia en `document-series`
- `proformas` persiste `document_series_id` y `proforma_number` como snapshot tecnico adicional a `proforma_reference`
- `proformas.document_series_id` identifica la serie documental usada para numerar la proforma
- `proformas.proforma_number` guarda el numero propio de la proforma
- `proformas.proforma_reference` guarda la referencia visible de la proforma
- `proforma_series_code` es el input funcional de create para elegir la serie de `document_type = proforma`
- `proformas.target_invoice_series_code` es opcional y, cuando existe, apunta a una serie de `issued_invoice`, nunca a una serie de `proforma`
- create de proforma solo usa `document-series` para numerar la cabecera inicial
- create de proforma puede persistir `tax_config` sin materializar impuestos
- una proforma puede crearse sin lineas y seguir siendo valida como borrador inicial
- si no hay lineas valoradas, `proforma_taxes` debe quedar vacia y los totales monetarios a `0`
- si `proformas.target_invoice_series_code` es `NULL`, la emision resuelve la serie default activa de `issued_invoice`
- en Fase 2E, `series` deja de ser el contrato nuevo para create/update de proformas
- la UI consulta `GET /document-series` con filtro por `document_type` y `is_active = true`
- la UI no consume `POST /document-series/assign-next` para previsualizar numeracion
- `/catalogs/invoice-series` deja de existir como endpoint runtime
- `customer_invoice_series` no participa ya en flujos activos de lectura o numeracion
## Migracion conservadora
- la migracion historica de `issued_invoice` parte de `customer_invoice_series`
- la creacion de series default de `proforma` usa `companies` como fuente
- las validaciones SQL se mantienen separadas del script de migracion
- no hay ejecucion automatica ni cutover productivo en esta fase
- la DDL de `proformas` usa `information_schema` + SQL dinamico para mantener compatibilidad MariaDB/MySQL sin depender de `IF NOT EXISTS` en `ALTER TABLE`
## Branch scope pendiente
El modelo ya contempla `branchId`, y la resolucion default da prioridad a `branch_id` cuando existe. Aun asi, `customer-invoices` no propaga un contexto real de sucursal hasta `assignNextNumber(...)`, asi que en esta fase toda la integracion sigue operando con alcance de empresa.
## Límites V1
- sin `format_pattern`
- sin reseteos anuales automáticos
- sin reservas de numeración
- sin huecos justificados
- sin migración productiva automática de legacy
## Extensiones futuras
- nuevos `DocumentType`
- seeds/migraciones controladas de series heredadas