SmartRootsSrl 9b938ef93d fix: fund report layout refactor and chart renderer fix
- FundAnagraficaRenderer: unified header style (DrawColHeader), DrawPerfGrid returns float, chart embedded in anagrafica section
- FundReportController: simplify filename to {isin}.pdf
- SkiaChartRendererV2: minor fix affecting certificate chart

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-06-09 15:56:21 +02:00
2026-03-20 17:40:06 +01:00

SmartReports

Generatore di report PDF per certificati finanziari strutturati, sviluppato in ASP.NET Core 8 con libreria Syncfusion PDF (Community License) e SkiaSharp per i grafici.

Caratteristiche principali

  • Generazione PDF multi-sezione da dati SQL Server
  • Due template report certificati: in quotazione (4 sezioni) e non in quotazione / scaduti / rimborsati / revocati (3 sezioni) — rilevamento automatico dal campo Stato
  • Report ETF/Fondi: 2 pagine — anagrafica con layout a 3 colonne (Dati Anagrafici, ESG Score, griglia Performance/Volatilità/RendRisk) + grafico storico prezzi
  • Pagina dividendi opzionale (?dividend=true): pagina landscape con tabella Sottostanti+Dividendi a header raggruppati
  • Grafico performance sottostanti (SkiaSharp → PNG in memoria)
  • Footer con branding opzionale e hyperlink cliccabile
  • Cache in memoria per ISIN già generati (chiavi separate per ogni combinazione di flag)
  • Endpoint per PDF inline, download, grafico standalone v1, grafico V2 multi-formato e grafico fondi
  • Supporto Docker

Stack tecnologico

Componente Tecnologia
Framework ASP.NET Core 8
PDF Syncfusion PDF v33 (Community License)
Grafici SkiaSharp
Database SQL Server (Microsoft.Data.SqlClient v5)
Runtime .NET 8

Struttura del report

Certificati in quotazione (Stato = "Quotazione") — 4 sezioni (+1 opzionale)

Sezione Contenuto
1 — Anagrafica Header con Tipologia / Data / Bid / Ask, caratteristiche prodotto, analisi KV (inclusi Direzione, RendimentoPotenziale, CategoryID), tabella sottostanti (omessa se ?dividend=true)
1b — Sottostanti e Dividendi (opzionale, ?dividend=true) Pagina landscape: tabella unificata con colonne SOTTOSTANTE / BARRIERE / DIVIDENDI a 2 livelli di header
2 — Eventi Lista eventi cedole e autocall (tabella landscape multi-pagina)
3 — Scenario Scenari di rendimento (opzionale, saltato se assente)
4 — Grafico Performance storica dei sottostanti

Certificati non in quotazione (Stato = "Scaduto" / "Rimborsato" / "Revocato") — 3 sezioni (+1 opzionale)

Sezione Contenuto
1 — Anagrafica (semplificata) Header con solo Tipologia, caratteristiche con Valore/Data Rimborso, analisi KV, tabella sottostanti (omessa se ?dividend=true)
1b — Sottostanti e Dividendi (opzionale, ?dividend=true) Pagina landscape: tabella unificata con colonne SOTTOSTANTE / BARRIERE / DIVIDENDI a 2 livelli di header
2 — Eventi Lista eventi con colonne adattate (Barriera Cedola, Soglia Rimborso, Barriera Capitale, Rimborso Capitale)
3 — Grafico Performance storica dei sottostanti

Il tipo di report viene selezionato automaticamente dall'orchestratore in base al campo Stato restituito dalla SP rpt_Master_CFT_ISIN.

Report ETF/Fondi — 2 pagine

Pagina Contenuto
1 — Anagrafica Title bar con Tipo/Nome/ISIN; strip Rank+Prezzo+Data; 3 colonne: Dati Anagrafici (Società, Categoria MS, Valuta, Hedged, Benchmark, Spese, Catalogo, Proventi, Data lancio, Patrimonio) · ESG Score (Sustainability, Environmental, Social, Governance) · Griglia Performance/Volatilità/RendRisk (3M, 6M, YTD, 1Y, 3Y, 5Y)
2 — Grafico Storico prezzi close (linea singola, SkiaSharp), asse X con intervalli mensili adattivi

SP: sfih_GetOptDettagli (anagrafica) · sfih_GetChartPrices (prezzi storici).

API Endpoints

Certificati:

GET /api/report/by-isin/{ISIN}          → PDF inline
GET /api/report?p={isin_cifrato}        → PDF inline (ISIN cifrato)
GET /api/report?alias={id}             → PDF inline (alias)
GET /api/report/download?p={...}       → PDF come allegato

GET /api/chart/{isin}                  → Grafico standalone v1 (PNG/PDF)
GET /api/chart/v2/{isin}               → Grafico standalone v2 (multi-formato, vedi sotto)

ETF/Fondi:

GET /api/report/fund/by-isin/{ISIN}    → PDF inline
GET /api/report/fund?p={isin_cifrato}  → PDF inline (ISIN cifrato)
GET /api/report/fund?alias={id}        → PDF inline (alias)
GET /api/report/fund/download?p={...}  → PDF come allegato

GET /api/chart/fund/{isin}             → Grafico storico prezzi (PNG/JPEG/PDF)
GET /health                            → Health check DB + chart service

Parametri opzionali accettati da tutti gli endpoint report certificati:

Parametro Default Effetto
?branding=true false Aggiunge footer "Powered by Smart Roots" con hyperlink
?dividend=true false Inserisce pagina landscape Sottostanti+Dividendi dopo la Sezione 1; omette la tabella sottostanti dalla Sezione 1
?natixis=true false Box Tipologia mostra info.Nome invece di info.Categoria

I parametri sono combinabili, es. ?branding=true&dividend=true&natixis=true.

Parametri opzionali accettati dagli endpoint report ETF/Fondi:

Parametro Default Effetto
?branding=true false Aggiunge footer "Powered by Smart Roots" con hyperlink

Grafico Fondi — parametri

GET /api/chart/fund/{isin}[?format=png|jpg|jpeg|pdf&width=&height=&save=true]
Parametro Valori Effetto
?format= png (default), jpg/jpeg, pdf Formato output
?save=true Salva JPEG su disco (ChartSettings:SavePath/{isin}_fund.jpg) — solo per jpg/jpeg

Grafico V2 — parametri

GET /api/chart/v2/{isin}[?format=png|jpg|jpeg|jpgEnc|pdf&width=&height=&save=true]
Parametro Valori Effetto
?format= png (default), jpg/jpeg, jpgEnc, pdf Formato output; jpgEnc usa filename da alias SP; pdf genera PDF landscape
?save=true Salva il JPEG su disco (percorsi da ChartSettings:SavePath / SavePathEnc) — solo per jpg/jpeg/jpgEnc

Colori grafico V2: CTF = nero #000000, WorstOf = rosso #CC0000, altri sottostanti = palette vivace (teal/amber/viola/celeste…), Barriera Capitale = marrone #715548.

Avvio locale

# Restore e build
dotnet restore
dotnet build

# Run
dotnet run --project CertReports.Syncfusion
# → https://localhost:{porta}/api/report/by-isin/{ISIN}

Avvio con Docker

docker-compose up --build
# → http://localhost:5080/api/report/by-isin/{ISIN}

Configurazione

File Scopo
appsettings.json Connection string (CertDb), Syncfusion license key, CryptoSettings passphrase, cache TTL
appsettings.Development.json Override per sviluppo locale (non deve contenere ConnectionStrings)

Connection string SQL Server:

"ConnectionStrings": {
  "CertDb": "Data Source=tcp:IP;Initial Catalog=FirstSolutionDB;User Id=...;Password=...;Encrypt=False;"
}

Aggiungere una nuova sezione PDF

  1. Implementare IPdfSectionRenderer
  2. Impostare SectionName e Order
  3. Registrare in Program.cs:
    builder.Services.AddScoped<IPdfSectionRenderer, NuovaSezione>();
    

L'orchestratore la include automaticamente ordinandola per Order.

Tema grafico

Tutto il tema (colori, font, layout, brush/pen) è centralizzato in CertReports.Syncfusion/Helpers/PdfTheme.cs.

Colore Hex Utilizzo
AccentBlue #1565C0 Titoli, header tabelle, valori chiave
NegativeRed #CC0000 Valori negativi
PositiveGreen #2E7D32 Valori positivi

Architettura

HTTP (ISIN) → ReportController → ReportOrchestrator
    ├── CertificateDataService   (SP → anagrafica, sottostanti, eventi, scenario)
    │
    ├── [Stato == "Quotazione"] ──────────────────────────────────────────
    │   ├── AnagraficaSectionRenderer       → PdfDocument (Sezione 1, senza tabella sottostanti se dividend=true)
    │   ├── DividendSectionRenderer         → PdfDocument (Sezione 1b, solo se ?dividend=true, landscape)
    │   ├── EventiSectionRenderer           → PdfDocument (Sezione 2)
    │   ├── ScenarioSectionRenderer         → PdfDocument (Sezione 3, opzionale)
    │   └── ChartSectionRenderer            → PdfDocument (Sezione 4)
    │
    ├── [Stato != "Quotazione"] ─────────────────────────────────────────
    │   ├── ExpiredAnagraficaSectionRenderer → PdfDocument (Sezione 1, senza tabella sottostanti se dividend=true)
    │   ├── DividendSectionRenderer          → PdfDocument (Sezione 1b, solo se ?dividend=true, landscape)
    │   ├── EventiSectionRenderer            → PdfDocument (Sezione 2, colonne adattate)
    │   └── ChartSectionRenderer             → PdfDocument (Sezione 3)
    │
    ├── ChartDataService            (SP → dati grafico v1)
    ├── SkiaChartRenderer          → PNG in memoria (v1)
    └── PdfMergerService           → byte[] → Response

HTTP (ISIN) → ChartController → /api/chart/v2/{isin}
    ├── ChartDataServiceV2         (cedlab_Chart_UL1 + cedlab_Chart_AllSeriesV2)
    └── SkiaChartRendererV2        → PNG/JPEG/PDF → Response (+ salvataggio disco se ?save=true)

HTTP (ISIN) → FundReportController → /api/report/fund/
    ├── FundDataService            (sfih_GetOptDettagli + sfih_GetChartPrices)
    ├── FundReportOrchestrator
    │   ├── FundAnagraficaRenderer → PdfDocument (Pagina 1: layout C)
    │   ├── FundChartSectionRenderer → PdfDocument (Pagina 2: grafico landscape)
    │   │   └── FundSkiaChartRenderer [static] → PNG in memoria
    │   └── PdfMergerService       → byte[] → Response
    └── PdfCacheService            (chiave fund:{isin}[:branded])

HTTP (ISIN) → FundChartController → /api/chart/fund/{isin}
    ├── FundDataService            (sfih_GetOptDettagli + sfih_GetChartPrices, in parallelo)
    └── FundSkiaChartRenderer [static] → PNG/JPEG/PDF → Response (+ salvataggio disco se ?save=true)

Sviluppato da Smart Roots

Description
No description provided
Readme 558 KiB
Languages
C# 99.5%
Dockerfile 0.5%