Uecko_ERP/docs/customer-invoices/proformas-reports.md
2026-07-07 17:40:16 +02:00

8.7 KiB

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:

GET /proformas/:proforma_id/report?format=pdf|html|json

El estado actual separa explícitamente:

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:

GET /proformas/:proforma_id/report/pdf

Comportamiento:

- 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:

GET /proformas/:proforma_id/report/preview

Comportamiento:

- Content-Type: text/html; charset=utf-8
- render inline
- FastReport HTML
- plantilla: proforma.frx
- sin firma digital
- sin cache
- sin query format

Uso previsto:

- visualizar el contenido de una proforma desde la lista
- previsualizar cómo quedaría la proforma antes de exportarla a PDF

Limitación actual:

Solo previsualiza una proforma persistida.
No existe preview de cambios no guardados del formulario.

No existen todavía endpoints como:

POST /proformas/report/preview
POST /proformas/:proforma_id/report/preview

Flujo técnico

Flujo conceptual:

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:

- use cases
- builders
- modelos de report
- errores funcionales
- puertos como CompanyReportProfileFinder

Reglas:

- Application no depende de Express, Sequelize, filesystem ni FastReport directamente
- los use cases devuelven Result

Infrastructure

Responsabilidades:

- routes Express
- controllers
- adapters
- FastReport renderers
- document pipelines
- cache/storage

Reglas:

- 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:

companyId
proformaId
status
format=pdf
languageCode
currencyCode
companyProfile.slug
companyProfile.version si existe

Regla funcional aplicada:

Una proforma no draft no puede modificarse.

Por tanto:

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:

- 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:

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:

CompanyReportProfileNotFoundError

se mapea a:

409 Conflict

Motivo:

La proforma existe, pero falta configuración documental de empresa.

No está permitido:

- 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():

locale
currencyCode
logo
address
version

Localization

El flujo usa un modelo explícito:

export type ReportLocalization = {
  languageCode: string;
  locale: string;
  currencyCode: string;
};

Criterio funcional:

- languageCode representa idioma: es, en, fr...
- locale representa formato regional: es-ES, en-GB...
- currencyCode representa moneda: EUR, USD...

Prioridad funcional deseada:

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:

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:

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:

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:

modules/customer-invoices/src/api/infrastructure/proformas/adapters/company-report-profile-finder.ts

Pipelines y renderers:

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:

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:

modules/customer-invoices/templates/rodax/es/proforma.frx

Legacy eliminado

Ya no existe:

GET /proformas/:proforma_id/report

También se eliminó el soporte ambiguo:

format=pdf|html|json

Legacy eliminado del árbol de aplicación:

modules/customer-invoices/src/api/application/proformas/use-cases/report-proforma2

Motivo:

- legacy no cableado
- no referenciado por rutas, DI, exports ni tests
- contaminaba el typecheck del módulo

No debe reintroducirse:

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:

/report/pdf

Pendiente:

- 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:

- 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:

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