7.5 KiB
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 (nuovo) |
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
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:
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:
Strategia isExpired — denylist: il check usa != "Quotazione" (denylist), così qualsiasi nuovo stato non previsto viene trattato come expired piuttosto che come attivo. Se in futuro si aggiungono stati con report differenti, si sostituirà con un allowlist esplicito.
bool isExpired = !string.IsNullOrEmpty(data.Info.Stato) && data.Info.Stato != "Quotazione";
// Copre: "Revocato", "Scaduto", "Rimborsato" — e qualsiasi stato futuro non-attivo
if (isExpired)
{
// Flusso expired: ExpiredAnagrafica + Eventi + Chart
var eventiRenderer = _sectionRenderers.First(r => r.SectionName == "Eventi");
pdfSections.Add(_expiredAnagraficaRenderer.Render(data));
pdfSections.Add(eventiRenderer.Render(data));
// Chart: await _chartRenderer.RenderAsync(data.Info.Isin) — aggiunto se non null
}
else
{
// Flusso attuale: foreach _sectionRenderers.OrderBy(r => r.Order) — logica esistente invariata
}
Come si ottiene EventiSectionRenderer nel flusso expired: tramite _sectionRenderers.First(r => r.SectionName == "Eventi"). È già registrato come IPdfSectionRenderer e presente nella collection iniettata.
Firma ChartRenderer: await _chartRenderer.RenderAsync(data.Info.Isin) — stessa chiamata del flusso attivo, restituisce PdfDocument? (null se il grafico non è disponibile).
Il renderer ExpiredAnagraficaSectionRenderer è iniettato direttamente nell'orchestratore (non via IEnumerable<IPdfSectionRenderer>) per evitare che venga incluso nel ciclo del flusso normale.
Cache — chiavi separate
Le chiavi sono passate a _cache.Get/Set a livello orchestratore; PdfCacheService.CacheKey() aggiunge poi il prefisso report_pdf_ internamente (comportamento invariato per entrambi i flussi).
| Scenario | Chiave passata all'orchestratore | Chiave effettiva in memoria |
|---|---|---|
| Attivo, no branding | {isin} |
report_pdf_{isin} |
| Attivo, branding | {isin}:branded |
report_pdf_{isin}:branded |
| Expired, no branding | {isin}:expired |
report_pdf_{isin}:expired |
| Expired, branding | {isin}:expired:branded |
report_pdf_{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:brandedvs{isin}:expired
Dependency Injection — Program.cs
// 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— invariatoEventiSectionRenderer.cs— riusato as-isScenarioSectionRenderer.cs— invariato (semplicemente non incluso nel flusso expired)ChartSectionRenderer.cs— riusato as-isPdfTheme.cs— invariatoReportController.cs— invariato- Tutti gli endpoint — invariati