Files
SmartReports/docs/superpowers/specs/2026-06-08-fund-report-design.md
2026-06-08 17:20:43 +02:00

250 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Design Spec — Report ETF/Fondi
**Data:** 2026-06-08
**Scope:** Nuovo report PDF a 2 pagine per ETF/fondi, con endpoint dedicati `/api/report/fund/` e `/api/chart/fund/`. Indipendente dal flusso certificati.
---
## 1. Endpoints
### Report PDF
| Metodo | Route | Comportamento |
|--------|-------|---------------|
| GET | `/api/report/fund/by-isin/{isin}` | PDF inline |
| GET | `/api/report/fund?p={isin_cifrato}` | PDF inline (ISIN cifrato, stesso CryptoHelper) |
| GET | `/api/report/fund?alias={id}` | PDF inline (alias → ISIN via `FindIsinByAliasIdAsync`) |
| GET | `/api/report/fund/download?p={...}` | PDF come allegato (`Content-Disposition: attachment`) |
### Grafico standalone
| Metodo | Route | Comportamento |
|--------|-------|---------------|
| GET | `/api/chart/fund/{isin}` | PNG/PDF inline (vedi §4) |
### Parametri opzionali (tutti gli endpoint report)
| Parametro | Default | Effetto |
|-----------|---------|---------|
| `?branding=true` | `false` | Footer "Powered by [Smart Roots](https://www.smart-roots.net)" — riusa `PdfTheme.DrawFooter` già esistente |
### Parametri opzionali (endpoint chart)
| Parametro | Default | Effetto |
|-----------|---------|---------|
| `?format=png\|pdf\|jpg\|jpeg` | `png` | Formato output |
| `?save=true` | `false` | Salva JPEG su disco (`ChartSettings:SavePath`) |
---
## 2. Architettura
```
HTTP → FundReportController
├── FundDataService sfih_GetOptDettagli @ISIN → FundInfo
├── FundReportOrchestrator
│ ├── FundAnagraficaRenderer → PdfDocument (Pagina 1)
│ ├── FundChartRenderer → PdfDocument (Pagina 2, placeholder)
│ └── PdfMergerService → byte[] (riusato)
└── PdfCacheService → cache chiave "fund:{isin}[:branded]"
HTTP → FundChartController
├── FundChartDataService SP da definire → FundChartData
└── FundSkiaChartRenderer → PNG/JPEG/PDF
```
**Riuso componenti esistenti:** `PdfMergerService`, `PdfCacheService`, `PdfTheme` (incluso `DrawFooter`), `CryptoHelper`.
**Nessuna modifica** ai controller/renderer/service certificati esistenti.
---
## 3. Pagina 1 — Anagrafica (Layout C)
### Struttura visiva
```
┌─────────────────────────────────────────────────────────┐
│ [BLUE BAR] {typ} — {str} — {isn} │
├──────────────────────────────────────────────────────────┤
│ [RANK strip] rnk │ [PREZZO strip] prz val │ dpz │
├──────────────────────────────────────────────────────────┤
│ Dati Anagrafici │ ESG Score │ Perf·Vol·R/R grid │
│ (flex 1.3) │ (flex 0.9) │ (flex 1.4) │
└──────────────────────────────────────────────────────────┘
│ footer: [Powered by Smart Roots]? pagina N │
```
### Mapping campi SP → sezioni
**Titolo:**
- `{typ} — {str} — {isn}` (es. `ETF — WisdomTree … — IE00BDVPNG13`)
**Strip Rank/Prezzo:**
- Rank: `rnk`
- Prezzo: `prz` + `val`
- Data aggiornamento: `dpz` (formato `dd/MM/yyyy`)
**Dati Anagrafici** (tabella label/valore):
| Label | Campo SP |
|-------|----------|
| Società | `soc` |
| Categoria MS | `msc` |
| Tipo | `typ` |
| Valuta | `val` |
| Hedged | `hed` (→ `"sì"` / `"no"`) |
| Benchmark | `bmk` |
| Spese correnti | `spc` (→ formato `0.##%`) |
| Catalogo | `itr` |
| Proventi | `prv` |
| Data lancio | `daf` (formato `dd/MM/yyyy`) |
| Patrimonio | `pat` (formato `#,##0 EUR`) |
**ESG Score** (4 card verdi verticali):
- Sustainability: `sus`
- Environmental: `env`
- Social: `ssc`
- Governance: `gov`
- Se un singolo valore è `0` (AMC/fallback), viene mostrato come `"—"`. La sezione ESG è sempre visibile.
**Griglia Performance/Volatilità/RendRisk** (3×2):
| Periodo | Perf | Vol | R/R |
|---------|------|-----|-----|
| 3 Mesi | `p3M` | `v3M` | `r3M` |
| 6 Mesi | `p6M` | `v6M` | `r6M` |
| Da inizio anno | `pYD` | `vYD` | `rYD` |
| 1 Anno | `p1Y` | `v1Y` | `r1Y` |
| 3 Anni | `p3Y` | `v3Y` | `r3Y` |
| 5 Anni | `p5Y` | `v5Y` | `r5Y` |
Colori: Perf positiva → `PositiveGreenBrush`, negativa → `NegativeRedBrush`, Vol e R/R → testo normale.
---
## 4. Pagina 2 — Grafico
**SP:** `sfih_GetChartPrices @ISIN VARCHAR(20)`
Restituisce `Px_Close (decimal)` e `Px_Date (date)` ordinati ASC, solo valori non NULL.
`FundChartRenderer` (pagina 2 nel PDF report):
- Singola linea nera sul close price storico
- Asse X: date (intervalli mensili adattivi come chart V2)
- Asse Y: scala automatica su min/max dei prezzi
- Titolo: `"Andamento Prezzo — {str}"` + sottotitolo con valuta
- Se la SP restituisce < 2 punti, la pagina mostra un messaggio "Dati insufficienti"
`FundSkiaChartRenderer` (endpoint standalone `/api/chart/fund/{isin}`):
- Stessa logica di rendering, output PNG/JPEG/PDF
- Supporta `?format=png|jpg|jpeg|pdf`, `?width=`, `?height=`, `?save=true`
- `?save=true` salva JPEG in `ChartSettings:SavePath\{isin}_fund.jpg`
- Nessuna logica WorstOf/barriere/label complesse (renderer dedicato, non V2)
---
## 5. Modelli
**File:** `Models/FundModels.cs`
```csharp
// Mapping 1:1 con result set di sfih_GetOptDettagli
public class FundInfo
{
public string Isin { get; set; } // isn
public string Strumento { get; set; } // str
public string Tipo { get; set; } // typ
public string Societa { get; set; } // soc
public string CategoriaMorningstar { get; set; } // msc
public string Valuta { get; set; } // val
public string Hedged { get; set; } // hed
public string Benchmark { get; set; } // bmk
public string Catalogo { get; set; } // itr
public string Proventi { get; set; } // prv
public DateTime? DataLancio { get; set; } // daf
public decimal? Patrimonio { get; set; } // pat
public decimal? SpeseCorrenti { get; set; } // spc
public decimal? Prezzo { get; set; } // prz
public DateTime? DataPrezzo { get; set; } // dpz
public decimal? Rank { get; set; } // rnk
// Performance
public decimal? P3M { get; set; } public decimal? P6M { get; set; }
public decimal? PYD { get; set; } public decimal? P1Y { get; set; }
public decimal? P3Y { get; set; } public decimal? P5Y { get; set; }
// Volatilità
public decimal? V3M { get; set; } public decimal? V6M { get; set; }
public decimal? VYD { get; set; } public decimal? V1Y { get; set; }
public decimal? V3Y { get; set; } public decimal? V5Y { get; set; }
// RendRisk
public decimal? R3M { get; set; } public decimal? R6M { get; set; }
public decimal? RYD { get; set; } public decimal? R1Y { get; set; }
public decimal? R3Y { get; set; } public decimal? R5Y { get; set; }
// ESG
public decimal? Sustainability { get; set; } // sus
public decimal? Environmental { get; set; } // env
public decimal? Social { get; set; } // ssc
public decimal? Governance { get; set; } // gov
}
public class FundReportData
{
public FundInfo Info { get; set; }
public bool ShowBranding { get; set; }
}
```
---
## 6. Interfacce
```csharp
// IFundDataService
Task<FundInfo?> GetFundInfoAsync(string isin);
Task<string?> FindIsinByAliasIdAsync(string aliasId); // riusa stessa logica
// IFundReportOrchestrator
Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false);
```
---
## 7. Registrazioni Program.cs
```csharp
builder.Services.AddScoped<IFundDataService, FundDataService>();
builder.Services.AddScoped<IFundReportOrchestrator, FundReportOrchestrator>();
builder.Services.AddScoped<FundAnagraficaRenderer>();
builder.Services.AddScoped<FundChartRenderer>(); // placeholder
builder.Services.AddScoped<FundSkiaChartRenderer>(); // per /api/chart/fund/
```
---
## 8. Cache
Chiave pattern: `fund:{isin}` + suffisso `:branded` se `showBranding=true`.
Riusa il `PdfCacheService` esistente (stesso TTL da `appsettings.json`).
---
## 9. File da creare
| File | Descrizione |
|------|-------------|
| `Models/FundModels.cs` | `FundInfo`, `FundReportData`, `FundChartData` (placeholder) |
| `Services/Interfaces/IFundServices.cs` | `IFundDataService`, `IFundReportOrchestrator` |
| `Services/Implementations/FundDataService.cs` | Chiama `sfih_GetOptDettagli` |
| `Services/Implementations/FundAnagraficaRenderer.cs` | Pagina 1 layout C |
| `Services/Implementations/FundChartRenderer.cs` | Pagina 2 placeholder |
| `Services/Implementations/FundReportOrchestrator.cs` | Coordina anagrafica + chart + merge + cache |
| `Services/Implementations/FundSkiaChartRenderer.cs` | Rendering grafico (placeholder, SP da aggiungere) |
| `Controllers/FundReportController.cs` | 4 endpoint `/api/report/fund/` |
| `Controllers/FundChartController.cs` | 1 endpoint `/api/chart/fund/` |
---
## 10. Fuori scope (questa iterazione)
- Parametri `?natixis`, `?dividend` — non applicabili ai fondi
- Test automatici (nessun test nel progetto al momento)