Files
SmartReports/docs/superpowers/plans/2026-03-26-memoria-natixis.md

17 KiB

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:

    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:

        public bool ShowDividend { get; set; } = false;
        public bool ShowNatixis { get; set; } = false;
    
  • Step 2: Build

    dotnet build CertReports.Syncfusion
    

    Expected: Build succeeded, 0 errors.

  • Step 3: Commit

    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:

        Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false, bool showDividend = false);
    

    Replace with:

        Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false, bool showDividend = false, bool showNatixis = false);
    
  • Step 2: Build

    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

    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:

        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:

        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:

            return await GenerateAndReturnPdf(isin, showBranding, showDividend);
    

    Replace with:

            return await GenerateAndReturnPdf(isin, showBranding, showDividend, showNatixis);
    
  • Step 3: Update GenerateReportByIsin endpoint (line 82)

    Find:

        public async Task<IActionResult> GenerateReportByIsin(
            string isin,
            [FromQuery(Name = "branding")] bool showBranding = false,
            [FromQuery(Name = "dividend")] bool showDividend = false)
    

    Replace with:

        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:

            return await GenerateAndReturnPdf(isin, showBranding, showDividend);
    

    Replace with:

            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:

        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:

        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:

                var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend);
    

    Replace with:

                var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend, showNatixis);
    
  • Step 7: Update GenerateAndReturnPdf helper signature (line 129)

    Find:

        private async Task<IActionResult> GenerateAndReturnPdf(string isin, bool showBranding = false, bool showDividend = false)
    

    Replace with:

        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:

                var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend);
    

    Replace with:

                var pdfBytes = await _orchestrator.GenerateReportAsync(isin, showBranding, showDividend, showNatixis);
    
  • Step 9: Build

    dotnet build CertReports.Syncfusion
    

    Expected: Build succeeded.

  • Step 10: Commit

    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:

        public async Task<byte[]> GenerateReportAsync(string isin, bool showBranding = false, bool showDividend = false)
    

    Replace with:

        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:

            var dividendSuffix = showDividend ? ":dividend" : "";
            var baseCacheKey    = showBranding ? $"{isin}:branded{dividendSuffix}"         : $"{isin}{dividendSuffix}";
            var expiredCacheKey = showBranding ? $"{isin}:expired:branded{dividendSuffix}" : $"{isin}:expired{dividendSuffix}";
    

    Replace with:

            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:

            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:

            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

    dotnet build CertReports.Syncfusion
    

    Expected: Build succeeded, 0 errors.

  • Step 5: Commit

    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):

                ("Leva",                  string.IsNullOrWhiteSpace(info.Leva) ? "—" : info.Leva),
            };
    

    Replace with:

                ("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:

            y = DrawTitle(g, info, PageW, y);
    

    Replace with:

            y = DrawTitle(g, info, PageW, y, data.ShowNatixis);
    
  • Step 3: Update DrawTitle signature (line 74)

    Find:

        private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y)
    

    Replace with:

        private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y, bool showNatixis)
    
  • Step 4: Update Tipologia resolution in DrawTitle (line 95)

    Find:

            bool showTip    = !string.IsNullOrEmpty(info.Categoria);
    

    Replace with:

            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:

                    "TIPOLOGIA", info.Categoria,
    

    Replace with:

                    "TIPOLOGIA", tipologia,
    
  • Step 6: Build

    dotnet build CertReports.Syncfusion
    

    Expected: Build succeeded, 0 errors.

  • Step 7: Commit

    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:

                ("Memoria Cedola",        info.Memory),
    

    Replace with:

                ("Memoria",               info.Memory),
    

Change B — Support Natixis in DrawTitle

  • Step 2: Update the DrawTitle call site in Render (line 36)

    Find:

            y = DrawTitle(g, info, PageW, y);
    

    Replace with:

            y = DrawTitle(g, info, PageW, y, data.ShowNatixis);
    
  • Step 3: Update DrawTitle signature (line 72)

    Find:

        private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y)
    

    Replace with:

        private float DrawTitle(PdfGraphics g, CertificateInfo info, float w, float y, bool showNatixis)
    
  • Step 4: Update Tipologia resolution in DrawTitle (line 86)

    Find:

            if (!string.IsNullOrEmpty(info.Categoria))
            {
                DrawInfoBox(g, 0, y, w, boxH,
                    "TIPOLOGIA", info.Categoria,
    

    Replace with:

            string tipologia = showNatixis ? info.Nome : info.Categoria;
            if (!string.IsNullOrEmpty(tipologia))
            {
                DrawInfoBox(g, 0, y, w, boxH,
                    "TIPOLOGIA", tipologia,
    
  • Step 5: Build

    dotnet build CertReports.Syncfusion
    

    Expected: Build succeeded, 0 errors.

  • Step 6: Commit

    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

    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).