From 5e9270eda71ec885fd0dfac9100b7d7c13a3e5fa Mon Sep 17 00:00:00 2001 From: dmolinari Date: Tue, 1 Jul 2025 12:45:32 -0300 Subject: [PATCH] feat: Complete API endpoints for grains and cattle data --- .../Controllers/MercadosController.cs | 51 +++++++++++++++++-- .../CotizacionGanadoRepository.cs | 15 +++++- .../Repositories/CotizacionGranoRepository.cs | 23 ++++++++- .../ICotizacionGanadoRepository.cs | 1 + .../ICotizacionGranoRepository.cs | 1 + 5 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/Mercados.Api/Controllers/MercadosController.cs b/src/Mercados.Api/Controllers/MercadosController.cs index 93a3f11..eedd326 100644 --- a/src/Mercados.Api/Controllers/MercadosController.cs +++ b/src/Mercados.Api/Controllers/MercadosController.cs @@ -9,15 +9,60 @@ namespace Mercados.Api.Controllers public class MercadosController : ControllerBase { private readonly ICotizacionBolsaRepository _bolsaRepo; + private readonly ICotizacionGranoRepository _granoRepo; + private readonly ICotizacionGanadoRepository _ganadoRepo; private readonly ILogger _logger; - // Inyectamos los repositorios que este controlador necesita. - public MercadosController(ICotizacionBolsaRepository bolsaRepo, ILogger logger) + // Inyectamos TODOS los repositorios que necesita el controlador. + public MercadosController( + ICotizacionBolsaRepository bolsaRepo, + ICotizacionGranoRepository granoRepo, + ICotizacionGanadoRepository ganadoRepo, + ILogger logger) { _bolsaRepo = bolsaRepo; + _granoRepo = granoRepo; + _ganadoRepo = ganadoRepo; _logger = logger; } + // --- Endpoint para Agroganadero --- + [HttpGet("agroganadero")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task GetAgroganadero() + { + try + { + var data = await _ganadoRepo.ObtenerUltimaTandaAsync(); + return Ok(data); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error al obtener cotizaciones de agroganadero."); + return StatusCode(500, "Ocurrió un error interno en el servidor."); + } + } + + // --- Endpoint para Granos --- + [HttpGet("granos")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status500InternalServerError)] + public async Task GetGranos() + { + try + { + var data = await _granoRepo.ObtenerUltimasAsync(); + return Ok(data); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error al obtener cotizaciones de granos."); + return StatusCode(500, "Ocurrió un error interno en el servidor."); + } + } + + // --- Endpoints de Bolsa --- [HttpGet("bolsa/eeuu")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status500InternalServerError)] @@ -51,7 +96,5 @@ namespace Mercados.Api.Controllers return StatusCode(500, "Ocurrió un error interno en el servidor."); } } - - // NOTA: Añadiremos los endpoints para Granos y Ganado en un momento. } } \ No newline at end of file diff --git a/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGanadoRepository.cs b/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGanadoRepository.cs index 85e1f5c..17809c0 100644 --- a/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGanadoRepository.cs +++ b/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGanadoRepository.cs @@ -16,7 +16,7 @@ namespace Mercados.Infrastructure.Persistence.Repositories public async Task GuardarMuchosAsync(IEnumerable cotizaciones) { using IDbConnection connection = _connectionFactory.CreateConnection(); - + // Dapper puede insertar una colección de objetos de una sola vez, ¡muy eficiente! const string sql = @" INSERT INTO CotizacionesGanado ( @@ -30,5 +30,18 @@ namespace Mercados.Infrastructure.Persistence.Repositories await connection.ExecuteAsync(sql, cotizaciones); } + public async Task> ObtenerUltimaTandaAsync() + { + using IDbConnection connection = _connectionFactory.CreateConnection(); + + // Primero, obtenemos la fecha de registro más reciente. + // Luego, seleccionamos todos los registros que tengan esa fecha. + const string sql = @" + SELECT * + FROM CotizacionesGanado + WHERE FechaRegistro = (SELECT MAX(FechaRegistro) FROM CotizacionesGanado);"; + + return await connection.QueryAsync(sql); + } } } \ No newline at end of file diff --git a/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGranoRepository.cs b/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGranoRepository.cs index dbffbb4..5d6678c 100644 --- a/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGranoRepository.cs +++ b/src/Mercados.Infrastructure/Persistence/Repositories/CotizacionGranoRepository.cs @@ -16,12 +16,33 @@ namespace Mercados.Infrastructure.Persistence.Repositories public async Task GuardarMuchosAsync(IEnumerable cotizaciones) { using IDbConnection connection = _connectionFactory.CreateConnection(); - + const string sql = @" INSERT INTO CotizacionesGranos (Nombre, Precio, VariacionPrecio, FechaOperacion, FechaRegistro) VALUES (@Nombre, @Precio, @VariacionPrecio, @FechaOperacion, @FechaRegistro);"; await connection.ExecuteAsync(sql, cotizaciones); } + public async Task> ObtenerUltimasAsync() + { + using IDbConnection connection = _connectionFactory.CreateConnection(); + + const string sql = @" + WITH RankedCotizaciones AS ( + SELECT + *, + ROW_NUMBER() OVER(PARTITION BY Nombre ORDER BY FechaRegistro DESC) as rn + FROM + CotizacionesGranos + ) + SELECT + Id, Nombre, Precio, VariacionPrecio, FechaOperacion, FechaRegistro + FROM + RankedCotizaciones + WHERE + rn = 1;"; + + return await connection.QueryAsync(sql); + } } } \ No newline at end of file diff --git a/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGanadoRepository.cs b/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGanadoRepository.cs index c36a4bd..122643f 100644 --- a/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGanadoRepository.cs +++ b/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGanadoRepository.cs @@ -5,5 +5,6 @@ namespace Mercados.Infrastructure.Persistence.Repositories public interface ICotizacionGanadoRepository : IBaseRepository { Task GuardarMuchosAsync(IEnumerable cotizaciones); + Task> ObtenerUltimaTandaAsync(); } } \ No newline at end of file diff --git a/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGranoRepository.cs b/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGranoRepository.cs index d8ecb4d..84ca922 100644 --- a/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGranoRepository.cs +++ b/src/Mercados.Infrastructure/Persistence/Repositories/ICotizacionGranoRepository.cs @@ -5,5 +5,6 @@ namespace Mercados.Infrastructure.Persistence.Repositories public interface ICotizacionGranoRepository : IBaseRepository { Task GuardarMuchosAsync(IEnumerable cotizaciones); + Task> ObtenerUltimasAsync(); } } \ No newline at end of file