docs: update expired report spec after review (cache keys, orchestrator logic, chart signature)

This commit is contained in:
2026-03-21 10:21:20 +01:00
parent 71d6a4c32d
commit cdbdfeede1

View File

@@ -16,7 +16,7 @@ Implementare un secondo template di report PDF per certificati non più in quota
| Pagina | Renderer | Contenuto | | Pagina | Renderer | Contenuto |
|--------|----------|-----------| |--------|----------|-----------|
| 1 | `ExpiredAnagraficaSectionRenderer` | Titolo + Caratteristiche + Analisi | | 1 | `ExpiredAnagraficaSectionRenderer` (nuovo) | Titolo + Caratteristiche + Analisi |
| 2 | `EventiSectionRenderer` (riusato) | Lista eventi (identica all'attuale) | | 2 | `EventiSectionRenderer` (riusato) | Lista eventi (identica all'attuale) |
| 3 | `ChartSectionRenderer` (riusato) | Grafico performance (identico all'attuale) | | 3 | `ChartSectionRenderer` (riusato) | Grafico performance (identico all'attuale) |
@@ -98,37 +98,42 @@ Nessuna altra modifica alle query o agli altri servizi dati.
Dopo il caricamento dei dati (`CertificateDataService`), leggere `data.Info.Stato` per scegliere il flusso: Dopo il caricamento dei dati (`CertificateDataService`), leggere `data.Info.Stato` per scegliere il flusso:
```csharp **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 = data.Info.Stato != "Quotazione" && !string.IsNullOrEmpty(data.Info.Stato);
```csharp
bool isExpired = !string.IsNullOrEmpty(data.Info.Stato) && data.Info.Stato != "Quotazione";
// Copre: "Revocato", "Scaduto", "Rimborsato" — e qualsiasi stato futuro non-attivo
List<PdfDocument> sections;
if (isExpired) if (isExpired)
{ {
// Flusso expired: ExpiredAnagrafica + Eventi + Chart // Flusso expired: ExpiredAnagrafica + Eventi + Chart
sections = new List<PdfDocument> var eventiRenderer = _sectionRenderers.First(r => r.SectionName == "Eventi");
{ pdfSections.Add(_expiredAnagraficaRenderer.Render(data));
_expiredAnagraficaRenderer.Render(data), pdfSections.Add(eventiRenderer.Render(data));
eventiRenderer.Render(data), // Chart: await _chartRenderer.RenderAsync(data.Info.Isin) — aggiunto se non null
// chart (async, può essere null)
};
} }
else else
{ {
// Flusso attuale: Anagrafica + Eventi + Scenario (condizionale) + Chart // Flusso attuale: foreach _sectionRenderers.OrderBy(r => r.Order) — logica esistente invariata
// 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. Il renderer `ExpiredAnagraficaSectionRenderer` è iniettato direttamente nell'orchestratore (non via `IEnumerable<IPdfSectionRenderer>`) per evitare che venga incluso nel ciclo del flusso normale.
### Cache — chiavi separate ### Cache — chiavi separate
| Scenario | Chiave cache | 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).
|----------|-------------|
| Attivo, no branding | `{isin}` | | Scenario | Chiave passata all'orchestratore | Chiave effettiva in memoria |
| Attivo, branding | `{isin}:branded` | |----------|----------------------------------|-----------------------------|
| Expired, no branding | `{isin}:expired` | | Attivo, no branding | `{isin}` | `report_pdf_{isin}` |
| Expired, branding | `{isin}:expired:branded` | | 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` |
--- ---