298 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			298 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Dapper;
 | |
| using GestionIntegral.Api.Models.Distribucion;
 | |
| using Microsoft.Extensions.Logging;
 | |
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Data;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using System.Threading.Tasks;
 | |
| 
 | |
| namespace GestionIntegral.Api.Data.Repositories.Distribucion
 | |
| {
 | |
|     public class EntradaSalidaCanillaRepository : IEntradaSalidaCanillaRepository
 | |
|     {
 | |
|         private readonly DbConnectionFactory _cf;
 | |
|         private readonly ILogger<EntradaSalidaCanillaRepository> _log;
 | |
| 
 | |
|         public EntradaSalidaCanillaRepository(DbConnectionFactory cf, ILogger<EntradaSalidaCanillaRepository> log)
 | |
|         {
 | |
|             _cf = cf;
 | |
|             _log = log;
 | |
|         }
 | |
| 
 | |
|         private string SelectQueryBase() => @"
 | |
|             SELECT 
 | |
|                 Id_Parte AS IdParte, Id_Publicacion AS IdPublicacion, Id_Canilla AS IdCanilla,
 | |
|                 Fecha, CantSalida, CantEntrada, Id_Precio AS IdPrecio, Id_Recargo AS IdRecargo,
 | |
|                 Id_PorcMon AS IdPorcMon, Observacion, Liquidado, FechaLiquidado, UserLiq
 | |
|             FROM dbo.dist_EntradasSalidasCanillas";
 | |
| 
 | |
|         public async Task<IEnumerable<EntradaSalidaCanilla>> GetAllAsync(
 | |
|             DateTime? fechaDesde, DateTime? fechaHasta,
 | |
|             int? idPublicacion, int? idCanilla, bool? liquidados)
 | |
|         {
 | |
|             var sqlBuilder = new StringBuilder(SelectQueryBase());
 | |
|             sqlBuilder.Append(" WHERE 1=1");
 | |
|             var parameters = new DynamicParameters();
 | |
| 
 | |
|             if (fechaDesde.HasValue) { sqlBuilder.Append(" AND Fecha >= @FechaDesdeParam"); parameters.Add("FechaDesdeParam", fechaDesde.Value.Date); }
 | |
|             if (fechaHasta.HasValue) { sqlBuilder.Append(" AND Fecha <= @FechaHastaParam"); parameters.Add("FechaHastaParam", fechaHasta.Value.Date); }
 | |
|             if (idPublicacion.HasValue) { sqlBuilder.Append(" AND Id_Publicacion = @IdPublicacionParam"); parameters.Add("IdPublicacionParam", idPublicacion.Value); }
 | |
|             if (idCanilla.HasValue) { sqlBuilder.Append(" AND Id_Canilla = @IdCanillaParam"); parameters.Add("IdCanillaParam", idCanilla.Value); }
 | |
|             if (liquidados.HasValue) { sqlBuilder.Append(" AND Liquidado = @LiquidadoParam"); parameters.Add("LiquidadoParam", liquidados.Value); }
 | |
| 
 | |
|             sqlBuilder.Append(" ORDER BY Fecha DESC, Id_Canilla, Id_Publicacion, Id_Parte DESC;");
 | |
| 
 | |
|             try
 | |
|             {
 | |
|                 using var connection = _cf.CreateConnection();
 | |
|                 return await connection.QueryAsync<EntradaSalidaCanilla>(sqlBuilder.ToString(), parameters);
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _log.LogError(ex, "Error al obtener Entradas/Salidas de Canillitas.");
 | |
|                 return Enumerable.Empty<EntradaSalidaCanilla>();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task<EntradaSalidaCanilla?> GetByIdAsync(int idParte)
 | |
|         {
 | |
|             var sql = SelectQueryBase() + " WHERE Id_Parte = @IdParteParam";
 | |
|             try
 | |
|             {
 | |
|                 using var connection = _cf.CreateConnection();
 | |
|                 return await connection.QuerySingleOrDefaultAsync<EntradaSalidaCanilla>(sql, new { IdParteParam = idParte });
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _log.LogError(ex, "Error al obtener EntradaSalidaCanilla por ID: {IdParte}", idParte);
 | |
|                 return null;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task<IEnumerable<EntradaSalidaCanilla>> GetByIdsAsync(IEnumerable<int> idsPartes, IDbTransaction? transaction = null)
 | |
|         {
 | |
|             if (idsPartes == null || !idsPartes.Any()) return Enumerable.Empty<EntradaSalidaCanilla>();
 | |
|             var sql = SelectQueryBase() + " WHERE Id_Parte IN @IdsPartesParam";
 | |
| 
 | |
|             var cn = transaction?.Connection ?? _cf.CreateConnection();
 | |
|             bool ownConnection = transaction == null;
 | |
|             IEnumerable<EntradaSalidaCanilla> result = Enumerable.Empty<EntradaSalidaCanilla>();
 | |
|             try
 | |
|             {
 | |
|                 if (ownConnection && cn.State == ConnectionState.Closed && cn is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync();
 | |
|                 result = await cn.QueryAsync<EntradaSalidaCanilla>(sql, new { IdsPartesParam = idsPartes }, 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<bool> ExistsByPublicacionCanillaFechaAsync(int idPublicacion, int idCanilla, DateTime fecha, IDbTransaction? transaction = null, int? excludeIdParte = null)
 | |
|         {
 | |
|             var sqlBuilder = new StringBuilder("SELECT COUNT(1) FROM dbo.dist_EntradasSalidasCanillas WHERE Id_Publicacion = @IdPubParam AND Id_Canilla = @IdCanParam AND Fecha = @FechaParam");
 | |
|             var parameters = new DynamicParameters();
 | |
|             parameters.Add("IdPubParam", idPublicacion);
 | |
|             parameters.Add("IdCanParam", idCanilla);
 | |
|             parameters.Add("FechaParam", fecha.Date);
 | |
| 
 | |
|             if (excludeIdParte.HasValue)
 | |
|             {
 | |
|                 sqlBuilder.Append(" AND Id_Parte != @ExcludeIdParteParam");
 | |
|                 parameters.Add("ExcludeIdParteParam", excludeIdParte.Value);
 | |
|             }
 | |
| 
 | |
|             var connection = transaction?.Connection ?? _cf.CreateConnection();
 | |
|             bool ownConnection = transaction == null;
 | |
|             bool result = false;
 | |
|             try
 | |
|             {
 | |
|                 if (ownConnection && connection.State == ConnectionState.Closed && connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync();
 | |
| 
 | |
|                 result = await connection.ExecuteScalarAsync<bool>(sqlBuilder.ToString(), parameters, transaction);
 | |
| 
 | |
|             }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 _log.LogError(ex, "Error en ExistsByPublicacionCanillaFechaAsync.");
 | |
|                 return true; // Asumir que existe en caso de error
 | |
|             }
 | |
|             finally
 | |
|             {
 | |
|                 if (ownConnection && connection.State == ConnectionState.Open && connection is System.Data.Common.DbConnection dbConnClose) await dbConnClose.CloseAsync();
 | |
|                 if (ownConnection) (connection as IDisposable)?.Dispose();
 | |
|             }
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public async Task<EntradaSalidaCanilla?> CreateAsync(EntradaSalidaCanilla nuevoES, int idUsuario, IDbTransaction transaction)
 | |
|         {
 | |
|             const string sqlInsert = @"
 | |
|                 INSERT INTO dbo.dist_EntradasSalidasCanillas 
 | |
|                     (Id_Publicacion, Id_Canilla, Fecha, CantSalida, CantEntrada, Id_Precio, Id_Recargo, Id_PorcMon, Observacion, Liquidado, FechaLiquidado, UserLiq)
 | |
|                 OUTPUT INSERTED.Id_Parte AS IdParte, INSERTED.Id_Publicacion AS IdPublicacion, INSERTED.Id_Canilla AS IdCanilla, INSERTED.Fecha, 
 | |
|                        INSERTED.CantSalida, INSERTED.CantEntrada, INSERTED.Id_Precio AS IdPrecio, INSERTED.Id_Recargo AS IdRecargo, 
 | |
|                        INSERTED.Id_PorcMon AS IdPorcMon, INSERTED.Observacion, INSERTED.Liquidado, INSERTED.FechaLiquidado, INSERTED.UserLiq
 | |
|                 VALUES (@IdPublicacion, @IdCanilla, @Fecha, @CantSalida, @CantEntrada, @IdPrecio, @IdRecargo, @IdPorcMon, @Observacion, @Liquidado, @FechaLiquidado, @UserLiq);";
 | |
| 
 | |
|             var inserted = await transaction.Connection!.QuerySingleAsync<EntradaSalidaCanilla>(sqlInsert, nuevoES, transaction);
 | |
|             if (inserted == null || inserted.IdParte == 0) throw new DataException("Error al crear E/S Canilla o ID no generado.");
 | |
| 
 | |
|             const string sqlHistorico = @"
 | |
|                 INSERT INTO dbo.dist_EntradasSalidasCanillas_H 
 | |
|                     (Id_Parte, Id_Publicacion, Id_Canilla, Fecha, CantSalida, CantEntrada, Id_Precio, Id_Recargo, Id_PorcMon, Observacion, Id_Usuario, FechaMod, TipoMod)
 | |
|                 VALUES (@IdParteHist, @IdPubHist, @IdCanillaHist, @FechaHist, @CantSalidaHist, @CantEntradaHist, @IdPrecioHist, @IdRecargoHist, @IdPorcMonHist, @ObsHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
 | |
|             // Liquidado, FechaLiquidado, UserLiq no van al historial de creación, sino al de liquidación.
 | |
| 
 | |
|             await transaction.Connection!.ExecuteAsync(sqlHistorico, new
 | |
|             {
 | |
|                 IdParteHist = inserted.IdParte,
 | |
|                 IdPubHist = inserted.IdPublicacion,
 | |
|                 IdCanillaHist = inserted.IdCanilla,
 | |
|                 FechaHist = inserted.Fecha,
 | |
|                 CantSalidaHist = inserted.CantSalida,
 | |
|                 CantEntradaHist = inserted.CantEntrada,
 | |
|                 IdPrecioHist = inserted.IdPrecio,
 | |
|                 IdRecargoHist = inserted.IdRecargo,
 | |
|                 IdPorcMonHist = inserted.IdPorcMon,
 | |
|                 ObsHist = inserted.Observacion,
 | |
|                 IdUsuarioHist = idUsuario,
 | |
|                 FechaModHist = DateTime.Now,
 | |
|                 TipoModHist = "Creada"
 | |
|             }, transaction);
 | |
|             return inserted;
 | |
|         }
 | |
| 
 | |
|         public async Task<bool> UpdateAsync(EntradaSalidaCanilla esAActualizar, int idUsuario, IDbTransaction transaction, string tipoMod = "Actualizada")
 | |
|         {
 | |
|             var actual = await transaction.Connection!.QuerySingleOrDefaultAsync<EntradaSalidaCanilla>(SelectQueryBase() + " WHERE Id_Parte = @IdParteParam",
 | |
|                 new { IdParteParam = esAActualizar.IdParte }, transaction);
 | |
|             if (actual == null) throw new KeyNotFoundException("Registro E/S Canilla no encontrado.");
 | |
| 
 | |
|             const string sqlUpdate = @"
 | |
|                 UPDATE dbo.dist_EntradasSalidasCanillas SET
 | |
|                     CantSalida = @CantSalida, CantEntrada = @CantEntrada, Observacion = @Observacion,
 | |
|                     Liquidado = @Liquidado, FechaLiquidado = @FechaLiquidado, UserLiq = @UserLiq,
 | |
|                     Id_Precio = @IdPrecio, Id_Recargo = @IdRecargo, Id_PorcMon = @IdPorcMon 
 | |
|                     -- No se permite cambiar Publicacion, Canilla, Fecha directamente aquí.
 | |
|                 WHERE Id_Parte = @IdParte;";
 | |
| 
 | |
|             const string sqlHistorico = @"
 | |
|                 INSERT INTO dbo.dist_EntradasSalidasCanillas_H 
 | |
|                     (Id_Parte, Id_Publicacion, Id_Canilla, Fecha, CantSalida, CantEntrada, Id_Precio, Id_Recargo, Id_PorcMon, Observacion, Id_Usuario, FechaMod, TipoMod)
 | |
|                 VALUES (@IdParteHist, @IdPubHist, @IdCanillaHist, @FechaHist, @CantSalidaHist, @CantEntradaHist, @IdPrecioHist, @IdRecargoHist, @IdPorcMonHist, @ObsHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
 | |
| 
 | |
|             await transaction.Connection!.ExecuteAsync(sqlHistorico, new
 | |
|             {
 | |
|                 IdParteHist = actual.IdParte,
 | |
|                 IdPubHist = actual.IdPublicacion,
 | |
|                 IdCanillaHist = actual.IdCanilla,
 | |
|                 FechaHist = actual.Fecha,
 | |
|                 CantSalidaHist = actual.CantSalida,
 | |
|                 CantEntradaHist = actual.CantEntrada,
 | |
|                 IdPrecioHist = actual.IdPrecio,
 | |
|                 IdRecargoHist = actual.IdRecargo,
 | |
|                 IdPorcMonHist = actual.IdPorcMon,
 | |
|                 ObsHist = actual.Observacion, // Valores ANTERIORES
 | |
|                 IdUsuarioHist = idUsuario,
 | |
|                 FechaModHist = DateTime.Now,
 | |
|                 TipoModHist = tipoMod
 | |
|             }, transaction);
 | |
| 
 | |
|             var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlUpdate, esAActualizar, transaction);
 | |
|             return rowsAffected == 1;
 | |
|         }
 | |
| 
 | |
|         public async Task<bool> LiquidarAsync(IEnumerable<int> idsPartes, DateTime fechaLiquidacion, int idUsuarioLiquidador, IDbTransaction transaction)
 | |
|         {
 | |
|             // Primero, obtener los registros actuales para el historial
 | |
|             var movimientosALiquidar = await GetByIdsAsync(idsPartes, transaction);
 | |
|             if (!movimientosALiquidar.Any() || movimientosALiquidar.Count() != idsPartes.Distinct().Count())
 | |
|             {
 | |
|                 _log.LogWarning("Intento de liquidar IdsPartes no encontrados o inconsistentes.");
 | |
|                 return false; // O lanzar excepción
 | |
|             }
 | |
| 
 | |
|             const string sqlUpdate = @"
 | |
|                 UPDATE dbo.dist_EntradasSalidasCanillas SET
 | |
|                     Liquidado = 1, FechaLiquidado = @FechaLiquidacionParam, UserLiq = @UserLiqParam
 | |
|                 WHERE Id_Parte = @IdParteParam AND Liquidado = 0;"; // Solo liquidar los no liquidados
 | |
| 
 | |
|             const string sqlHistorico = @"
 | |
|                  INSERT INTO dbo.dist_EntradasSalidasCanillas_H 
 | |
|                     (Id_Parte, Id_Publicacion, Id_Canilla, Fecha, CantSalida, CantEntrada, Id_Precio, Id_Recargo, Id_PorcMon, Observacion, Id_Usuario, FechaMod, TipoMod)
 | |
|                 VALUES (@IdParteHist, @IdPubHist, @IdCanillaHist, @FechaHist, @CantSalidaHist, @CantEntradaHist, @IdPrecioHist, @IdRecargoHist, @IdPorcMonHist, @ObsHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
 | |
| 
 | |
|             int totalRowsAffected = 0;
 | |
|             foreach (var mov in movimientosALiquidar)
 | |
|             {
 | |
|                 if (mov.Liquidado) continue; // Ya estaba liquidado, no hacer nada ni registrar historial
 | |
| 
 | |
|                 await transaction.Connection!.ExecuteAsync(sqlHistorico, new
 | |
|                 {
 | |
|                     IdParteHist = mov.IdParte,
 | |
|                     IdPubHist = mov.IdPublicacion,
 | |
|                     IdCanillaHist = mov.IdCanilla,
 | |
|                     FechaHist = mov.Fecha,
 | |
|                     CantSalidaHist = mov.CantSalida,
 | |
|                     CantEntradaHist = mov.CantEntrada,
 | |
|                     IdPrecioHist = mov.IdPrecio,
 | |
|                     IdRecargoHist = mov.IdRecargo,
 | |
|                     IdPorcMonHist = mov.IdPorcMon,
 | |
|                     ObsHist = mov.Observacion,
 | |
|                     IdUsuarioHist = idUsuarioLiquidador,
 | |
|                     FechaModHist = DateTime.Now,
 | |
|                     TipoModHist = "Liquidada"
 | |
|                 }, transaction);
 | |
| 
 | |
|                 var rows = await transaction.Connection!.ExecuteAsync(sqlUpdate,
 | |
|                     new { FechaLiquidacionParam = fechaLiquidacion.Date, UserLiqParam = idUsuarioLiquidador, IdParteParam = mov.IdParte },
 | |
|                     transaction);
 | |
|                 totalRowsAffected += rows;
 | |
|             }
 | |
|             // Se considera éxito si al menos una fila fue afectada (o si todas ya estaban liquidadas y no hubo errores)
 | |
|             // Si se pasaron IDs que no existen, GetByIdsAsync ya devolvería menos elementos.
 | |
|             return totalRowsAffected >= 0;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         public async Task<bool> DeleteAsync(int idParte, int idUsuario, IDbTransaction transaction)
 | |
|         {
 | |
|             var actual = await GetByIdAsync(idParte); // No necesita TX, solo para el historial
 | |
|             if (actual == null) throw new KeyNotFoundException("Registro E/S Canilla no encontrado para eliminar.");
 | |
|             if (actual.Liquidado) throw new InvalidOperationException("No se puede eliminar un movimiento liquidado.");
 | |
| 
 | |
| 
 | |
|             const string sqlDelete = "DELETE FROM dbo.dist_EntradasSalidasCanillas WHERE Id_Parte = @IdParteParam";
 | |
|             const string sqlHistorico = @"
 | |
|                  INSERT INTO dbo.dist_EntradasSalidasCanillas_H 
 | |
|                     (Id_Parte, Id_Publicacion, Id_Canilla, Fecha, CantSalida, CantEntrada, Id_Precio, Id_Recargo, Id_PorcMon, Observacion, Id_Usuario, FechaMod, TipoMod)
 | |
|                 VALUES (@IdParteHist, @IdPubHist, @IdCanillaHist, @FechaHist, @CantSalidaHist, @CantEntradaHist, @IdPrecioHist, @IdRecargoHist, @IdPorcMonHist, @ObsHist, @IdUsuarioHist, @FechaModHist, @TipoModHist);";
 | |
| 
 | |
|             await transaction.Connection!.ExecuteAsync(sqlHistorico, new
 | |
|             {
 | |
|                 IdParteHist = actual.IdParte,
 | |
|                 IdPubHist = actual.IdPublicacion,
 | |
|                 IdCanillaHist = actual.IdCanilla,
 | |
|                 FechaHist = actual.Fecha,
 | |
|                 CantSalidaHist = actual.CantSalida,
 | |
|                 CantEntradaHist = actual.CantEntrada,
 | |
|                 IdPrecioHist = actual.IdPrecio,
 | |
|                 IdRecargoHist = actual.IdRecargo,
 | |
|                 IdPorcMonHist = actual.IdPorcMon,
 | |
|                 ObsHist = actual.Observacion,
 | |
|                 IdUsuarioHist = idUsuario,
 | |
|                 FechaModHist = DateTime.Now,
 | |
|                 TipoModHist = "Eliminada"
 | |
|             }, transaction);
 | |
| 
 | |
|             var rowsAffected = await transaction.Connection!.ExecuteAsync(sqlDelete, new { IdParteParam = idParte }, transaction);
 | |
|             return rowsAffected == 1;
 | |
|         }
 | |
|     }
 | |
| } |