187 lines
9.1 KiB
Markdown
187 lines
9.1 KiB
Markdown
# Módulo de Reportes
|
|||
|
|
|
||
|
|
El frontend expone **tres sistemas de reportes distintos**, con configuración, rutas y componentes propios cada uno. No son variantes del mismo flujo: apuntan a integraciones distintas del lado del backend, y uno de ellos (`informes`) no tiene backend real detrás todavía.
|
||
|
|
|
||
|
|
| Sistema | Ruta base | Config | Componente runner | Backend real |
|
||
|
|
|---|---|---|---|---|
|
||
|
|
| **Reportes HTML** | `/reportes-html/:module` | `config/htmlReports.ts` → `htmlReportsConfig` | `HtmlReportRunner.tsx` | `mini-backend/routers/reports.py` (Jinja2 + WeasyPrint, datos de HANA) — **sí implementado** |
|
||
|
|
| **Reportes Crystal** | `/reportes-crystal/:module` | `config/crystalReports.ts` → `crystalReportsConfig` | `CrystalReportRunner.tsx` | `mini-backend/routers/apigateway.py` (SAP B1 API Gateway / Crystal Reports Server) — **sí implementado** |
|
||
|
|
| **Informes** | `/informes/:module` | `config/reports.ts` → `reportsConfig` | `ReportRunner.tsx` | Ninguno confirmado — ver nota abajo |
|
||
|
|
|
||
|
|
### Nota sobre `informes` (`ReportRunner.tsx` + `reportsConfig`)
|
||
|
|
|
||
|
|
`reportsConfig` (en `config/reports.ts`) define reportes como "Estado de Cuenta", "Saldos de Clientes", "Ventas por Artículo", "Kardex de Artículos", etc., cada uno con un `endpoint` del tipo `/api/reports/socios/estado-cuenta`, `/api/reports/inventario/kardex`, etc. El único endpoint que `mini-backend/routers/reports.py` expone bajo `/api/reports/` es `POST /api/reports/stickers`. Ninguno de los endpoints que `reportsConfig` referencia existe en el backend actual. Esto sugiere que `ReportRunner.tsx` y `reportsConfig` son un scaffold frontend para reportes planeados a futuro, no un flujo funcional hoy — cualquier reporte del módulo "Informes" fallará al generar hasta que se implemente su endpoint correspondiente en el backend.
|
||
|
|
|
||
|
|
## Arquitectura General
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
graph TB
|
||
|
|
subgraph "Listados (elegir reporte)"
|
||
|
|
RHL[HtmlReportsList.tsx]
|
||
|
|
RCL[CrystalReportsList.tsx]
|
||
|
|
MRL[ModuleReportsList.tsx]
|
||
|
|
end
|
||
|
|
|
||
|
|
subgraph "Runners (parámetros + ejecución)"
|
||
|
|
HRR[HtmlReportRunner.tsx]
|
||
|
|
CRR[CrystalReportRunner.tsx]
|
||
|
|
RR[ReportRunner.tsx]
|
||
|
|
RPF[ReportParameterForm.tsx]
|
||
|
|
RRV[ReportResultsView.tsx]
|
||
|
|
MST[ModalSearchTemplate.tsx<br/>búsqueda F4]
|
||
|
|
end
|
||
|
|
|
||
|
|
subgraph "Config"
|
||
|
|
CFG_H[htmlReportsConfig]
|
||
|
|
CFG_C[crystalReportsConfig]
|
||
|
|
CFG_R[reportsConfig]
|
||
|
|
end
|
||
|
|
|
||
|
|
subgraph "Backend FastAPI (mini-backend)"
|
||
|
|
REP[routers/reports.py<br/>POST /api/reports/stickers]
|
||
|
|
APIGW[routers/apigateway.py<br/>GET/POST /api/apigateway/reports/*]
|
||
|
|
HANA[core/hana.py<br/>hana_connection]
|
||
|
|
AGW_CORE[core/api_gateway.py<br/>forward_to_api_gateway]
|
||
|
|
end
|
||
|
|
|
||
|
|
subgraph "Externo"
|
||
|
|
HANADB[(HANA DB)]
|
||
|
|
SAPGW[SAP B1 API Gateway<br/>rs/v1 Crystal Reports Server]
|
||
|
|
end
|
||
|
|
|
||
|
|
RHL --> CFG_H --> HRR
|
||
|
|
RCL --> CFG_C --> CRR
|
||
|
|
MRL --> CFG_R --> RR
|
||
|
|
|
||
|
|
HRR --> RPF
|
||
|
|
CRR --> RPF
|
||
|
|
RR --> RPF
|
||
|
|
RR --> RRV
|
||
|
|
HRR -.f4-modal.-> MST
|
||
|
|
CRR -.f4-modal.-> MST
|
||
|
|
|
||
|
|
HRR -->|POST /api/reports/:endpoint| REP
|
||
|
|
REP --> HANA --> HANADB
|
||
|
|
|
||
|
|
CRR -->|POST /api/apigateway/reports/:docCode/export| APIGW
|
||
|
|
RCL -.al listar.-> APIGW
|
||
|
|
APIGW --> AGW_CORE --> SAPGW
|
||
|
|
|
||
|
|
RR -.->|"endpoint del reportsConfig<br/>(no existe en el backend)"| REP
|
||
|
|
```
|
||
|
|
|
||
|
|
## Flujo real: Reporte HTML (ejemplo "stickers")
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
actor User as Usuario
|
||
|
|
participant List as HtmlReportsList
|
||
|
|
participant Runner as HtmlReportRunner
|
||
|
|
participant Modal as ModalSearchTemplate
|
||
|
|
participant API as api.ts
|
||
|
|
participant Backend as reports.py
|
||
|
|
participant HANA as HANA
|
||
|
|
|
||
|
|
User->>List: /reportes-html/inventario
|
||
|
|
List->>List: lee htmlReportsConfig["inventario"]
|
||
|
|
List-->>User: tarjeta "Impresión de Etiquetas"
|
||
|
|
|
||
|
|
User->>Runner: clic → /reportes-html/inventario/stickers
|
||
|
|
Runner->>Runner: busca definition por docCode "stickers"
|
||
|
|
Runner-->>User: formulario (Documento f4-modal, Cantidad, Formato, Papel)
|
||
|
|
|
||
|
|
User->>Runner: clic en campo "Documento"
|
||
|
|
Runner->>Modal: abre ModalSearchTemplate (endpoint DeliveryNotes)
|
||
|
|
Modal-->>User: tabla de guías de remisión
|
||
|
|
User->>Modal: selecciona guía
|
||
|
|
Modal-->>Runner: DocEntry seleccionado
|
||
|
|
|
||
|
|
User->>Runner: completa cantidad/formato y clic "Generar Reporte"
|
||
|
|
Runner->>API: POST /api/reports/stickers {doc_entry, cantidad, formato, papel}
|
||
|
|
API->>Backend: fetch con X-Session-Token
|
||
|
|
Backend->>HANA: STICKERS_QUERY (datos de la guía por DocEntry)
|
||
|
|
HANA-->>Backend: fila con cliente, dirección, etc.
|
||
|
|
Backend->>Backend: renderiza templates/reports/stickers.html (Jinja2)
|
||
|
|
alt formato = pdf
|
||
|
|
Backend->>Backend: WeasyPrint HTML → PDF
|
||
|
|
Backend-->>API: StreamingResponse application/pdf
|
||
|
|
else formato = html
|
||
|
|
Backend-->>API: HTMLResponse
|
||
|
|
end
|
||
|
|
API-->>Runner: blob
|
||
|
|
Runner-->>User: <iframe> con vista previa
|
||
|
|
```
|
||
|
|
|
||
|
|
## Flujo real: Reporte Crystal (ejemplo "DLN20015")
|
||
|
|
|
||
|
|
```mermaid
|
||
|
|
sequenceDiagram
|
||
|
|
actor User as Usuario
|
||
|
|
participant List as CrystalReportsList
|
||
|
|
participant Runner as CrystalReportRunner
|
||
|
|
participant API as api.ts
|
||
|
|
participant Backend as apigateway.py
|
||
|
|
participant Core as core/api_gateway.py
|
||
|
|
participant SAPGW as SAP API Gateway
|
||
|
|
|
||
|
|
User->>List: /reportes-crystal/inventario
|
||
|
|
List->>List: lee crystalReportsConfig["inventario"]
|
||
|
|
List-->>User: tarjeta "Impresión de Etiquetas" (docCode DLN20015)
|
||
|
|
|
||
|
|
User->>Runner: clic → /reportes-crystal/inventario/DLN20015
|
||
|
|
Runner-->>User: formulario (Documento f4-modal, Cantidad)
|
||
|
|
|
||
|
|
User->>Runner: completa parámetros y clic "Exportar PDF"
|
||
|
|
Runner->>API: POST /api/apigateway/reports/DLN20015/export<br/>[{name, type, value}]
|
||
|
|
API->>Backend: fetch con X-Session-Token
|
||
|
|
Backend->>Core: forward_to_api_gateway(POST rs/v1/ExportPDFData?DocCode=DLN20015)
|
||
|
|
Core->>SAPGW: request con credenciales APIGATEWAY_* del .env
|
||
|
|
SAPGW-->>Core: PDF en base64
|
||
|
|
Core-->>Backend: response
|
||
|
|
Backend->>Backend: decodifica base64 → bytes
|
||
|
|
Backend-->>API: StreamingResponse application/pdf
|
||
|
|
API-->>Runner: blob
|
||
|
|
Runner-->>User: <iframe> con vista previa PDF
|
||
|
|
```
|
||
|
|
|
||
|
|
Nota: `crystalReportsConfig` solo tiene un reporte cargado, en `inventario` (`DLN20015`, "Impresión de Etiquetas"). Los otros módulos (`socios`, `ventas`, `compras`) están declarados con arrays vacíos — no hay reportes Crystal configurados para ellos todavía. Curiosamente, el comentario en `mini-backend/routers/reports.py` indica que la consulta SQL de `stickers` (el reporte HTML) es "la query original de Crystal Reports para DLN20015, adaptada" — es decir, el mismo reporte de negocio (etiquetas de guía de remisión) existe hoy por **dos caminos en paralelo**: el Crystal Report original vía API Gateway, y su reimplementación propia vía HANA + Jinja + WeasyPrint.
|
||
|
|
|
||
|
|
## Árbol de Componentes y Rutas
|
||
|
|
|
||
|
|
```
|
||
|
|
App.tsx (BrowserRouter)
|
||
|
|
└── / (ProtectedRoute → MainLayout)
|
||
|
|
├── /informes/:module → ModuleReportsList.tsx
|
||
|
|
│ └── /informes/:module/:reportId → ReportRunner.tsx
|
||
|
|
│ ├── ReportParameterForm.tsx
|
||
|
|
│ └── ReportResultsView.tsx
|
||
|
|
├── /reportes-crystal/:module → CrystalReportsList.tsx
|
||
|
|
│ └── /reportes-crystal/:module/:docCode → CrystalReportRunner.tsx
|
||
|
|
│ └── ModalSearchTemplate.tsx (f4-modal)
|
||
|
|
└── /reportes-html/:module → HtmlReportsList.tsx
|
||
|
|
└── /reportes-html/:module/:docCode → HtmlReportRunner.tsx
|
||
|
|
└── ModalSearchTemplate.tsx (f4-modal)
|
||
|
|
```
|
||
|
|
|
||
|
|
`:module` es uno de `socios | ventas | compras | inventario` (`moduleLabels`/`moduleIcons` en `config/reports.ts`), compartido por los tres sistemas.
|
||
|
|
|
||
|
|
## Archivos Clave
|
||
|
|
|
||
|
|
| Archivo | Ruta | Propósito |
|
||
|
|
|---|---|---|
|
||
|
|
| `ModuleReportsList.tsx` | `src/views/informes/` | Lista reportes de `reportsConfig` por módulo |
|
||
|
|
| `ReportRunner.tsx` | `src/components/report/` | Ejecuta reportes de `reportsConfig` (endpoints aún no implementados en backend) |
|
||
|
|
| `ReportParameterForm.tsx` | `src/components/report/` | Formulario de parámetros para `ReportRunner` |
|
||
|
|
| `ReportResultsView.tsx` | `src/components/report/` | Renderiza tabla/totales/PDF según `outputType` |
|
||
|
|
| `CrystalReportsList.tsx` | `src/views/reportes/` | Lista reportes de `crystalReportsConfig` por módulo |
|
||
|
|
| `CrystalReportRunner.tsx` | `src/components/report/` | Arma el body y llama a `/api/apigateway/reports/:docCode/export` |
|
||
|
|
| `HtmlReportsList.tsx` | `src/views/reportes/` | Lista reportes de `htmlReportsConfig` por módulo |
|
||
|
|
| `HtmlReportRunner.tsx` | `src/components/report/` | Arma el body y llama a `/api/reports/:endpoint` |
|
||
|
|
| `ModalSearchTemplate.tsx` | `src/components/ui/` | Modal de búsqueda F4 reutilizado por ambos runners reales |
|
||
|
|
| `config/reports.ts` | `src/config/` | `reportsConfig`, `moduleLabels`, `moduleIcons` |
|
||
|
|
| `config/crystalReports.ts` | `src/config/` | `crystalReportsConfig` |
|
||
|
|
| `config/htmlReports.ts` | `src/config/` | `htmlReportsConfig` |
|
||
|
|
| `types/reports.ts` | `src/types/` | Tipos `ReportDefinition`, `F4Config`, etc. |
|
||
|
|
| `reports.py` | `mini-backend/routers/` | `POST /api/reports/stickers` (Jinja2 + WeasyPrint, datos vía `core/hana.py`) |
|
||
|
|
| `apigateway.py` | `mini-backend/routers/` | `GET /api/apigateway/reports`, `GET .../{docCode}/parameters`, `POST .../{docCode}/export` |
|
||
|
|
| `api_gateway.py` | `mini-backend/core/` | `forward_to_api_gateway`, proxy hacia el SAP API Gateway |
|