feat: add expired certificate report branching in orchestrator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-21 10:38:41 +01:00
parent 571df139e5
commit b60956db9a

View File

@@ -21,6 +21,7 @@ public class ReportOrchestrator : IReportOrchestrator
private readonly IPdfMergerService _merger; private readonly IPdfMergerService _merger;
private readonly IPdfCacheService _cache; private readonly IPdfCacheService _cache;
private readonly ILogger<ReportOrchestrator> _logger; private readonly ILogger<ReportOrchestrator> _logger;
private readonly ExpiredAnagraficaSectionRenderer _expiredAnagraficaRenderer;
public ReportOrchestrator( public ReportOrchestrator(
ICertificateDataService dataService, ICertificateDataService dataService,
@@ -28,7 +29,8 @@ public class ReportOrchestrator : IReportOrchestrator
IChartSectionRenderer chartRenderer, IChartSectionRenderer chartRenderer,
IPdfMergerService merger, IPdfMergerService merger,
IPdfCacheService cache, IPdfCacheService cache,
ILogger<ReportOrchestrator> logger) ILogger<ReportOrchestrator> logger,
ExpiredAnagraficaSectionRenderer expiredAnagraficaRenderer)
{ {
_dataService = dataService; _dataService = dataService;
_sectionRenderers = sectionRenderers; _sectionRenderers = sectionRenderers;
@@ -36,13 +38,16 @@ public class ReportOrchestrator : IReportOrchestrator
_merger = merger; _merger = merger;
_cache = cache; _cache = cache;
_logger = logger; _logger = logger;
_expiredAnagraficaRenderer = expiredAnagraficaRenderer;
} }
public async Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false) public async Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false)
{ {
// ── Cache check (chiave include branding) ───────────────────────── // ── Cache check ────────────────────────────────────────────────
var cacheKey = showBranding ? $"{isin}:branded" : isin; var baseCacheKey = showBranding ? $"{isin}:branded" : isin;
var cached = _cache.Get(cacheKey); var expiredCacheKey = showBranding ? $"{isin}:expired:branded" : $"{isin}:expired";
var cached = _cache.Get(baseCacheKey) ?? _cache.Get(expiredCacheKey);
if (cached != null) if (cached != null)
{ {
_logger.LogInformation("Report per ISIN {Isin} servito da cache ({Size} bytes)", isin, cached.Length); _logger.LogInformation("Report per ISIN {Isin} servito da cache ({Size} bytes)", isin, cached.Length);
@@ -60,40 +65,56 @@ public class ReportOrchestrator : IReportOrchestrator
ShowBranding = showBranding, ShowBranding = showBranding,
}; };
// Determina se lo scenario ha dati validi (evita doppia chiamata SP) // ── 2. Determina il tipo di report ────────────────────────────
bool isScenarioAllowed = reportData.Scenario.Rows.Count > 0; bool isExpired = !string.IsNullOrEmpty(reportData.Info.Stato)
&& reportData.Info.Stato != "Quotazione";
var cacheKey = isExpired ? expiredCacheKey : baseCacheKey;
_logger.LogInformation( _logger.LogInformation(
"Dati recuperati per {Isin}: {SottostantiCount} sottostanti, {EventiCount} eventi, Scenario: {ScenarioAllowed}", "Dati recuperati per {Isin}: Stato={Stato}, isExpired={IsExpired}, {EventiCount} eventi",
isin, reportData.Info.Sottostanti.Count, reportData.Eventi.Count, isScenarioAllowed); isin, reportData.Info.Stato, isExpired, reportData.Eventi.Count);
// ── 2. Genera le sezioni PDF ────────────────────────────────── // ── 3. Genera le sezioni PDF ──────────────────────────────────
var pdfSections = new List<PdfDocument>(); var pdfSections = new List<PdfDocument>();
foreach (var renderer in _sectionRenderers.OrderBy(r => r.Order)) if (isExpired)
{ {
// Salta la sezione scenario se il certificato è Protection // Flusso expired: ExpiredAnagrafica + Eventi + Chart
if (renderer.SectionName == "Scenario" && !isScenarioAllowed) pdfSections.Add(_expiredAnagraficaRenderer.Render(reportData));
{ _logger.LogInformation("Sezione 'ExpiredAnagrafica' generata per {Isin}", isin);
_logger.LogInformation("Sezione Scenario saltata per {Isin} (certificato Protection)", isin);
continue;
}
try var eventiRenderer = _sectionRenderers.First(r => r.SectionName == "Eventi");
pdfSections.Add(eventiRenderer.Render(reportData));
_logger.LogInformation("Sezione 'Eventi' generata per {Isin}", isin);
}
else
{
// Flusso attuale: Anagrafica + Eventi + Scenario (condizionale)
bool isScenarioAllowed = reportData.Scenario.Rows.Count > 0;
foreach (var renderer in _sectionRenderers.OrderBy(r => r.Order))
{ {
var sectionPdf = renderer.Render(reportData); if (renderer.SectionName == "Scenario" && !isScenarioAllowed)
pdfSections.Add(sectionPdf); {
_logger.LogInformation("Sezione '{Section}' generata per {Isin}", renderer.SectionName, isin); _logger.LogInformation("Sezione Scenario saltata per {Isin}", isin);
} continue;
catch (Exception ex) }
{
_logger.LogError(ex, "Errore nella generazione della sezione '{Section}' per {Isin}", try
renderer.SectionName, isin); {
throw; pdfSections.Add(renderer.Render(reportData));
_logger.LogInformation("Sezione '{Section}' generata per {Isin}", renderer.SectionName, isin);
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore nella sezione '{Section}' per {Isin}", renderer.SectionName, isin);
throw;
}
} }
} }
// ── 3. Genera/recupera il grafico ────────────────────────────── // ── 4. Grafico (entrambi i flussi) ────────────────────────────
var chartPdf = await _chartRenderer.RenderAsync(isin); var chartPdf = await _chartRenderer.RenderAsync(isin);
if (chartPdf != null) if (chartPdf != null)
{ {
@@ -101,20 +122,16 @@ public class ReportOrchestrator : IReportOrchestrator
_logger.LogInformation("Sezione Grafico aggiunta per {Isin}", isin); _logger.LogInformation("Sezione Grafico aggiunta per {Isin}", isin);
} }
// ── 4. Unisci tutto ──────────────────────────────────────────── // ── 5. Unisci tutto ────────────────────────────────────────────
var finalPdf = _merger.Merge(pdfSections); var finalPdf = _merger.Merge(pdfSections);
_logger.LogInformation("Report generato per {Isin}: {Size} bytes, {Sections} sezioni", _logger.LogInformation("Report generato per {Isin}: {Size} bytes, {Sections} sezioni",
isin, finalPdf.Length, pdfSections.Count); isin, finalPdf.Length, pdfSections.Count);
// Salva in cache
_cache.Set(cacheKey, finalPdf); _cache.Set(cacheKey, finalPdf);
// Cleanup
foreach (var doc in pdfSections) foreach (var doc in pdfSections)
{
doc.Close(true); doc.Close(true);
}
return finalPdf; return finalPdf;
} }