docs: add implementation plan for Memoria field and Natixis parameter

This commit is contained in:
2026-03-26 11:56:01 +01:00
parent 1bf99a917c
commit de9d235703

View File

@@ -0,0 +1,521 @@
# Memoria Field + Natixis Parameter — Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add a "Memoria" KV field in the Analisi section of all reports, and a `?natixis` query param that switches the Tipologia source from `info.Categoria` to `info.Nome`.
**Architecture:** The `ShowNatixis` bool follows the existing `ShowBranding`/`ShowDividend` pattern: added to `CertificateReportData`, propagated from controller → orchestrator → renderers. Cache keys follow the existing suffix-concatenation pattern. The `DrawTitle` private method in both renderers gains a `bool showNatixis` parameter (Option A from spec).
**Tech Stack:** ASP.NET Core 8, Syncfusion PDF, C# 12
---
## Important Pre-Read
Before starting, note these facts about the existing code:
- `CertificateInfo.Memory` (string) **already exists** in `CertificateModels.cs:22` — no model/SP changes needed for Feature 1.
- `ExpiredAnagraficaSectionRenderer.DrawAnalisi` **already contains** `("Memoria Cedola", info.Memory)` at line 211 — it only needs to be **renamed** to `"Memoria"`.
- `AnagraficaSectionRenderer.DrawAnalisi` does **not** have the field — it needs to be **added** after `("Leva", ...)` at line 327.
- No automated tests exist in this project. Each task ends with `dotnet build` as verification.
---
## File Map
| File | Change |
|------|--------|
| `Models/CertificateModels.cs` | Add `bool ShowNatixis` to `CertificateReportData` |
| `Services/Interfaces/IServices.cs` | Add `showNatixis` param to `GenerateReportAsync` |
| `Controllers/ReportController.cs` | Add `[FromQuery] natixis` to all 3 endpoints + helper |
| `Services/Implementations/ReportOrchestrator.cs` | Add param, propagate flag, update cache key logic |
| `Services/Implementations/AnagraficaSectionRenderer.cs` | Add Memoria item in `DrawAnalisi`; add `showNatixis` to `DrawTitle` |
| `Services/Implementations/ExpiredAnagraficaSectionRenderer.cs` | Rename "Memoria Cedola"→"Memoria"; add `showNatixis` to `DrawTitle` |
---
## Task 1: Add `ShowNatixis` to `CertificateReportData`
**Files:**
- Modify: `CertReports.Syncfusion/Models/CertificateModels.cs` (around line 162)
- [ ] **Step 1: Add the property**
In `CertificateModels.cs`, find the `CertificateReportData` class:
```csharp
public class CertificateReportData
{
public CertificateInfo Info { get; set; } = new();
public List<CertificateEvent> Eventi { get; set; } = new();
public ScenarioAnalysis Scenario { get; set; } = new();
public byte[]? ChartImage { get; set; }
public bool ShowBranding { get; set; } = false;
public bool ShowDividend { get; set; } = false;
}
```
Add `ShowNatixis` after `ShowDividend`:
```csharp
public bool ShowDividend { get; set; } = false;
public bool ShowNatixis { get; set; } = false;
```
- [ ] **Step 2: Build**
```bash
dotnet build CertReports.Syncfusion
```
Expected: Build succeeded, 0 errors.
- [ ] **Step 3: Commit**
```bash
git add CertReports.Syncfusion/Models/CertificateModels.cs
git commit -m "feat: add ShowNatixis flag to CertificateReportData"
```
---
## Task 2: Update `IReportOrchestrator` interface
**Files:**
- Modify: `CertReports.Syncfusion/Services/Interfaces/IServices.cs` (line 49)
- [ ] **Step 1: Update the signature**
Find:
```csharp
Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false, bool showDividend = false);
```
Replace with:
```csharp
Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false, bool showDividend = false, bool showNatixis = false);
```
- [ ] **Step 2: Build**
```bash
dotnet build CertReports.Syncfusion
```
Expected: **Build fails** with CS0535 ("ReportOrchestrator does not implement interface member GenerateReportAsync") — this is intentional and will be resolved in Task 4.
- [ ] **Step 3: Commit**
```bash
git add CertReports.Syncfusion/Services/Interfaces/IServices.cs
git commit -m "feat: add showNatixis param to IReportOrchestrator interface"
```
---
## Task 3: Update `ReportController`
**Files:**
- Modify: `CertReports.Syncfusion/Controllers/ReportController.cs`
- [ ] **Step 1: Update `GenerateReport` endpoint (line 43)**
Find:
```csharp
public async Task<IActionResult> GenerateReport(
[FromQuery(Name = "p")] string? encryptedIsin = null,
[FromQuery(Name = "alias")] string? aliasId = null,
[FromQuery(Name = "branding")] bool showBranding = false,
[FromQuery(Name = "dividend")] bool showDividend = false)
```
Replace with:
```csharp
public async Task<IActionResult> GenerateReport(
[FromQuery(Name = "p")] string? encryptedIsin = null,
[FromQuery(Name = "alias")] string? aliasId = null,
[FromQuery(Name = "branding")] bool showBranding = false,
[FromQuery(Name = "dividend")] bool showDividend = false,
[FromQuery(Name = "natixis")] bool showNatixis = false)
```
- [ ] **Step 2: Update the call to `GenerateAndReturnPdf` inside `GenerateReport` (line 74)**
Find:
```csharp
return await GenerateAndReturnPdf(isin, showBranding, showDividend);
```
Replace with:
```csharp
return await GenerateAndReturnPdf(isin, showBranding, showDividend, showNatixis);
```
- [ ] **Step 3: Update `GenerateReportByIsin` endpoint (line 82)**
Find:
```csharp
public async Task<IActionResult> GenerateReportByIsin(
string isin,
[FromQuery(Name = "branding")] bool showBranding = false,
[FromQuery(Name = "dividend")] bool showDividend = false)
```
Replace with:
```csharp
public async Task<IActionResult> GenerateReportByIsin(
string isin,
[FromQuery(Name = "branding")] bool showBranding = false,
[FromQuery(Name = "dividend")] bool showDividend = false,
[FromQuery(Name = "natixis")] bool showNatixis = false)
```
- [ ] **Step 4: Update the call to `GenerateAndReturnPdf` inside `GenerateReportByIsin` (line 92)**
Find:
```csharp
return await GenerateAndReturnPdf(isin, showBranding, showDividend);
```
Replace with:
```csharp
return await GenerateAndReturnPdf(isin, showBranding, showDividend, showNatixis);
```
Note: there are two identical `return await GenerateAndReturnPdf(isin, showBranding, showDividend);` lines — make sure you update the one inside `GenerateReportByIsin` (around line 92).
- [ ] **Step 5: Update `DownloadReport` endpoint (line 99)**
Find:
```csharp
public async Task<IActionResult> DownloadReport(
[FromQuery(Name = "p")] string? encryptedIsin = null,
[FromQuery(Name = "alias")] string? aliasId = null,
[FromQuery(Name = "branding")] bool showBranding = false,
[FromQuery(Name = "dividend")] bool showDividend = false)
```
Replace with:
```csharp
public async Task<IActionResult> DownloadReport(
[FromQuery(Name = "p")] string? encryptedIsin = null,
[FromQuery(Name = "alias")] string? aliasId = null,
[FromQuery(Name = "branding")] bool showBranding = false,
[FromQuery(Name = "dividend")] bool showDividend = false,
[FromQuery(Name = "natixis")] bool showNatixis = false)
```
- [ ] **Step 6: Update the `_orchestrator.GenerateReportAsync` call inside `DownloadReport` (line 117)**
Find:
```csharp
var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend);
```
Replace with:
```csharp
var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend, showNatixis);
```
- [ ] **Step 7: Update `GenerateAndReturnPdf` helper signature (line 129)**
Find:
```csharp
private async Task<IActionResult> GenerateAndReturnPdf(string isin, bool showBranding = false, bool showDividend = false)
```
Replace with:
```csharp
private async Task<IActionResult> GenerateAndReturnPdf(string isin, bool showBranding = false, bool showDividend = false, bool showNatixis = false)
```
- [ ] **Step 8: Update the `_orchestrator.GenerateReportAsync` call inside `GenerateAndReturnPdf` (line 134)**
Find:
```csharp
var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend);
```
Replace with:
```csharp
var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend, showNatixis);
```
- [ ] **Step 9: Build**
```bash
dotnet build CertReports.Syncfusion
```
Expected: Build succeeded.
- [ ] **Step 10: Commit**
```bash
git add CertReports.Syncfusion/Controllers/ReportController.cs
git commit -m "feat: add natixis query param to all ReportController endpoints"
```
---
## Task 4: Update `ReportOrchestrator`
**Files:**
- Modify: `CertReports.Syncfusion/Services/Implementations/ReportOrchestrator.cs`
- [ ] **Step 1: Update method signature (line 47)**
Find:
```csharp
public async Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false, bool showDividend = false)
```
Replace with:
```csharp
public async Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false, bool showDividend = false, bool showNatixis = false)
```
- [ ] **Step 2: Update cache key logic (lines 50-52)**
Find:
```csharp
var dividendSuffix = showDividend ? ":dividend" : "";
var baseCacheKey = showBranding ? $"{isin}:branded{dividendSuffix}" : $"{isin}{dividendSuffix}";
var expiredCacheKey = showBranding ? $"{isin}:expired:branded{dividendSuffix}" : $"{isin}:expired{dividendSuffix}";
```
Replace with:
```csharp
var dividendSuffix = showDividend ? ":dividend" : "";
var natixisSuffix = showNatixis ? ":natixis" : "";
var baseCacheKey = showBranding
? $"{isin}:branded{dividendSuffix}{natixisSuffix}"
: $"{isin}{dividendSuffix}{natixisSuffix}";
var expiredCacheKey = showBranding
? $"{isin}:expired:branded{dividendSuffix}{natixisSuffix}"
: $"{isin}:expired{dividendSuffix}{natixisSuffix}";
```
- [ ] **Step 3: Propagate `ShowNatixis` into `CertificateReportData` (lines 64-71)**
Find:
```csharp
var reportData = new CertificateReportData
{
Info = await _dataService.GetCertificateInfoAsync(isin),
Eventi = await _dataService.GetCertificateEventsAsync(isin),
Scenario = await _dataService.GetScenarioAnalysisAsync(isin),
ShowBranding = showBranding,
ShowDividend = showDividend,
};
```
Replace with:
```csharp
var reportData = new CertificateReportData
{
Info = await _dataService.GetCertificateInfoAsync(isin),
Eventi = await _dataService.GetCertificateEventsAsync(isin),
Scenario = await _dataService.GetScenarioAnalysisAsync(isin),
ShowBranding = showBranding,
ShowDividend = showDividend,
ShowNatixis = showNatixis,
};
```
- [ ] **Step 4: Build**
```bash
dotnet build CertReports.Syncfusion
```
Expected: Build succeeded, 0 errors.
- [ ] **Step 5: Commit**
```bash
git add CertReports.Syncfusion/Services/Implementations/ReportOrchestrator.cs
git commit -m "feat: propagate showNatixis through orchestrator and cache keys"
```
---
## Task 5: Update `AnagraficaSectionRenderer` (active certs)
Two changes: (A) add Memoria to `DrawAnalisi`, (B) support natixis in `DrawTitle`.
**Files:**
- Modify: `CertReports.Syncfusion/Services/Implementations/AnagraficaSectionRenderer.cs`
### Change A — Add Memoria to DrawAnalisi
- [ ] **Step 1: Add Memoria item after Leva (line 327)**
Find (this is the closing `};` of the `leftItems` array — NOT the `rightItems` array that follows a few lines later):
```csharp
("Leva", string.IsNullOrWhiteSpace(info.Leva) ? "—" : info.Leva),
};
```
Replace with:
```csharp
("Leva", string.IsNullOrWhiteSpace(info.Leva) ? "—" : info.Leva),
("Memoria", string.IsNullOrWhiteSpace(info.Memory) ? "—" : info.Memory),
};
```
### Change B — Support Natixis in DrawTitle
- [ ] **Step 2: Update the `DrawTitle` call site in `Render` (line 37)**
Find:
```csharp
y = DrawTitle(g, info, PageW, y);
```
Replace with:
```csharp
y = DrawTitle(g, info, PageW, y, data.ShowNatixis);
```
- [ ] **Step 3: Update `DrawTitle` signature (line 74)**
Find:
```csharp
private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y)
```
Replace with:
```csharp
private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y, bool showNatixis)
```
- [ ] **Step 4: Update Tipologia resolution in `DrawTitle` (line 95)**
Find:
```csharp
bool showTip = !string.IsNullOrEmpty(info.Categoria);
```
Replace with:
```csharp
string tipologia = showNatixis ? info.Nome : info.Categoria;
bool showTip = !string.IsNullOrEmpty(tipologia);
```
- [ ] **Step 5: Replace `info.Categoria` with `tipologia` in the `DrawInfoBox` call (line 110)**
Find:
```csharp
"TIPOLOGIA", info.Categoria,
```
Replace with:
```csharp
"TIPOLOGIA", tipologia,
```
- [ ] **Step 6: Build**
```bash
dotnet build CertReports.Syncfusion
```
Expected: Build succeeded, 0 errors.
- [ ] **Step 7: Commit**
```bash
git add CertReports.Syncfusion/Services/Implementations/AnagraficaSectionRenderer.cs
git commit -m "feat: add Memoria field to Analisi and natixis support to AnagraficaSectionRenderer"
```
---
## Task 6: Update `ExpiredAnagraficaSectionRenderer` (expired certs)
Two changes: (A) rename "Memoria Cedola" → "Memoria" in `DrawAnalisi`, (B) support natixis in `DrawTitle`.
**Files:**
- Modify: `CertReports.Syncfusion/Services/Implementations/ExpiredAnagraficaSectionRenderer.cs`
### Change A — Rename label in DrawAnalisi
- [ ] **Step 1: Rename "Memoria Cedola" to "Memoria" (line 211)**
Find:
```csharp
("Memoria Cedola", info.Memory),
```
Replace with:
```csharp
("Memoria", info.Memory),
```
### Change B — Support Natixis in DrawTitle
- [ ] **Step 2: Update the `DrawTitle` call site in `Render` (line 36)**
Find:
```csharp
y = DrawTitle(g, info, PageW, y);
```
Replace with:
```csharp
y = DrawTitle(g, info, PageW, y, data.ShowNatixis);
```
- [ ] **Step 3: Update `DrawTitle` signature (line 72)**
Find:
```csharp
private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y)
```
Replace with:
```csharp
private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y, bool showNatixis)
```
- [ ] **Step 4: Update Tipologia resolution in `DrawTitle` (line 86)**
Find:
```csharp
if (!string.IsNullOrEmpty(info.Categoria))
{
DrawInfoBox(g, 0, y, w, boxH,
"TIPOLOGIA", info.Categoria,
```
Replace with:
```csharp
string tipologia = showNatixis ? info.Nome : info.Categoria;
if (!string.IsNullOrEmpty(tipologia))
{
DrawInfoBox(g, 0, y, w, boxH,
"TIPOLOGIA", tipologia,
```
- [ ] **Step 5: Build**
```bash
dotnet build CertReports.Syncfusion
```
Expected: Build succeeded, 0 errors.
- [ ] **Step 6: Commit**
```bash
git add CertReports.Syncfusion/Services/Implementations/ExpiredAnagraficaSectionRenderer.cs
git commit -m "feat: rename Memoria Cedola and add natixis support to ExpiredAnagraficaSectionRenderer"
```
---
## Task 7: Manual Verification
- [ ] **Step 1: Run the application**
```bash
dotnet run --project CertReports.Syncfusion
```
- [ ] **Step 2: Verify Memoria field (active cert)**
Open: `https://localhost:{port}/api/report/by-isin/{ISIN_ATTIVO}`
Expected: In the Analisi section (left column), "Memoria" appears below "Leva" as the 9th item. If `info.Memory` is empty, shows "—".
- [ ] **Step 3: Verify Memoria field (expired cert)**
Open: `https://localhost:{port}/api/report/by-isin/{ISIN_SCADUTO}`
Expected: In the Analisi section, the field is labeled "Memoria" (not "Memoria Cedola").
- [ ] **Step 4: Verify Natixis=false (default)**
Open: `https://localhost:{port}/api/report/by-isin/{ISIN}` (no natixis param)
Expected: Tipologia box shows `info.Categoria` — same as before.
- [ ] **Step 5: Verify Natixis=true**
Open: `https://localhost:{port}/api/report/by-isin/{ISIN}?natixis=true`
Expected: Tipologia box shows `info.Nome` instead of `info.Categoria`.
- [ ] **Step 6: Verify cache keys are independent**
Open the same ISIN first without natixis, then with `?natixis=true`. Both should generate fresh PDFs with the correct Tipologia value (not the cached one).