feat: add GET /api/chart/underlying/{idUnderlyings} endpoint

This commit is contained in:
2026-07-21 10:41:12 +02:00
parent 3887404572
commit 7b9553ad4e

View File

@@ -21,17 +21,20 @@ public class ChartController : ControllerBase
{ {
private readonly IChartDataService _chartDataService; private readonly IChartDataService _chartDataService;
private readonly IChartDataServiceV2 _chartDataServiceV2; private readonly IChartDataServiceV2 _chartDataServiceV2;
private readonly IUnderlyingChartDataService _underlyingChartDataService;
private readonly ILogger<ChartController> _logger; private readonly ILogger<ChartController> _logger;
private readonly IConfiguration _configuration; private readonly IConfiguration _configuration;
public ChartController( public ChartController(
IChartDataService chartDataService, IChartDataService chartDataService,
IChartDataServiceV2 chartDataServiceV2, IChartDataServiceV2 chartDataServiceV2,
IUnderlyingChartDataService underlyingChartDataService,
ILogger<ChartController> logger, ILogger<ChartController> logger,
IConfiguration configuration) IConfiguration configuration)
{ {
_chartDataService = chartDataService; _chartDataService = chartDataService;
_chartDataServiceV2 = chartDataServiceV2; _chartDataServiceV2 = chartDataServiceV2;
_underlyingChartDataService = underlyingChartDataService;
_logger = logger; _logger = logger;
_configuration = configuration; _configuration = configuration;
} }
@@ -175,6 +178,67 @@ public class ChartController : ControllerBase
} }
} }
/// <summary>
/// Endpoint standalone: grafico con solo la linea prezzo storico di UN sottostante,
/// identificato da IDUnderlyings — nessun contesto certificato (no strike/barriere/legenda).
/// Richiede SP cedlab_Chart_UnderlyingOnly nel DB.
/// Formati supportati: png (default), jpg/jpeg, pdf. Non supporta jpgEnc né ?save=true
/// (nessun alias-certificato applicabile a un sottostante puro).
/// </summary>
[HttpGet("underlying/{idUnderlyings:int}")]
public async Task<IActionResult> GenerateChartUnderlying(
int idUnderlyings,
[FromQuery] int width = 1100,
[FromQuery] int height = 700,
[FromQuery] string format = "png")
{
if (idUnderlyings <= 0)
return BadRequest("IDUnderlyings non valido.");
width = Math.Clamp(width, 400, 2000);
height = Math.Clamp(height, 300, 1500);
try
{
var chartData = await _underlyingChartDataService.GetChartDataAsync(idUnderlyings);
if (chartData == null || chartData.Points.Count == 0)
{
return NotFound(new
{
status = "KO",
message = $"Nessun dato per il grafico del sottostante {idUnderlyings}.",
});
}
bool isJpeg = format.Equals("jpg", StringComparison.OrdinalIgnoreCase)
|| format.Equals("jpeg", StringComparison.OrdinalIgnoreCase);
byte[] imgBytes = SkiaChartRendererV2.RenderSingleSeriesToPng(chartData, width, height, jpeg: isJpeg);
if (format.Equals("pdf", StringComparison.OrdinalIgnoreCase))
{
byte[] pdfBytes = WrapPngInPdf(imgBytes);
Response.Headers.Append("Content-Disposition", $"inline; filename=chart_underlying_{idUnderlyings}.pdf");
return File(pdfBytes, "application/pdf");
}
if (isJpeg)
{
Response.Headers.Append("Content-Disposition", $"inline; filename=chart_underlying_{idUnderlyings}.jpg");
return File(imgBytes, "image/jpeg");
}
Response.Headers.Append("Content-Disposition", $"inline; filename=chart_underlying_{idUnderlyings}.png");
return File(imgBytes, "image/png");
}
catch (Exception ex)
{
_logger.LogError(ex, "Errore generazione chart sottostante per IDUnderlyings {IDUnderlyings}", idUnderlyings);
return StatusCode(500, new { status = "KO", message = "Errore nella generazione del grafico sottostante." });
}
}
/// <summary> /// <summary>
/// Salva il JPEG su disco nei percorsi configurati in appsettings.json (ChartSettings). /// Salva il JPEG su disco nei percorsi configurati in appsettings.json (ChartSettings).
/// format=jpg/jpeg → SavePath/{isin}.jpg /// format=jpg/jpeg → SavePath/{isin}.jpg