docs: add expired certificate report design spec
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
# Design Spec: Report Certificati Non in Quotazione (Expired)
|
||||
|
||||
**Data:** 2026-03-21
|
||||
**Progetto:** SmartReports / CertReports.Syncfusion
|
||||
**Autore:** Brainstorming session
|
||||
|
||||
---
|
||||
|
||||
## Obiettivo
|
||||
|
||||
Implementare un secondo template di report PDF per certificati non più in quotazione (Stato: Revocato, Scaduto, Rimborsato). Il report mantiene lo stesso stile grafico del report attivo ma mostra meno informazioni: 3 pagine totali (Anagrafica semplificata + Lista Eventi + Grafico). Niente Scenario. Il rilevamento del tipo è automatico tramite il campo `Stato` restituito dalla SP esistente `rpt_Master_CFT_ISIN`.
|
||||
|
||||
---
|
||||
|
||||
## Struttura del Report Expired (3 pagine)
|
||||
|
||||
| Pagina | Renderer | Contenuto |
|
||||
|--------|----------|-----------|
|
||||
| 1 | `ExpiredAnagraficaSectionRenderer` | Titolo + Caratteristiche + Analisi |
|
||||
| 2 | `EventiSectionRenderer` (riusato) | Lista eventi (identica all'attuale) |
|
||||
| 3 | `ChartSectionRenderer` (riusato) | Grafico performance (identico all'attuale) |
|
||||
|
||||
---
|
||||
|
||||
## Modifiche al Modello
|
||||
|
||||
### `CertificateInfo` — aggiungere un campo
|
||||
|
||||
```csharp
|
||||
public string Stato { get; set; } = string.Empty;
|
||||
// Valori possibili: "Quotazione" | "Revocato" | "Scaduto" | "Rimborsato"
|
||||
```
|
||||
|
||||
### `CertificateDataService` — mappare il nuovo campo
|
||||
|
||||
Nel metodo che chiama `rpt_Master_CFT_ISIN`, aggiungere la mappatura:
|
||||
```csharp
|
||||
Stato = reader["Stato"]?.ToString() ?? string.Empty
|
||||
```
|
||||
|
||||
Nessuna altra modifica alle query o agli altri servizi dati.
|
||||
|
||||
---
|
||||
|
||||
## Nuovo Renderer: `ExpiredAnagraficaSectionRenderer`
|
||||
|
||||
**File:** `CertReports.Syncfusion/Services/Implementations/ExpiredAnagraficaSectionRenderer.cs`
|
||||
**Interfaccia:** `IPdfSectionRenderer`
|
||||
**Order:** 1
|
||||
**SectionName:** `"ExpiredAnagrafica"`
|
||||
|
||||
### Layout Pagina 1 (Portrait A4)
|
||||
|
||||
#### Blocco Titolo
|
||||
- "Scheda Prodotto {ISIN}" — stesso stile del titolo attuale (font grande, colore AccentBlue)
|
||||
- Riga sotto: "Tipologia: {Categoria}" — font normale
|
||||
- **Niente** Bid/Ask, niente LastPriceDate
|
||||
- Linea separatrice orizzontale blu (come attuale)
|
||||
|
||||
#### Blocco Caratteristiche Prodotto (tabella sinistra, stessa grafica attuale)
|
||||
|
||||
| Label | Campo modello |
|
||||
|-------|---------------|
|
||||
| EMITTENTE | `Info.Emittente` |
|
||||
| ISIN | `Info.Isin` |
|
||||
| Mercato | `Info.Mercato` |
|
||||
| Valuta | `Info.Valuta` |
|
||||
| Data Emissione | `Info.DataEmissione` |
|
||||
| Valore Rimborso | `Info.ValoreRimborso` |
|
||||
| Data Rimborso | `Info.DataRimborso` |
|
||||
|
||||
#### Blocco Analisi (KV, stessa grafica attuale)
|
||||
|
||||
| Label | Campo modello |
|
||||
|-------|---------------|
|
||||
| Importo Cedola (p.a.) | `Info.NominalAnnualYield` |
|
||||
| Frequenza Cedola | `Info.FrequenzaCedole` |
|
||||
| Valore Nominale | `Info.NominalValue` |
|
||||
| Memoria Cedola | `Info.Memory` |
|
||||
| Tipo Barriera | `Info.BarrierType` |
|
||||
| Tipo Basket | `Info.BasketType` |
|
||||
| Rendimento Totale | `Info.RendimentoTotale` |
|
||||
|
||||
#### Escluso dalla pagina 1
|
||||
- Sezione Bid/Ask/LastPriceDate
|
||||
- Tabella Sottostanti (sezione C del report attivo)
|
||||
- Sezione cedole (CpnPagati/DaPagare/InMemoria)
|
||||
- Sezione Analisi (8+9 KV del report attivo)
|
||||
|
||||
### Footer
|
||||
`PdfTheme.DrawFooter(g, pageWidth, pageHeight, pageNumber, showBranding)` — identico a tutti gli altri renderer, supporta il parametro branding.
|
||||
|
||||
---
|
||||
|
||||
## Modifiche all'Orchestratore
|
||||
|
||||
### `ReportOrchestrator.cs`
|
||||
|
||||
Dopo il caricamento dei dati (`CertificateDataService`), leggere `data.Info.Stato` per scegliere il flusso:
|
||||
|
||||
```csharp
|
||||
bool isExpired = data.Info.Stato != "Quotazione" && !string.IsNullOrEmpty(data.Info.Stato);
|
||||
|
||||
List<PdfDocument> sections;
|
||||
if (isExpired)
|
||||
{
|
||||
// Flusso expired: ExpiredAnagrafica + Eventi + Chart
|
||||
sections = new List<PdfDocument>
|
||||
{
|
||||
_expiredAnagraficaRenderer.Render(data),
|
||||
eventiRenderer.Render(data),
|
||||
// chart (async, può essere null)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flusso attuale: Anagrafica + Eventi + Scenario (condizionale) + Chart
|
||||
// logica esistente invariata
|
||||
}
|
||||
```
|
||||
|
||||
Il renderer `ExpiredAnagraficaSectionRenderer` è iniettato direttamente nell'orchestratore (non via `IEnumerable<IPdfSectionRenderer>`) per evitare che venga incluso nel ciclo del flusso normale.
|
||||
|
||||
### Cache — chiavi separate
|
||||
|
||||
| Scenario | Chiave cache |
|
||||
|----------|-------------|
|
||||
| Attivo, no branding | `{isin}` |
|
||||
| Attivo, branding | `{isin}:branded` |
|
||||
| Expired, no branding | `{isin}:expired` |
|
||||
| Expired, branding | `{isin}:expired:branded` |
|
||||
|
||||
---
|
||||
|
||||
## Branding
|
||||
|
||||
Il parametro `?branding=true` funziona identicamente al report attivo:
|
||||
- Propagato come `CertificateReportData.ShowBranding`
|
||||
- Passato a `PdfTheme.DrawFooter(..., showBranding)` in ogni pagina del report expired
|
||||
- Footer sinistra: "Powered by " + hyperlink "Smart Roots" → `https://www.smart-roots.net`
|
||||
- Footer destra: numero pagina
|
||||
- Cache usa chiave `{isin}:expired:branded` vs `{isin}:expired`
|
||||
|
||||
---
|
||||
|
||||
## Dependency Injection — `Program.cs`
|
||||
|
||||
```csharp
|
||||
// Registrazione diretta (non come IPdfSectionRenderer) per evitare inclusione nel ciclo normale
|
||||
builder.Services.AddScoped<ExpiredAnagraficaSectionRenderer>();
|
||||
```
|
||||
|
||||
Gli altri renderer esistenti rimangono invariati.
|
||||
|
||||
---
|
||||
|
||||
## Endpoint
|
||||
|
||||
**Nessun nuovo endpoint.** Il rilevamento del tipo report è trasparente al chiamante. Tutti gli endpoint esistenti funzionano per entrambi i tipi:
|
||||
|
||||
| Endpoint | Comportamento |
|
||||
|----------|---------------|
|
||||
| `GET /api/report?p={encrypted}` | Auto-rileva da Stato |
|
||||
| `GET /api/report?alias={id}` | Auto-rileva da Stato |
|
||||
| `GET /api/report/by-isin/{isin}` | Auto-rileva da Stato |
|
||||
| `GET /api/report/download?p={...}` | Auto-rileva da Stato |
|
||||
| `GET /api/report/download?alias={...}` | Auto-rileva da Stato |
|
||||
| Tutti | Supportano `?branding=true` |
|
||||
|
||||
---
|
||||
|
||||
## File Modificati / Creati
|
||||
|
||||
| File | Tipo modifica |
|
||||
|------|---------------|
|
||||
| `Models/CertificateModels.cs` | Aggiunta campo `Stato` a `CertificateInfo` |
|
||||
| `Services/Implementations/CertificateDataService.cs` | Mappatura campo `Stato` dalla SP |
|
||||
| `Services/Implementations/ExpiredAnagraficaSectionRenderer.cs` | **Nuovo file** |
|
||||
| `Services/Implementations/ReportOrchestrator.cs` | Logica branching expired/attivo + cache keys |
|
||||
| `Program.cs` | Registrazione `ExpiredAnagraficaSectionRenderer` |
|
||||
|
||||
---
|
||||
|
||||
## Non modificati
|
||||
|
||||
- `AnagraficaSectionRenderer.cs` — invariato
|
||||
- `EventiSectionRenderer.cs` — riusato as-is
|
||||
- `ScenarioSectionRenderer.cs` — invariato (semplicemente non incluso nel flusso expired)
|
||||
- `ChartSectionRenderer.cs` — riusato as-is
|
||||
- `PdfTheme.cs` — invariato
|
||||
- `ReportController.cs` — invariato
|
||||
- Tutti gli endpoint — invariati
|
||||
Reference in New Issue
Block a user