using Dapper; using GestionIntegral.Api.Models.Impresion; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Data; using System.Text; using System.Threading.Tasks; namespace GestionIntegral.Api.Data.Repositories.Impresion { public class RegTiradaRepository : IRegTiradaRepository { private readonly DbConnectionFactory _cf; private readonly ILogger _log; public RegTiradaRepository(DbConnectionFactory cf, ILogger log) { _cf = cf; _log = log; } public async Task GetByIdAsync(int idRegistro) { const string sql = "SELECT Id_Registro AS IdRegistro, Ejemplares, Id_Publicacion AS IdPublicacion, Fecha, Id_Planta AS IdPlanta FROM dbo.bob_RegTiradas WHERE Id_Registro = @IdRegistroParam"; using var connection = _cf.CreateConnection(); return await connection.QuerySingleOrDefaultAsync(sql, new { IdRegistroParam = idRegistro }); } public async Task GetByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta, IDbTransaction? transaction = null) { const string sql = "SELECT Id_Registro AS IdRegistro, Ejemplares, Id_Publicacion AS IdPublicacion, Fecha, Id_Planta AS IdPlanta FROM dbo.bob_RegTiradas WHERE Fecha = @FechaParam AND Id_Publicacion = @IdPublicacionParam AND Id_Planta = @IdPlantaParam"; var cn = transaction?.Connection ?? _cf.CreateConnection(); bool ownConnection = transaction == null; RegTirada? result = null; try { if (ownConnection && cn.State == ConnectionState.Closed && cn is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); result = await cn.QuerySingleOrDefaultAsync(sql, new { FechaParam = fecha.Date, IdPublicacionParam = idPublicacion, IdPlantaParam = idPlanta }, transaction); } finally { if (ownConnection && cn.State == ConnectionState.Open && cn is System.Data.Common.DbConnection dbConnClose) await dbConnClose.CloseAsync(); if (ownConnection) (cn as IDisposable)?.Dispose(); } return result; } public async Task> GetByCriteriaAsync(DateTime? fecha, int? idPublicacion, int? idPlanta) { var sqlBuilder = new StringBuilder("SELECT Id_Registro AS IdRegistro, Ejemplares, Id_Publicacion AS IdPublicacion, Fecha, Id_Planta AS IdPlanta FROM dbo.bob_RegTiradas WHERE 1=1 "); var parameters = new DynamicParameters(); if (fecha.HasValue) { sqlBuilder.Append("AND Fecha = @FechaParam "); parameters.Add("FechaParam", fecha.Value.Date); } if (idPublicacion.HasValue) { sqlBuilder.Append("AND Id_Publicacion = @IdPublicacionParam "); parameters.Add("IdPublicacionParam", idPublicacion.Value); } if (idPlanta.HasValue) { sqlBuilder.Append("AND Id_Planta = @IdPlantaParam "); parameters.Add("IdPlantaParam", idPlanta.Value); } sqlBuilder.Append("ORDER BY Fecha DESC, Id_Publicacion;"); using var connection = _cf.CreateConnection(); return await connection.QueryAsync(sqlBuilder.ToString(), parameters); } public async Task CreateAsync(RegTirada nuevaTirada, int idUsuario, IDbTransaction transaction) { const string sqlInsert = @" INSERT INTO dbo.bob_RegTiradas (Ejemplares, Id_Publicacion, Fecha, Id_Planta) OUTPUT INSERTED.Id_Registro AS IdRegistro, INSERTED.Ejemplares, INSERTED.Id_Publicacion AS IdPublicacion, INSERTED.Fecha, INSERTED.Id_Planta AS IdPlanta VALUES (@Ejemplares, @IdPublicacion, @Fecha, @IdPlanta);"; var inserted = await transaction.Connection!.QuerySingleAsync(sqlInsert, nuevaTirada, transaction); const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await transaction.Connection!.ExecuteAsync(sqlHistorico, new { IdRegistroParam = inserted.IdRegistro, EjemplaresParam = inserted.Ejemplares, IdPublicacionParam = inserted.IdPublicacion, FechaParam = inserted.Fecha, IdPlantaParam = inserted.IdPlanta, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" }, transaction); return inserted; } public async Task DeleteAsync(int idRegistro, int idUsuario, IDbTransaction transaction) { var actual = await GetByIdAsync(idRegistro); // No necesita TX aquí ya que es solo para historial if (actual == null) throw new KeyNotFoundException("Registro de tirada no encontrado."); const string sqlDelete = "DELETE FROM dbo.bob_RegTiradas WHERE Id_Registro = @IdRegistroParam"; const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await transaction.Connection!.ExecuteAsync(sqlHistorico, new { IdRegistroParam = actual.IdRegistro, EjemplaresParam = actual.Ejemplares, IdPublicacionParam = actual.IdPublicacion, FechaParam = actual.Fecha, IdPlantaParam = actual.IdPlanta, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado" }, transaction); var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdRegistroParam = idRegistro }, transaction); return rowsAffected == 1; } public async Task DeleteByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta, int idUsuario, IDbTransaction transaction) { var tiradasAEliminar = await GetByCriteriaAsync(fecha.Date, idPublicacion, idPlanta); // Obtener antes de borrar para historial foreach (var actual in tiradasAEliminar) { const string sqlHistorico = @"INSERT INTO dbo.bob_RegTiradas_H (Id_Registro, Ejemplares, Id_Publicacion, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) VALUES (@IdRegistroParam, @EjemplaresParam, @IdPublicacionParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await transaction.Connection!.ExecuteAsync(sqlHistorico, new { IdRegistroParam = actual.IdRegistro, EjemplaresParam = actual.Ejemplares, IdPublicacionParam = actual.IdPublicacion, FechaParam = actual.Fecha, IdPlantaParam = actual.IdPlanta, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado (Por Fecha/Pub/Planta)" }, transaction); } const string sqlDelete = "DELETE FROM dbo.bob_RegTiradas WHERE Fecha = @FechaParam AND Id_Publicacion = @IdPublicacionParam AND Id_Planta = @IdPlantaParam"; var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { FechaParam = fecha.Date, IdPublicacionParam = idPublicacion, IdPlantaParam = idPlanta }, transaction); return rowsAffected > 0; // Devuelve true si se borró al menos una fila } public async Task> GetRegTiradasHistorialAsync( DateTime? fechaDesde, DateTime? fechaHasta, int? idUsuarioModifico, string? tipoModificacion, int? idRegistroOriginal, int? idPublicacionFiltro, int? idPlantaFiltro, DateTime? fechaTiradaFiltro) { using var connection = _cf.CreateConnection(); var sqlBuilder = new StringBuilder(@" SELECT h.Id_Registro, h.Ejemplares, h.Id_Publicacion, h.Fecha, h.Id_Planta, h.Id_Usuario, h.FechaMod, h.TipoMod, u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico, pub.Nombre AS NombrePublicacion, p.Nombre AS NombrePlanta FROM dbo.bob_RegTiradas_H h JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id JOIN dbo.dist_dtPublicaciones pub ON h.Id_Publicacion = pub.Id_Publicacion JOIN dbo.bob_dtPlantas p ON h.Id_Planta = p.Id_Planta 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 (idRegistroOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Registro = @IdRegistroOriginalParam"); parameters.Add("IdRegistroOriginalParam", idRegistroOriginal.Value); } if (idPublicacionFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionFiltroParam"); parameters.Add("IdPublicacionFiltroParam", idPublicacionFiltro.Value); } if (idPlantaFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Planta = @IdPlantaFiltroParam"); parameters.Add("IdPlantaFiltroParam", idPlantaFiltro.Value); } if (fechaTiradaFiltro.HasValue) { sqlBuilder.Append(" AND h.Fecha = @FechaTiradaFiltroParam"); parameters.Add("FechaTiradaFiltroParam", fechaTiradaFiltro.Value.Date); } sqlBuilder.Append(" ORDER BY h.FechaMod DESC;"); try { var result = await connection.QueryAsync( sqlBuilder.ToString(), (hist, userMod, pubNombre, plantaNombre) => (hist, userMod, pubNombre, plantaNombre), parameters, splitOn: "NombreUsuarioModifico,NombrePublicacion,NombrePlanta" ); return result; } catch (Exception ex) { _log.LogError(ex, "Error al obtener historial de Registro de Tiradas."); return Enumerable.Empty<(RegTiradaHistorico, string, string, string)>(); } } public async Task> GetRegSeccionesTiradaHistorialAsync( DateTime? fechaDesde, DateTime? fechaHasta, int? idUsuarioModifico, string? tipoModificacion, int? idTiradaOriginal, int? idPublicacionFiltro, int? idSeccionFiltro, int? idPlantaFiltro, DateTime? fechaTiradaFiltro) { using var connection = _cf.CreateConnection(); var sqlBuilder = new StringBuilder(@" SELECT h.Id_Tirada, h.Id_Publicacion, h.Id_Seccion, h.CantPag, h.Fecha, h.Id_Planta, h.Id_Usuario, h.FechaMod, h.TipoMod, u.Nombre + ' ' + u.Apellido AS NombreUsuarioModifico, pub.Nombre AS NombrePublicacion, sec.Nombre AS NombreSeccion, p.Nombre AS NombrePlanta FROM dbo.bob_RegPublicaciones_H h JOIN dbo.gral_Usuarios u ON h.Id_Usuario = u.Id JOIN dbo.dist_dtPublicaciones pub ON h.Id_Publicacion = pub.Id_Publicacion JOIN dbo.dist_dtPubliSecciones sec ON h.Id_Seccion = sec.Id_Seccion AND h.Id_Publicacion = sec.Id_Publicacion -- Crucial para el JOIN correcto de sección JOIN dbo.bob_dtPlantas p ON h.Id_Planta = p.Id_Planta 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 (idTiradaOriginal.HasValue) { sqlBuilder.Append(" AND h.Id_Tirada = @IdTiradaOriginalParam"); parameters.Add("IdTiradaOriginalParam", idTiradaOriginal.Value); } if (idPublicacionFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Publicacion = @IdPublicacionFiltroParam"); parameters.Add("IdPublicacionFiltroParam", idPublicacionFiltro.Value); } if (idSeccionFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Seccion = @IdSeccionFiltroParam"); parameters.Add("IdSeccionFiltroParam", idSeccionFiltro.Value); } if (idPlantaFiltro.HasValue) { sqlBuilder.Append(" AND h.Id_Planta = @IdPlantaFiltroParam"); parameters.Add("IdPlantaFiltroParam", idPlantaFiltro.Value); } if (fechaTiradaFiltro.HasValue) { sqlBuilder.Append(" AND h.Fecha = @FechaTiradaFiltroParam"); parameters.Add("FechaTiradaFiltroParam", fechaTiradaFiltro.Value.Date); } sqlBuilder.Append(" ORDER BY h.FechaMod DESC;"); try { var result = await connection.QueryAsync( sqlBuilder.ToString(), (hist, userMod, pubNombre, secNombre, plantaNombre) => (hist, userMod, pubNombre, secNombre, plantaNombre), parameters, splitOn: "NombreUsuarioModifico,NombrePublicacion,NombreSeccion,NombrePlanta" ); return result; } catch (Exception ex) { _log.LogError(ex, "Error al obtener historial de Secciones de Tirada."); return Enumerable.Empty<(RegPublicacionSeccionHistorico, string, string, string, string)>(); } } } public class RegPublicacionSeccionRepository : IRegPublicacionSeccionRepository { private readonly DbConnectionFactory _cf; private readonly ILogger _log; public RegPublicacionSeccionRepository(DbConnectionFactory cf, ILogger log) { _cf = cf; _log = log; } public async Task> GetByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta) { const string sql = @"SELECT Id_Tirada AS IdTirada, Id_Publicacion AS IdPublicacion, Id_Seccion AS IdSeccion, CantPag, Fecha, Id_Planta AS IdPlanta FROM dbo.bob_RegPublicaciones WHERE Fecha = @FechaParam AND Id_Publicacion = @IdPublicacionParam AND Id_Planta = @IdPlantaParam"; using var connection = _cf.CreateConnection(); return await connection.QueryAsync(sql, new { FechaParam = fecha.Date, IdPublicacionParam = idPublicacion, IdPlantaParam = idPlanta }); } public async Task CreateAsync(RegPublicacionSeccion nuevaSeccionTirada, int idUsuario, IDbTransaction transaction) { const string sqlInsert = @" INSERT INTO dbo.bob_RegPublicaciones (Id_Publicacion, Id_Seccion, CantPag, Fecha, Id_Planta) OUTPUT INSERTED.Id_Tirada AS IdTirada, INSERTED.Id_Publicacion AS IdPublicacion, INSERTED.Id_Seccion AS IdSeccion, INSERTED.CantPag, INSERTED.Fecha, INSERTED.Id_Planta AS IdPlanta VALUES (@IdPublicacion, @IdSeccion, @CantPag, @Fecha, @IdPlanta);"; var inserted = await transaction.Connection!.QuerySingleAsync(sqlInsert, nuevaSeccionTirada, transaction); const string sqlHistorico = @"INSERT INTO dbo.bob_RegPublicaciones_H (Id_Tirada, Id_Publicacion, Id_Seccion, CantPag, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) VALUES (@IdTiradaParam, @IdPublicacionParam, @IdSeccionParam, @CantPagParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await transaction.Connection!.ExecuteAsync(sqlHistorico, new { IdTiradaParam = inserted.IdTirada, IdPublicacionParam = inserted.IdPublicacion, IdSeccionParam = inserted.IdSeccion, CantPagParam = inserted.CantPag, FechaParam = inserted.Fecha, IdPlantaParam = inserted.IdPlanta, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Creado" }, transaction); return inserted; } public async Task DeleteByFechaPublicacionPlantaAsync(DateTime fecha, int idPublicacion, int idPlanta, int idUsuario, IDbTransaction transaction) { var seccionesAEliminar = await GetByFechaPublicacionPlantaAsync(fecha.Date, idPublicacion, idPlanta); // No necesita TX, es SELECT foreach (var actual in seccionesAEliminar) { const string sqlHistorico = @"INSERT INTO dbo.bob_RegPublicaciones_H (Id_Tirada, Id_Publicacion, Id_Seccion, CantPag, Fecha, Id_Planta, Id_Usuario, FechaMod, TipoMod) VALUES (@IdTiradaParam, @IdPublicacionParam, @IdSeccionParam, @CantPagParam, @FechaParam, @IdPlantaParam, @IdUsuarioParam, @FechaModParam, @TipoModParam);"; await transaction.Connection!.ExecuteAsync(sqlHistorico, new { IdTiradaParam = actual.IdTirada, IdPublicacionParam = actual.IdPublicacion, IdSeccionParam = actual.IdSeccion, CantPagParam = actual.CantPag, FechaParam = actual.Fecha, IdPlantaParam = actual.IdPlanta, IdUsuarioParam = idUsuario, FechaModParam = DateTime.Now, TipoModParam = "Eliminado (Por Fecha/Pub/Planta)" }, transaction); } const string sqlDelete = "DELETE FROM dbo.bob_RegPublicaciones WHERE Fecha = @FechaParam AND Id_Publicacion = @IdPublicacionParam AND Id_Planta = @IdPlantaParam"; var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { FechaParam = fecha.Date, IdPublicacionParam = idPublicacion, IdPlantaParam = idPlanta }, transaction); return rowsAffected >= 0; // Devuelve true incluso si no había nada que borrar (para que no falle la TX si es parte de una cadena) } } }