2025-05-23 15:47:39 -03:00
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 )
{
2025-06-03 13:45:20 -03:00
var actual = await GetByIdAsync ( idParte ) ; // Sigue siendo útil para el historial
2025-05-23 15:47:39 -03:00
if ( actual = = null ) throw new KeyNotFoundException ( "Registro E/S Canilla no encontrado para eliminar." ) ;
const string sqlDelete = "DELETE FROM dbo.dist_EntradasSalidasCanillas WHERE Id_Parte = @IdParteParam" ;
const string sqlHistorico = @ "
2025-06-03 13:45:20 -03:00
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 ) ; ";
2025-05-23 15:47:39 -03:00
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 ;
}
2025-06-09 19:37:07 -03:00
public async Task < IEnumerable < ( EntradaSalidaCanillaHistorico Historial , string NombreUsuarioModifico ) > > GetHistorialAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
int? idUsuarioModifico , string? tipoModificacion ,
int? idParteOriginal )
{
using var connection = _cf . CreateConnection ( ) ;
var sqlBuilder = new StringBuilder ( @ "
SELECT
h . Id_Parte , h . Id_Publicacion , h . Id_Canilla , h . Fecha ,
h . CantSalida , h . CantEntrada , h . Id_Precio , h . Id_Recargo , h . Id_PorcMon , h . Observacion ,
h . Id_Usuario , h . FechaMod , h . TipoMod ,
u . Nombre + ' ' + u . Apellido AS NombreUsuarioModifico
FROM dbo . dist_EntradasSalidasCanillas_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 ( idParteOriginal . HasValue ) { sqlBuilder . Append ( " AND h.Id_Parte = @IdParteOriginalParam" ) ; parameters . Add ( "IdParteOriginalParam" , idParteOriginal . Value ) ; }
sqlBuilder . Append ( " ORDER BY h.FechaMod DESC;" ) ;
try
{
var result = await connection . QueryAsync < EntradaSalidaCanillaHistorico , string , ( EntradaSalidaCanillaHistorico , string ) > (
sqlBuilder . ToString ( ) ,
( hist , userName ) = > ( hist , userName ) ,
parameters ,
splitOn : "NombreUsuarioModifico"
) ;
return result ;
}
catch ( Exception ex )
{
_log . LogError ( ex , "Error al obtener historial de Entradas/Salidas Canillitas." ) ;
return Enumerable . Empty < ( EntradaSalidaCanillaHistorico , string ) > ( ) ;
}
}
2025-05-23 15:47:39 -03:00
}
}