419 lines
8.7 KiB
Markdown
419 lines
8.7 KiB
Markdown
|
|
# Proformas Reports
|
||
|
|
|
||
|
|
## Resumen funcional
|
||
|
|
|
||
|
|
El flujo activo de reports de proformas en `modules/customer-invoices` ya no usa un endpoint ambiguo con `format`.
|
||
|
|
|
||
|
|
El endpoint legacy eliminado era:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
GET /proformas/:proforma_id/report?format=pdf|html|json
|
||
|
|
```
|
||
|
|
|
||
|
|
El estado actual separa explícitamente:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
GET /proformas/:proforma_id/report/pdf
|
||
|
|
GET /proformas/:proforma_id/report/preview
|
||
|
|
```
|
||
|
|
|
||
|
|
No existe soporte JSON para reports de proformas.
|
||
|
|
|
||
|
|
## Endpoints finales
|
||
|
|
|
||
|
|
### Descarga PDF
|
||
|
|
|
||
|
|
Endpoint:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
GET /proformas/:proforma_id/report/pdf
|
||
|
|
```
|
||
|
|
|
||
|
|
Comportamiento:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- Content-Type: application/pdf
|
||
|
|
- descarga como attachment
|
||
|
|
- render con FastReport PDF
|
||
|
|
- plantilla: proforma.frx
|
||
|
|
- sin firma digital
|
||
|
|
- cache solo si la proforma no está en draft
|
||
|
|
- sin query format
|
||
|
|
```
|
||
|
|
|
||
|
|
### Preview HTML
|
||
|
|
|
||
|
|
Endpoint:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
GET /proformas/:proforma_id/report/preview
|
||
|
|
```
|
||
|
|
|
||
|
|
Comportamiento:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- Content-Type: text/html; charset=utf-8
|
||
|
|
- render inline
|
||
|
|
- FastReport HTML
|
||
|
|
- plantilla: proforma.frx
|
||
|
|
- sin firma digital
|
||
|
|
- sin cache
|
||
|
|
- sin query format
|
||
|
|
```
|
||
|
|
|
||
|
|
Uso previsto:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- visualizar el contenido de una proforma desde la lista
|
||
|
|
- previsualizar cómo quedaría la proforma antes de exportarla a PDF
|
||
|
|
```
|
||
|
|
|
||
|
|
Limitación actual:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
Solo previsualiza una proforma persistida.
|
||
|
|
No existe preview de cambios no guardados del formulario.
|
||
|
|
```
|
||
|
|
|
||
|
|
No existen todavía endpoints como:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
POST /proformas/report/preview
|
||
|
|
POST /proformas/:proforma_id/report/preview
|
||
|
|
```
|
||
|
|
|
||
|
|
## Flujo técnico
|
||
|
|
|
||
|
|
Flujo conceptual:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
Route
|
||
|
|
-> Controller
|
||
|
|
-> Use case
|
||
|
|
-> Proforma finder / read model assembler
|
||
|
|
-> Full snapshot
|
||
|
|
-> Report snapshot
|
||
|
|
-> Document pipeline
|
||
|
|
-> FastReport renderer
|
||
|
|
-> HTTP response
|
||
|
|
```
|
||
|
|
|
||
|
|
Separación por capas:
|
||
|
|
|
||
|
|
### Application
|
||
|
|
|
||
|
|
Responsabilidades:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- use cases
|
||
|
|
- builders
|
||
|
|
- modelos de report
|
||
|
|
- errores funcionales
|
||
|
|
- puertos como CompanyReportProfileFinder
|
||
|
|
```
|
||
|
|
|
||
|
|
Reglas:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- Application no depende de Express, Sequelize, filesystem ni FastReport directamente
|
||
|
|
- los use cases devuelven Result
|
||
|
|
```
|
||
|
|
|
||
|
|
### Infrastructure
|
||
|
|
|
||
|
|
Responsabilidades:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- routes Express
|
||
|
|
- controllers
|
||
|
|
- adapters
|
||
|
|
- FastReport renderers
|
||
|
|
- document pipelines
|
||
|
|
- cache/storage
|
||
|
|
```
|
||
|
|
|
||
|
|
Reglas:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- los controllers no contienen lógica documental
|
||
|
|
- FastReport vive en Infrastructure
|
||
|
|
- no hay firma digital en el pipeline de proformas
|
||
|
|
- no hay acoplamiento con issued-invoices
|
||
|
|
```
|
||
|
|
|
||
|
|
## Diferencias entre PDF y HTML preview
|
||
|
|
|
||
|
|
| Aspecto | PDF | HTML preview |
|
||
|
|
| --- | --- | --- |
|
||
|
|
| Endpoint | `/report/pdf` | `/report/preview` |
|
||
|
|
| MIME type | `application/pdf` | `text/html; charset=utf-8` |
|
||
|
|
| Disposition | `attachment` | `inline` |
|
||
|
|
| Renderer | FastReport PDF | FastReport HTML |
|
||
|
|
| Cache | solo no `draft` | no |
|
||
|
|
| Firma digital | no | no |
|
||
|
|
|
||
|
|
## Reglas de cache
|
||
|
|
|
||
|
|
La cache PDF usa una `storageKey` determinista.
|
||
|
|
|
||
|
|
La key V1 incluye:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
companyId
|
||
|
|
proformaId
|
||
|
|
status
|
||
|
|
format=pdf
|
||
|
|
languageCode
|
||
|
|
currencyCode
|
||
|
|
companyProfile.slug
|
||
|
|
companyProfile.version si existe
|
||
|
|
```
|
||
|
|
|
||
|
|
Regla funcional aplicada:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
Una proforma no draft no puede modificarse.
|
||
|
|
```
|
||
|
|
|
||
|
|
Por tanto:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
draft:
|
||
|
|
- no cachear PDF
|
||
|
|
|
||
|
|
non-draft:
|
||
|
|
- cachear PDF
|
||
|
|
```
|
||
|
|
|
||
|
|
La cache se considera segura respecto al contenido de la proforma cuando `status !== "draft"` por la inmutabilidad funcional de estados no draft.
|
||
|
|
|
||
|
|
Deuda pendiente:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- invalidación por cambios de plantilla
|
||
|
|
- invalidación por cambios de branding/logo/datos empresa
|
||
|
|
- invalidación por una versión documental más rica cuando exista
|
||
|
|
```
|
||
|
|
|
||
|
|
## Reglas de firma digital
|
||
|
|
|
||
|
|
Las proformas no se firman digitalmente.
|
||
|
|
|
||
|
|
Regla explícita:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
La firma digital aplica a issued invoices, no a proformas.
|
||
|
|
```
|
||
|
|
|
||
|
|
Esto evita copiar incorrectamente el pipeline de `issued-invoices` dentro del flujo de proformas.
|
||
|
|
|
||
|
|
## CompanyReportProfile y error 409
|
||
|
|
|
||
|
|
El report de proforma necesita datos reales de empresa.
|
||
|
|
|
||
|
|
No se puede renderizar una proforma sin `CompanyReportProfile`.
|
||
|
|
|
||
|
|
Si el perfil no existe:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
CompanyReportProfileNotFoundError
|
||
|
|
```
|
||
|
|
|
||
|
|
se mapea a:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
409 Conflict
|
||
|
|
```
|
||
|
|
|
||
|
|
Motivo:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
La proforma existe, pero falta configuración documental de empresa.
|
||
|
|
```
|
||
|
|
|
||
|
|
No está permitido:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- inventar datos de empresa
|
||
|
|
- hardcodear companySlug
|
||
|
|
- continuar renderizando con datos incompletos
|
||
|
|
- devolver error genérico 500
|
||
|
|
```
|
||
|
|
|
||
|
|
Actualmente `CompanyReportProfileFinder` usa el servicio público de `companies`.
|
||
|
|
|
||
|
|
Campos que hoy pueden no venir expuestos por `companies` y quedan como `Maybe.none()`:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
locale
|
||
|
|
currencyCode
|
||
|
|
logo
|
||
|
|
address
|
||
|
|
version
|
||
|
|
```
|
||
|
|
|
||
|
|
## Localization
|
||
|
|
|
||
|
|
El flujo usa un modelo explícito:
|
||
|
|
|
||
|
|
```ts
|
||
|
|
export type ReportLocalization = {
|
||
|
|
languageCode: string;
|
||
|
|
locale: string;
|
||
|
|
currencyCode: string;
|
||
|
|
};
|
||
|
|
```
|
||
|
|
|
||
|
|
Criterio funcional:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- languageCode representa idioma: es, en, fr...
|
||
|
|
- locale representa formato regional: es-ES, en-GB...
|
||
|
|
- currencyCode representa moneda: EUR, USD...
|
||
|
|
```
|
||
|
|
|
||
|
|
Prioridad funcional deseada:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
1. valores guardados en el documento
|
||
|
|
2. valores del cliente/recipient si existen
|
||
|
|
3. valores de la empresa
|
||
|
|
4. fallback técnico controlado
|
||
|
|
```
|
||
|
|
|
||
|
|
No debe repetirse la incoherencia anterior entre `languageCode` y `locale`.
|
||
|
|
|
||
|
|
## Ficheros principales
|
||
|
|
|
||
|
|
Rutas y controllers:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/express/proformas.routes.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/express/controllers/report-proforma-pdf.controller.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/express/controllers/preview-proforma-report.controller.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
Use cases:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/src/api/application/proformas/use-cases/report-proforma-pdf.use-case.ts
|
||
|
|
modules/customer-invoices/src/api/application/proformas/use-cases/preview-proforma-report.use-case.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
Errores y mapping HTTP:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/src/api/application/proformas/errors/company-report-profile-not-found.error.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/express/proformas-api-error-mapper.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
Adapter de empresa:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/adapters/company-report-profile-finder.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
Pipelines y renderers:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/pipelines/proforma-pdf-document-pipeline-factory.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/pipelines/proforma-html-preview-pipeline-factory.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/renderers/fastreport/proforma-pdf-document-renderer.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/renderers/fastreport/proforma-html-preview-renderer.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
Metadata, cache y persistencia de documentos:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/services/proforma-pdf-document-metadata-factory.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/services/proforma-html-preview-document-metadata-factory.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/pre-processors/proforma-pdf-cache-pre-processor.ts
|
||
|
|
modules/customer-invoices/src/api/infrastructure/proformas/documents/side-effects/persist-proforma-pdf-side-effect.ts
|
||
|
|
```
|
||
|
|
|
||
|
|
Template:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/templates/rodax/es/proforma.frx
|
||
|
|
```
|
||
|
|
|
||
|
|
## Legacy eliminado
|
||
|
|
|
||
|
|
Ya no existe:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
GET /proformas/:proforma_id/report
|
||
|
|
```
|
||
|
|
|
||
|
|
También se eliminó el soporte ambiguo:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
format=pdf|html|json
|
||
|
|
```
|
||
|
|
|
||
|
|
Legacy eliminado del árbol de aplicación:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
modules/customer-invoices/src/api/application/proformas/use-cases/report-proforma2
|
||
|
|
```
|
||
|
|
|
||
|
|
Motivo:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- legacy no cableado
|
||
|
|
- no referenciado por rutas, DI, exports ni tests
|
||
|
|
- contaminaba el typecheck del módulo
|
||
|
|
```
|
||
|
|
|
||
|
|
No debe reintroducirse:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
report-proforma2
|
||
|
|
ReportProformaUseCase legacy
|
||
|
|
format=pdf|html|json
|
||
|
|
/proformas/:proforma_id/report
|
||
|
|
```
|
||
|
|
|
||
|
|
## Frontend
|
||
|
|
|
||
|
|
No se ha cambiado todavía el frontend para preview HTML.
|
||
|
|
|
||
|
|
Sí se actualizó la descarga PDF para apuntar al endpoint nuevo:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
/report/pdf
|
||
|
|
```
|
||
|
|
|
||
|
|
Pendiente:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- crear cliente web para /report/preview
|
||
|
|
- integrar preview HTML en lista/editor
|
||
|
|
- probar si el HTML generado por FastReport es usable dentro de iframe/panel/modal
|
||
|
|
```
|
||
|
|
|
||
|
|
## Deuda pendiente
|
||
|
|
|
||
|
|
Pendientes explícitos:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
- invalidación de cache por cambios de plantilla
|
||
|
|
- invalidación de cache por cambios de branding/logo/datos empresa
|
||
|
|
- exposición futura de logo, address, locale, currencyCode y version desde companies
|
||
|
|
- cliente frontend para /report/preview
|
||
|
|
- preview de cambios no guardados del formulario
|
||
|
|
- errores TypeScript restantes en otras zonas de customer-invoices no relacionadas con reports de proformas
|
||
|
|
```
|
||
|
|
|
||
|
|
## Próximos pasos recomendados
|
||
|
|
|
||
|
|
Siguientes pasos razonables:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
1. exponer más campos documentales desde companies
|
||
|
|
2. introducir invalidación de cache por plantilla/branding
|
||
|
|
3. añadir cliente frontend para /report/preview
|
||
|
|
4. validar si el HTML de FastReport es usable en iframe/panel/modal
|
||
|
|
5. diseñar preview de cambios no guardados sin persistencia
|
||
|
|
```
|