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