using Dapper; using GestionIntegral.Api.Models.Distribucion; using Microsoft.Extensions.Configuration; // Para IConfiguration using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Data; using Microsoft.Data.SqlClient; // O el proveedor de tu BD using System.Linq; using System.Threading.Tasks; using GestionIntegral.Api.Dtos.Reportes; using System.Text; namespace GestionIntegral.Api.Data.Repositories.Distribucion { public class NovedadCanillaRepository : INovedadCanillaRepository { private readonly DbConnectionFactory _connectionFactory; // Inyecta tu DbConnectionFactory private readonly ILogger _logger; public NovedadCanillaRepository(DbConnectionFactory connectionFactory, ILogger logger) { _connectionFactory = connectionFactory; _logger = logger; } private async Task LogHistorialAsync(NovedadCanilla novedadOriginal, int idUsuario, string tipoMod, IDbConnection connection, IDbTransaction? transaction) { var historial = new NovedadCanillaHistorial { IdNovedad = novedadOriginal.IdNovedad, IdCanilla = novedadOriginal.IdCanilla, Fecha = novedadOriginal.Fecha, Detalle = novedadOriginal.Detalle, IdUsuario = idUsuario, FechaMod = DateTime.Now, TipoMod = tipoMod }; var sqlHistorial = @" INSERT INTO dbo.dist_dtNovedadesCanillas_H (Id_Novedad, Id_Canilla, Fecha, Detalle, Id_Usuario, FechaMod, TipoMod) VALUES (@IdNovedad, @IdCanilla, @Fecha, @Detalle, @IdUsuario, @FechaMod, @TipoMod);"; await connection.ExecuteAsync(sqlHistorial, historial, transaction); } public async Task> GetByCanillaAsync(int idCanilla, DateTime? fechaDesde, DateTime? fechaHasta) { using var connection = _connectionFactory.CreateConnection(); var sqlBuilder = new System.Text.StringBuilder(@" SELECT n.Id_Novedad AS IdNovedad, n.Id_Canilla AS IdCanilla, n.Fecha, n.Detalle, c.NomApe AS NombreCanilla FROM dbo.dist_dtNovedadesCanillas n JOIN dbo.dist_dtCanillas c ON n.Id_Canilla = c.Id_Canilla WHERE n.Id_Canilla = @IdCanilla"); var parameters = new DynamicParameters(); parameters.Add("IdCanilla", idCanilla); if (fechaDesde.HasValue) { sqlBuilder.Append(" AND n.Fecha >= @FechaDesde"); parameters.Add("FechaDesde", fechaDesde.Value.Date); // Solo fecha, sin hora } if (fechaHasta.HasValue) { sqlBuilder.Append(" AND n.Fecha <= @FechaHasta"); // Para incluir todo el día de fechaHasta parameters.Add("FechaHasta", fechaHasta.Value.Date.AddDays(1).AddTicks(-1)); } sqlBuilder.Append(" ORDER BY n.Fecha DESC, n.Id_Novedad DESC;"); var result = await connection.QueryAsync( sqlBuilder.ToString(), (novedad, nombreCanilla) => (novedad, nombreCanilla), parameters, splitOn: "NombreCanilla" ); return result; } public async Task GetByIdAsync(int idNovedad) { using var connection = _connectionFactory.CreateConnection(); var sql = "SELECT Id_Novedad AS IdNovedad, Id_Canilla AS IdCanilla, Fecha, Detalle FROM dbo.dist_dtNovedadesCanillas WHERE Id_Novedad = @IdNovedad;"; return await connection.QuerySingleOrDefaultAsync(sql, new { IdNovedad = idNovedad }); } public async Task ExistsByCanillaAndFechaAsync(int idCanilla, DateTime fecha, int? excludeIdNovedad = null) { using var connection = _connectionFactory.CreateConnection(); var sqlBuilder = new System.Text.StringBuilder("SELECT COUNT(1) FROM dbo.dist_dtNovedadesCanillas WHERE Id_Canilla = @IdCanilla AND Fecha = @Fecha"); var parameters = new DynamicParameters(); parameters.Add("IdCanilla", idCanilla); parameters.Add("Fecha", fecha.Date); // Comparar solo la fecha if (excludeIdNovedad.HasValue) { sqlBuilder.Append(" AND Id_Novedad != @ExcludeIdNovedad"); parameters.Add("ExcludeIdNovedad", excludeIdNovedad.Value); } var count = await connection.ExecuteScalarAsync(sqlBuilder.ToString(), parameters); return count > 0; } public async Task CreateAsync(NovedadCanilla novedad, int idUsuario, IDbTransaction? transaction = null) { var sql = @" INSERT INTO dbo.dist_dtNovedadesCanillas (Id_Canilla, Fecha, Detalle) VALUES (@IdCanilla, @Fecha, @Detalle); SELECT CAST(SCOPE_IDENTITY() as int);"; IDbConnection conn = transaction?.Connection ?? _connectionFactory.CreateConnection(); bool manageConnection = transaction == null; // Solo gestionar si no hay transacción externa try { if (manageConnection && conn.State != ConnectionState.Open) await (conn as SqlConnection)!.OpenAsync(); var newId = await conn.QuerySingleAsync(sql, novedad, transaction); novedad.IdNovedad = newId; await LogHistorialAsync(novedad, idUsuario, "Insertada", conn, transaction); return novedad; } catch (Exception ex) { _logger.LogError(ex, "Error al crear NovedadCanilla para Canilla ID: {IdCanilla}", novedad.IdCanilla); return null; } finally { if (manageConnection && conn.State == ConnectionState.Open) conn.Close(); } } public async Task UpdateAsync(NovedadCanilla novedad, int idUsuario, IDbTransaction? transaction = null) { var novedadOriginal = await GetByIdAsync(novedad.IdNovedad); // Necesitamos el estado original para el log if (novedadOriginal == null) return false; // No se encontró var sql = @" UPDATE dbo.dist_dtNovedadesCanillas SET Detalle = @Detalle -- No se permite cambiar IdCanilla ni Fecha de una novedad existente WHERE Id_Novedad = @IdNovedad;"; IDbConnection conn = transaction?.Connection ?? _connectionFactory.CreateConnection(); bool manageConnection = transaction == null; try { if (manageConnection && conn.State != ConnectionState.Open) await (conn as SqlConnection)!.OpenAsync(); await LogHistorialAsync(novedadOriginal, idUsuario, "Modificada", conn, transaction); // Log con datos ANTES de actualizar var affectedRows = await conn.ExecuteAsync(sql, novedad, transaction); return affectedRows > 0; } catch (Exception ex) { _logger.LogError(ex, "Error al actualizar NovedadCanilla ID: {IdNovedad}", novedad.IdNovedad); return false; } finally { if (manageConnection && conn.State == ConnectionState.Open) conn.Close(); } } public async Task DeleteAsync(int idNovedad, int idUsuario, IDbTransaction? transaction = null) { var novedadOriginal = await GetByIdAsync(idNovedad); if (novedadOriginal == null) return false; var sql = "DELETE FROM dbo.dist_dtNovedadesCanillas WHERE Id_Novedad = @IdNovedad;"; IDbConnection conn = transaction?.Connection ?? _connectionFactory.CreateConnection(); bool manageConnection = transaction == null; try { if (manageConnection && conn.State != ConnectionState.Open) await (conn as SqlConnection)!.OpenAsync(); await LogHistorialAsync(novedadOriginal, idUsuario, "Eliminada", conn, transaction); var affectedRows = await conn.ExecuteAsync(sql, new { IdNovedad = idNovedad }, transaction); return affectedRows > 0; } catch (Exception ex) { _logger.LogError(ex, "Error al eliminar NovedadCanilla ID: {IdNovedad}", idNovedad); return false; } finally { if (manageConnection && conn.State == ConnectionState.Open) conn.Close(); } } public async Task> GetReporteNovedadesAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta) { using var connection = _connectionFactory.CreateConnection(); var parameters = new { idEmpresa, fechaDesde = fechaDesde.Date, // Enviar solo la fecha fechaHasta = fechaHasta.Date.AddDays(1).AddTicks(-1) // Para incluir todo el día hasta las 23:59:59.999... }; // El nombre del SP en el archivo es SP_DistCanillasNovedades return await connection.QueryAsync( "dbo.SP_DistCanillasNovedades", // Asegúrate que el nombre del SP sea exacto parameters, commandType: CommandType.StoredProcedure ); } public async Task> GetReporteGananciasAsync(int idEmpresa, DateTime fechaDesde, DateTime fechaHasta) { using var connection = _connectionFactory.CreateConnection(); var parameters = new { idEmpresa, fechaDesde = fechaDesde.Date, fechaHasta = fechaHasta.Date // El SP SP_DistCanillasGanancias maneja el rango inclusivo directamente }; return await connection.QueryAsync( "dbo.SP_DistCanillasGanancias", // Nombre del SP parameters, commandType: CommandType.StoredProcedure ); } public async Task> GetHistorialAsync( DateTime? fechaDesde, DateTime? fechaHasta, int? idUsuarioModifico, string? tipoModificacion, int? idNovedadOriginal) { using var connection = _connectionFactory.CreateConnection(); var sqlBuilder = new StringBuilder(@" SELECT h.Id_Novedad, h.Id_Canilla, h.Fecha, h.Detalle, h.Id_Usuario, h.FechaMod, h.TipoMod, u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico FROM dbo.dist_dtNovedadesCanillas_H h JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id WHERE 1=1"); var parameters = new DynamicParameters(); if (fechaDesde.HasValue) { sqlBuilder.Append(" AND h.FechaMod >= @FechaDesdeParam"); parameters.Add("FechaDesdeParam", fechaDesde.Value.Date); } if (fechaHasta.HasValue) { sqlBuilder.Append(" AND h.FechaMod <= @FechaHastaParam"); parameters.Add("FechaHastaParam", fechaHasta.Value.Date.AddDays(1).AddTicks(-1)); } if (idUsuarioModifico.HasValue) { sqlBuilder.Append(" AND h.Id_Usuario = @IdUsuarioModificoParam"); parameters.Add("IdUsuarioModificoParam", idUsuarioModifico.Value); } if (!string.IsNullOrWhiteSpace(tipoModificacion)) { sqlBuilder.Append(" AND h.TipoMod = @TipoModParam"); parameters.Add("TipoModParam", tipoModificacion); } if (idNovedadOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Novedad = @IdNovedadOriginalParam"); parameters.Add("IdNovedadOriginalParam", idNovedadOriginal.Value); } sqlBuilder.Append(" ORDER BY h.FechaMod DESC;"); try { var result = await connection.QueryAsync( sqlBuilder.ToString(), (hist, userName) => (hist, userName), parameters, splitOn: "NombreUsuarioModifico" ); return result; } catch (Exception ex) { _logger.LogError(ex, "Error al obtener historial de Novedades de Canillitas."); return Enumerable.Empty<(NovedadCanillaHistorico, string)>(); } } } }