From 71d6a4c32ddece17f603d03ca6e7df978e60321e Mon Sep 17 00:00:00 2001 From: SmartRootsSrl Date: Sat, 21 Mar 2026 10:17:53 +0100 Subject: [PATCH] docs: add expired certificate report design spec --- ...03-21-expired-certificate-report-design.md | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-21-expired-certificate-report-design.md diff --git a/docs/superpowers/specs/2026-03-21-expired-certificate-report-design.md b/docs/superpowers/specs/2026-03-21-expired-certificate-report-design.md new file mode 100644 index 0000000..c4fc315 --- /dev/null +++ b/docs/superpowers/specs/2026-03-21-expired-certificate-report-design.md @@ -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 sections; +if (isExpired) +{ + // Flusso expired: ExpiredAnagrafica + Eventi + Chart + sections = new List + { + _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`) 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(); +``` + +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