From 8595dd16a8070f8667f23f34e72e248767a47bdd Mon Sep 17 00:00:00 2001 From: dmolinari Date: Tue, 1 Jul 2025 12:27:28 -0300 Subject: [PATCH] fix: Resolve encoding issue for AgroFetcher and authorization for BcrFetcher --- .../DataFetchers/BcrDataFetcher.cs | 43 ++++++++++++------- .../Mercados.Infrastructure.csproj | 1 + src/Mercados.Worker/Program.cs | 2 + 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/Mercados.Infrastructure/DataFetchers/BcrDataFetcher.cs b/src/Mercados.Infrastructure/DataFetchers/BcrDataFetcher.cs index d0d668a..393e087 100644 --- a/src/Mercados.Infrastructure/DataFetchers/BcrDataFetcher.cs +++ b/src/Mercados.Infrastructure/DataFetchers/BcrDataFetcher.cs @@ -11,19 +11,23 @@ namespace Mercados.Infrastructure.DataFetchers public class BcrDataFetcher : IDataFetcher { #region Clases DTO para la respuesta de la API de BCR - private class BcrTokenResponse { + private class BcrTokenResponse + { [JsonPropertyName("data")] public TokenData? Data { get; set; } } - private class TokenData { + private class TokenData + { [JsonPropertyName("token")] public string? Token { get; set; } } - private class BcrPreciosResponse { + private class BcrPreciosResponse + { [JsonPropertyName("data")] public List? Data { get; set; } } - private class BcrPrecioItem { + private class BcrPrecioItem + { [JsonPropertyName("precio_Cotizacion")] public decimal PrecioCotizacion { get; set; } [JsonPropertyName("variacion_Precio_Cotizacion")] @@ -47,10 +51,10 @@ namespace Mercados.Infrastructure.DataFetchers private readonly ILogger _logger; public BcrDataFetcher( - IHttpClientFactory httpClientFactory, - ICotizacionGranoRepository cotizacionRepository, - IFuenteDatoRepository fuenteDatoRepository, - IConfiguration configuration, + IHttpClientFactory httpClientFactory, + ICotizacionGranoRepository cotizacionRepository, + IFuenteDatoRepository fuenteDatoRepository, + IConfiguration configuration, ILogger logger) { _httpClientFactory = httpClientFactory; @@ -65,19 +69,26 @@ namespace Mercados.Infrastructure.DataFetchers _logger.LogInformation("Iniciando fetch para {SourceName}.", SourceName); try { - var client = _httpClientFactory.CreateClient(); + var client = _httpClientFactory.CreateClient(); // Creamos el cliente una vez + var token = await GetAuthTokenAsync(client); if (string.IsNullOrEmpty(token)) { return (false, "No se pudo obtener el token de autenticación de BCR."); } - client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + // Añadimos el token a las cabeceras por defecto de este cliente para todas las peticiones futuras. + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Replace("Bearer ", "")); // Aseguramos que no haya doble "Bearer" var cotizaciones = new List(); + var fechaDesde = DateTime.Now.AddDays(-3).ToString("yyyy-MM-dd"); + var fechaHasta = DateTime.Now.ToString("yyyy-MM-dd"); + foreach (var grain in _grainIds) { - var response = await client.GetFromJsonAsync( - $"{BaseUrl}/PreciosCamara?idGrano={grain.Value}&fechaConcertacionDesde={DateTime.Now.AddDays(-3):yyyy-MM-dd}&fechaConcertacionHasta={DateTime.Now:yyyy-MM-dd}"); + var requestUrl = $"{BaseUrl}/PreciosCamara?idGrano={grain.Value}&fechaConcertacionDesde={fechaDesde}&fechaConcertacionHasta={fechaHasta}"; + + // Usamos el mismo cliente que ya tiene el token configurado. + var response = await client.GetFromJsonAsync(requestUrl); var latestRecord = response?.Data?.OrderByDescending(r => r.FechaOperacionPizarra).FirstOrDefault(); if (latestRecord != null) @@ -92,12 +103,12 @@ namespace Mercados.Infrastructure.DataFetchers }); } } - + if (!cotizaciones.Any()) return (false, "No se obtuvieron datos de granos de BCR."); await _cotizacionRepository.GuardarMuchosAsync(cotizaciones); await UpdateSourceInfoAsync(); - + _logger.LogInformation("Fetch para {SourceName} completado. Se guardaron {Count} registros.", SourceName, cotizaciones.Count); return (true, $"Proceso completado. Se guardaron {cotizaciones.Count} registros."); } @@ -113,14 +124,14 @@ namespace Mercados.Infrastructure.DataFetchers var request = new HttpRequestMessage(HttpMethod.Post, $"{BaseUrl}/Login"); request.Headers.Add("api_key", _configuration["ApiKeys:Bcr:Key"]); request.Headers.Add("secret", _configuration["ApiKeys:Bcr:Secret"]); - + var response = await client.SendAsync(request); response.EnsureSuccessStatusCode(); var tokenResponse = await response.Content.ReadFromJsonAsync(); return tokenResponse?.Data?.Token; } - + private async Task UpdateSourceInfoAsync() { var fuente = await _fuenteDatoRepository.ObtenerPorNombreAsync(SourceName); diff --git a/src/Mercados.Infrastructure/Mercados.Infrastructure.csproj b/src/Mercados.Infrastructure/Mercados.Infrastructure.csproj index e55e3bd..65da25c 100644 --- a/src/Mercados.Infrastructure/Mercados.Infrastructure.csproj +++ b/src/Mercados.Infrastructure/Mercados.Infrastructure.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Mercados.Worker/Program.cs b/src/Mercados.Worker/Program.cs index be13d8d..34c828f 100644 --- a/src/Mercados.Worker/Program.cs +++ b/src/Mercados.Worker/Program.cs @@ -1,9 +1,11 @@ +using System.Text; using Mercados.Infrastructure; using Mercados.Infrastructure.DataFetchers; using Mercados.Infrastructure.Persistence; using Mercados.Infrastructure.Persistence.Repositories; using Mercados.Worker; +Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // --- Configuración del Host --- // Esto prepara el host del servicio, permitiendo la inyección de dependencias, // la configuración desde appsettings.json y el logging.