2025-05-23 15:47:39 -03:00
using GestionIntegral.Api.Data ;
using GestionIntegral.Api.Data.Repositories.Distribucion ;
using GestionIntegral.Api.Data.Repositories.Usuarios ;
using GestionIntegral.Api.Dtos.Distribucion ;
using GestionIntegral.Api.Models.Distribucion ;
using Microsoft.Extensions.Logging ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Globalization ;
using System.Linq ;
using System.Threading.Tasks ;
using System.Security.Claims ;
2025-06-09 19:37:07 -03:00
using GestionIntegral.Api.Dtos.Auditoria ;
2025-05-23 15:47:39 -03:00
namespace GestionIntegral.Api.Services.Distribucion
{
public class EntradaSalidaCanillaService : IEntradaSalidaCanillaService
{
private readonly IEntradaSalidaCanillaRepository _esCanillaRepository ;
private readonly IPublicacionRepository _publicacionRepository ;
private readonly ICanillaRepository _canillaRepository ;
private readonly IPrecioRepository _precioRepository ;
private readonly IRecargoZonaRepository _recargoZonaRepository ;
private readonly IPorcMonCanillaRepository _porcMonCanillaRepository ;
private readonly IUsuarioRepository _usuarioRepository ;
private readonly DbConnectionFactory _connectionFactory ;
private readonly ILogger < EntradaSalidaCanillaService > _logger ;
public EntradaSalidaCanillaService (
IEntradaSalidaCanillaRepository esCanillaRepository ,
IPublicacionRepository publicacionRepository ,
ICanillaRepository canillaRepository ,
IPrecioRepository precioRepository ,
IRecargoZonaRepository recargoZonaRepository ,
IPorcMonCanillaRepository porcMonCanillaRepository ,
IUsuarioRepository usuarioRepository ,
DbConnectionFactory connectionFactory ,
ILogger < EntradaSalidaCanillaService > logger )
{
_esCanillaRepository = esCanillaRepository ;
_publicacionRepository = publicacionRepository ;
_canillaRepository = canillaRepository ;
_precioRepository = precioRepository ;
_recargoZonaRepository = recargoZonaRepository ;
_porcMonCanillaRepository = porcMonCanillaRepository ;
_usuarioRepository = usuarioRepository ;
_connectionFactory = connectionFactory ;
_logger = logger ;
}
private async Task < EntradaSalidaCanillaDto ? > MapToDto ( EntradaSalidaCanilla ? es )
{
if ( es = = null ) return null ;
var publicacionDataResult = await _publicacionRepository . GetByIdAsync ( es . IdPublicacion ) ;
var canillaDataResult = await _canillaRepository . GetByIdAsync ( es . IdCanilla ) ; // Devuelve tupla
Publicacion ? publicacionEntity = publicacionDataResult . Publicacion ; // Componente nullable de la tupla
Canilla ? canillaEntity = canillaDataResult . Canilla ; // Componente nullable de la tupla
var usuarioLiq = es . UserLiq . HasValue ? await _usuarioRepository . GetByIdAsync ( es . UserLiq . Value ) : null ;
decimal montoARendir = await CalcularMontoARendir ( es , canillaEntity , publicacionEntity ) ;
return new EntradaSalidaCanillaDto
{
IdParte = es . IdParte ,
IdPublicacion = es . IdPublicacion ,
NombrePublicacion = publicacionEntity ? . Nombre ? ? "Pub. Desconocida" ,
IdCanilla = es . IdCanilla ,
NomApeCanilla = canillaEntity ? . NomApe ? ? "Can. Desconocido" ,
CanillaEsAccionista = canillaEntity ? . Accionista ? ? false ,
Fecha = es . Fecha . ToString ( "yyyy-MM-dd" ) ,
CantSalida = es . CantSalida ,
CantEntrada = es . CantEntrada ,
Vendidos = es . CantSalida - es . CantEntrada ,
Observacion = es . Observacion ,
Liquidado = es . Liquidado ,
FechaLiquidado = es . FechaLiquidado ? . ToString ( "yyyy-MM-dd" ) ,
UserLiq = es . UserLiq ,
NombreUserLiq = usuarioLiq ! = null ? $"{usuarioLiq.Nombre} {usuarioLiq.Apellido}" : null ,
MontoARendir = montoARendir ,
PrecioUnitarioAplicado = ( await _precioRepository . GetByIdAsync ( es . IdPrecio ) ) ? . Lunes ? ? 0 ,
RecargoAplicado = es . IdRecargo > 0 ? ( await _recargoZonaRepository . GetByIdAsync ( es . IdRecargo ) ) ? . Valor ? ? 0 : 0 ,
PorcentajeOMontoCanillaAplicado = es . IdPorcMon > 0 ? ( await _porcMonCanillaRepository . GetByIdAsync ( es . IdPorcMon ) ) ? . PorcMon ? ? 0 : 0 ,
EsPorcentajeCanilla = es . IdPorcMon > 0 ? ( await _porcMonCanillaRepository . GetByIdAsync ( es . IdPorcMon ) ) ? . EsPorcentaje ? ? false : false
} ;
}
private async Task < decimal > CalcularMontoARendir ( EntradaSalidaCanilla es , Canilla ? canilla , Publicacion ? publicacion ) // Acepta nullable Canilla y Publicacion
{
if ( es . CantSalida - es . CantEntrada < = 0 ) return 0 ;
var precioConfig = await _precioRepository . GetByIdAsync ( es . IdPrecio ) ;
if ( precioConfig = = null )
{
_logger . LogError ( "Configuración de precio ID {IdPrecio} no encontrada para movimiento ID {IdParte}." , es . IdPrecio , es . IdParte ) ;
throw new InvalidOperationException ( $"Configuración de precio ID {es.IdPrecio} no encontrada para el movimiento." ) ;
}
decimal precioDia = 0 ;
DayOfWeek diaSemana = es . Fecha . DayOfWeek ;
switch ( diaSemana )
{
case DayOfWeek . Monday : precioDia = precioConfig . Lunes ? ? 0 ; break ;
case DayOfWeek . Tuesday : precioDia = precioConfig . Martes ? ? 0 ; break ;
case DayOfWeek . Wednesday : precioDia = precioConfig . Miercoles ? ? 0 ; break ;
case DayOfWeek . Thursday : precioDia = precioConfig . Jueves ? ? 0 ; break ;
case DayOfWeek . Friday : precioDia = precioConfig . Viernes ? ? 0 ; break ;
case DayOfWeek . Saturday : precioDia = precioConfig . Sabado ? ? 0 ; break ;
case DayOfWeek . Sunday : precioDia = precioConfig . Domingo ? ? 0 ; break ;
}
decimal valorRecargo = 0 ;
if ( es . IdRecargo > 0 )
{
var recargoConfig = await _recargoZonaRepository . GetByIdAsync ( es . IdRecargo ) ;
if ( recargoConfig ! = null ) valorRecargo = recargoConfig . Valor ;
}
decimal precioFinalUnitario = precioDia + valorRecargo ;
int cantidadVendida = es . CantSalida - es . CantEntrada ;
if ( canilla ! = null & & canilla . Accionista & & es . IdPorcMon > 0 ) // Check null para canilla
{
var porcMonConfig = await _porcMonCanillaRepository . GetByIdAsync ( es . IdPorcMon ) ;
if ( porcMonConfig ! = null )
{
if ( porcMonConfig . EsPorcentaje )
{
return Math . Round ( ( precioFinalUnitario * cantidadVendida * porcMonConfig . PorcMon ) / 100 , 2 ) ;
}
else
{
return Math . Round ( cantidadVendida * porcMonConfig . PorcMon , 2 ) ;
}
}
}
return Math . Round ( precioFinalUnitario * cantidadVendida , 2 ) ;
}
public async Task < IEnumerable < EntradaSalidaCanillaDto > > ObtenerTodosAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
int? idPublicacion , int? idCanilla , bool? liquidados , bool? incluirNoLiquidados )
{
bool? filtroLiquidadoFinal = null ;
if ( liquidados . HasValue )
{
filtroLiquidadoFinal = liquidados . Value ;
}
else
{
if ( incluirNoLiquidados . HasValue & & ! incluirNoLiquidados . Value )
{
filtroLiquidadoFinal = true ;
}
}
var movimientos = await _esCanillaRepository . GetAllAsync ( fechaDesde , fechaHasta , idPublicacion , idCanilla , filtroLiquidadoFinal ) ;
var dtos = new List < EntradaSalidaCanillaDto > ( ) ;
foreach ( var mov in movimientos )
{
var dto = await MapToDto ( mov ) ;
if ( dto ! = null ) dtos . Add ( dto ) ;
}
return dtos ;
}
public async Task < EntradaSalidaCanillaDto ? > ObtenerPorIdAsync ( int idParte )
{
var movimiento = await _esCanillaRepository . GetByIdAsync ( idParte ) ;
return await MapToDto ( movimiento ) ;
}
public async Task < ( bool Exito , string? Error ) > ActualizarMovimientoAsync ( int idParte , UpdateEntradaSalidaCanillaDto updateDto , int idUsuario )
{
using var connection = _connectionFactory . CreateConnection ( ) ;
if ( connection is System . Data . Common . DbConnection dbConnOpen & & connection . State = = ConnectionState . Closed ) await dbConnOpen . OpenAsync ( ) ; else if ( connection . State = = ConnectionState . Closed ) connection . Open ( ) ;
using var transaction = connection . BeginTransaction ( ) ;
try
{
var esExistente = await _esCanillaRepository . GetByIdAsync ( idParte ) ;
if ( esExistente = = null ) return ( false , "Movimiento no encontrado." ) ;
if ( esExistente . Liquidado ) return ( false , "No se puede modificar un movimiento ya liquidado." ) ;
esExistente . CantSalida = updateDto . CantSalida ;
esExistente . CantEntrada = updateDto . CantEntrada ;
esExistente . Observacion = updateDto . Observacion ;
var actualizado = await _esCanillaRepository . UpdateAsync ( esExistente , idUsuario , transaction ) ;
if ( ! actualizado ) throw new DataException ( "Error al actualizar el movimiento." ) ;
transaction . Commit ( ) ;
_logger . LogInformation ( "Movimiento Canillita ID {Id} actualizado por Usuario ID {UserId}." , idParte , idUsuario ) ;
return ( true , null ) ;
}
catch ( KeyNotFoundException ) { if ( transaction . Connection ! = null ) try { transaction . Rollback ( ) ; } catch { } return ( false , "Movimiento no encontrado." ) ; }
catch ( Exception ex )
{
if ( transaction . Connection ! = null ) try { transaction . Rollback ( ) ; } catch { }
_logger . LogError ( ex , "Error ActualizarMovimientoAsync Canillita ID: {Id}" , idParte ) ;
return ( false , $"Error interno: {ex.Message}" ) ;
}
finally
{
if ( connection ? . State = = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConnClose ) await dbConnClose . CloseAsync ( ) ; else connection . Close ( ) ;
}
}
}
public async Task < ( bool Exito , string? Error ) > EliminarMovimientoAsync ( int idParte , int idUsuario , ClaimsPrincipal userPrincipal )
{
// Helper interno para verificar permisos desde el ClaimsPrincipal proporcionado
bool TienePermisoEspecifico ( string codAcc ) = > userPrincipal . IsInRole ( "SuperAdmin" ) | | userPrincipal . HasClaim ( c = > c . Type = = "permission" & & c . Value = = codAcc ) ;
using var connection = _connectionFactory . CreateConnection ( ) ;
IDbTransaction ? transaction = null ;
try
{
if ( connection is System . Data . Common . DbConnection dbConnOpen & & connection . State = = ConnectionState . Closed ) await dbConnOpen . OpenAsync ( ) ;
else if ( connection . State = = ConnectionState . Closed ) connection . Open ( ) ;
2025-06-03 13:45:20 -03:00
2025-05-23 15:47:39 -03:00
transaction = connection . BeginTransaction ( ) ;
2025-06-03 13:45:20 -03:00
var esExistente = await _esCanillaRepository . GetByIdAsync ( idParte ) ; // Obtener el estado actual
2025-05-23 15:47:39 -03:00
if ( esExistente = = null )
{
if ( transaction ? . Connection ! = null ) transaction . Rollback ( ) ;
return ( false , "Movimiento no encontrado." ) ;
}
if ( esExistente . Liquidado )
{
2025-06-03 13:45:20 -03:00
if ( ! TienePermisoEspecifico ( "MC006" ) ) // <--- AQUÍ ESTÁ LA VERIFICACIÓN
2025-05-23 15:47:39 -03:00
{
if ( transaction ? . Connection ! = null ) transaction . Rollback ( ) ;
return ( false , "No tiene permiso para eliminar movimientos ya liquidados. Se requiere permiso especial (MC006) o ser SuperAdmin." ) ;
}
_logger . LogWarning ( "Usuario ID {IdUsuario} está eliminando un movimiento LIQUIDADO (IDParte: {IdParte}). Permiso MC006 verificado." , idUsuario , idParte ) ;
}
2025-06-03 13:45:20 -03:00
// Si no está liquidado, el permiso MC004 ya fue verificado en el controlador (o debería serlo).
2025-05-23 15:47:39 -03:00
2025-06-03 13:45:20 -03:00
var eliminado = await _esCanillaRepository . DeleteAsync ( idParte , idUsuario , transaction ) ; // Ahora esto no lanzará la excepción por liquidado
2025-05-23 15:47:39 -03:00
if ( ! eliminado )
{
// No es necesario hacer rollback aquí si DeleteAsync lanza una excepción,
// ya que el bloque catch lo manejará. Si DeleteAsync devuelve false sin lanzar,
// entonces sí sería necesario un rollback.
if ( transaction ? . Connection ! = null ) transaction . Rollback ( ) ;
throw new DataException ( "Error al eliminar el movimiento desde el repositorio." ) ;
}
if ( transaction ? . Connection ! = null ) transaction . Commit ( ) ;
_logger . LogInformation ( "Movimiento Canillita ID {IdParte} eliminado por Usuario ID {IdUsuario}." , idParte , idUsuario ) ;
return ( true , null ) ;
}
2025-06-03 13:45:20 -03:00
catch ( KeyNotFoundException )
{
2025-05-23 15:47:39 -03:00
if ( transaction ? . Connection ! = null ) try { transaction . Rollback ( ) ; } catch ( Exception exR ) { _logger . LogError ( exR , "Rollback fallido KeyNotFoundException." ) ; }
2025-06-03 13:45:20 -03:00
return ( false , "Movimiento no encontrado." ) ;
2025-05-23 15:47:39 -03:00
}
catch ( Exception ex )
{
if ( transaction ? . Connection ! = null ) { try { transaction . Rollback ( ) ; } catch ( Exception exRollback ) { _logger . LogError ( exRollback , "Error durante rollback de transacción." ) ; } }
_logger . LogError ( ex , "Error EliminarMovimientoAsync Canillita ID: {IdParte}" , idParte ) ;
return ( false , $"Error interno: {ex.Message}" ) ;
}
finally
{
if ( transaction ! = null ) transaction . Dispose ( ) ;
if ( connection ? . State = = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConnClose ) await dbConnClose . CloseAsync ( ) ; else connection . Close ( ) ;
}
}
}
public async Task < ( bool Exito , string? Error ) > LiquidarMovimientosAsync ( LiquidarMovimientosCanillaRequestDto liquidarDto , int idUsuarioLiquidador )
{
if ( liquidarDto . IdsPartesALiquidar = = null | | ! liquidarDto . IdsPartesALiquidar . Any ( ) )
return ( false , "No se especificaron movimientos para liquidar." ) ;
using var connection = _connectionFactory . CreateConnection ( ) ;
if ( connection is System . Data . Common . DbConnection dbConnOpen & & connection . State = = ConnectionState . Closed ) await dbConnOpen . OpenAsync ( ) ; else if ( connection . State = = ConnectionState . Closed ) connection . Open ( ) ;
using var transaction = connection . BeginTransaction ( ) ;
try
{
bool liquidacionExitosa = await _esCanillaRepository . LiquidarAsync ( liquidarDto . IdsPartesALiquidar , liquidarDto . FechaLiquidacion . Date , idUsuarioLiquidador , transaction ) ;
if ( ! liquidacionExitosa )
{
_logger . LogWarning ( "Liquidación de movimientos de canillita pudo no haber afectado a todos los IDs solicitados. IDs: {Ids}" , string . Join ( "," , liquidarDto . IdsPartesALiquidar ) ) ;
}
if ( transaction . Connection ! = null ) transaction . Commit ( ) ;
_logger . LogInformation ( "Movimientos de Canillita liquidados. Ids: {Ids} por Usuario ID {UserId}." , string . Join ( "," , liquidarDto . IdsPartesALiquidar ) , idUsuarioLiquidador ) ;
return ( true , null ) ;
}
catch ( Exception ex )
{
if ( transaction . Connection ! = null ) { try { transaction . Rollback ( ) ; } catch ( Exception exRollback ) { _logger . LogError ( exRollback , "Error durante rollback de transacción." ) ; } }
_logger . LogError ( ex , "Error al liquidar movimientos de canillita." ) ;
return ( false , $"Error interno al liquidar movimientos: {ex.Message}" ) ;
}
finally
{
if ( connection ? . State = = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConnClose ) await dbConnClose . CloseAsync ( ) ; else connection . Close ( ) ;
}
}
}
public async Task < ( IEnumerable < EntradaSalidaCanillaDto > ? MovimientosCreados , string? Error ) > CrearMovimientosEnLoteAsync ( CreateBulkEntradaSalidaCanillaDto createBulkDto , int idUsuario )
{
var canillaDataResult = await _canillaRepository . GetByIdAsync ( createBulkDto . IdCanilla ) ;
Canilla ? canillaActual = canillaDataResult . Canilla ;
if ( canillaActual = = null ) return ( null , "Canillita no válido." ) ;
if ( canillaActual . Baja ) return ( null , "El canillita está dado de baja." ) ;
List < EntradaSalidaCanilla > movimientosCreadosEntidades = new List < EntradaSalidaCanilla > ( ) ;
List < string > erroresItems = new List < string > ( ) ;
using var connection = _connectionFactory . CreateConnection ( ) ;
if ( connection is System . Data . Common . DbConnection dbConnOpen & & connection . State = = ConnectionState . Closed ) await dbConnOpen . OpenAsync ( ) ; else if ( connection . State = = ConnectionState . Closed ) connection . Open ( ) ;
using var transaction = connection . BeginTransaction ( ) ;
try
{
foreach ( var itemDto in createBulkDto . Items . Where ( i = > i . IdPublicacion > 0 ) )
{
if ( await _esCanillaRepository . ExistsByPublicacionCanillaFechaAsync ( itemDto . IdPublicacion , createBulkDto . IdCanilla , createBulkDto . Fecha . Date , transaction : transaction ) )
{
var pubInfo = await _publicacionRepository . GetByIdSimpleAsync ( itemDto . IdPublicacion ) ;
erroresItems . Add ( $"Ya existe un registro para la publicación '{pubInfo?.Nombre ?? itemDto.IdPublicacion.ToString()}' para {canillaActual.NomApe} en la fecha {createBulkDto.Fecha:dd/MM/yyyy}." ) ;
}
}
if ( erroresItems . Any ( ) )
{
if ( transaction . Connection ! = null ) transaction . Rollback ( ) ;
return ( null , string . Join ( " " , erroresItems ) ) ;
}
foreach ( var itemDto in createBulkDto . Items )
{
if ( itemDto . IdPublicacion = = 0 & & itemDto . CantSalida = = 0 & & itemDto . CantEntrada = = 0 & & string . IsNullOrWhiteSpace ( itemDto . Observacion ) ) continue ;
if ( itemDto . IdPublicacion = = 0 )
{
if ( itemDto . CantSalida > 0 | | itemDto . CantEntrada > 0 | | ! string . IsNullOrWhiteSpace ( itemDto . Observacion ) )
{
erroresItems . Add ( $"Falta seleccionar la publicación para una de las líneas con cantidades/observación." ) ;
}
continue ;
}
var publicacionItem = await _publicacionRepository . GetByIdSimpleAsync ( itemDto . IdPublicacion ) ;
bool noEsValidaONoHabilitada = false ;
if ( publicacionItem = = null )
{
noEsValidaONoHabilitada = true ;
}
else
{
// Si Habilitada es bool? y NULL significa que toma el DEFAULT 1 (true) de la BD
// entonces solo consideramos error si es explícitamente false.
if ( publicacionItem . Habilitada . HasValue & & publicacionItem . Habilitada . Value = = false )
{
noEsValidaONoHabilitada = true ;
}
// Si publicacionItem.Habilitada es null o true, noEsValidaONoHabilitada permanece false.
}
if ( noEsValidaONoHabilitada )
{
erroresItems . Add ( $"Publicación ID {itemDto.IdPublicacion} no es válida o no está habilitada." ) ;
continue ;
}
var precioActivo = await _precioRepository . GetActiveByPublicacionAndDateAsync ( itemDto . IdPublicacion , createBulkDto . Fecha . Date , transaction ) ;
if ( precioActivo = = null )
{
string nombrePubParaError = publicacionItem ? . Nombre ? ? $"ID {itemDto.IdPublicacion}" ;
erroresItems . Add ( $"No hay precio definido para '{nombrePubParaError}' en {createBulkDto.Fecha:dd/MM/yyyy}." ) ;
continue ;
}
RecargoZona ? recargoActivo = null ;
// Aquí usamos canillaActual! porque ya verificamos que no es null al inicio del método.
if ( canillaActual ! . IdZona > 0 )
{
recargoActivo = await _recargoZonaRepository . GetActiveByPublicacionZonaAndDateAsync ( itemDto . IdPublicacion , canillaActual . IdZona , createBulkDto . Fecha . Date , transaction ) ;
}
PorcMonCanilla ? porcMonActivo = null ;
// Aquí usamos canillaActual! porque ya verificamos que no es null al inicio del método.
if ( canillaActual ! . Accionista )
{
porcMonActivo = await _porcMonCanillaRepository . GetActiveByPublicacionCanillaAndDateAsync ( itemDto . IdPublicacion , createBulkDto . IdCanilla , createBulkDto . Fecha . Date , transaction ) ;
if ( porcMonActivo = = null )
{
// Dentro de este bloque, canillaActual.NomApe es seguro porque Accionista era true.
string nombreCanParaError = canillaActual . NomApe ;
string nombrePubParaError = publicacionItem ? . Nombre ? ? $"Publicación ID {itemDto.IdPublicacion}" ;
erroresItems . Add ( $"'{nombreCanParaError}' es accionista pero no tiene %/monto para '{nombrePubParaError}' en {createBulkDto.Fecha:dd/MM/yyyy}." ) ;
continue ;
}
}
var nuevoES = new EntradaSalidaCanilla
{
IdPublicacion = itemDto . IdPublicacion ,
IdCanilla = createBulkDto . IdCanilla ,
Fecha = createBulkDto . Fecha . Date ,
CantSalida = itemDto . CantSalida ,
CantEntrada = itemDto . CantEntrada ,
Observacion = itemDto . Observacion ,
IdPrecio = precioActivo . IdPrecio ,
IdRecargo = recargoActivo ? . IdRecargo ? ? 0 ,
IdPorcMon = porcMonActivo ? . IdPorcMon ? ? 0 ,
Liquidado = false ,
FechaLiquidado = null ,
UserLiq = null
} ;
var esCreada = await _esCanillaRepository . CreateAsync ( nuevoES , idUsuario , transaction ) ;
if ( esCreada = = null ) throw new DataException ( $"Error al registrar movimiento para Publicación ID {itemDto.IdPublicacion}." ) ;
movimientosCreadosEntidades . Add ( esCreada ) ;
}
if ( erroresItems . Any ( ) )
{
if ( transaction . Connection ! = null ) transaction . Rollback ( ) ;
return ( null , string . Join ( " " , erroresItems ) ) ;
}
// CORRECCIÓN PARA CS0019 (línea 394 original):
bool tieneItemsSignificativos = false ;
if ( createBulkDto . Items ! = null ) // Checkear si Items es null antes de llamar a Any()
{
tieneItemsSignificativos = createBulkDto . Items . Any ( i = > i . IdPublicacion > 0 & &
( i . CantSalida > 0 | | i . CantEntrada > 0 | | ! string . IsNullOrWhiteSpace ( i . Observacion ) ) ) ;
}
if ( ! movimientosCreadosEntidades . Any ( ) & & tieneItemsSignificativos )
{
if ( transaction . Connection ! = null ) transaction . Rollback ( ) ;
return ( null , "No se pudo procesar ningún ítem válido con datos significativos." ) ;
}
if ( transaction . Connection ! = null ) transaction . Commit ( ) ;
_logger . LogInformation ( "Lote de {Count} movimientos Canillita para Canilla ID {IdCanilla} en Fecha {Fecha} creados por Usuario ID {UserId}." ,
movimientosCreadosEntidades . Count , createBulkDto . IdCanilla , createBulkDto . Fecha . Date , idUsuario ) ;
var dtosCreados = new List < EntradaSalidaCanillaDto > ( ) ;
foreach ( var entidad in movimientosCreadosEntidades )
{
var dto = await MapToDto ( entidad ) ;
if ( dto ! = null ) dtosCreados . Add ( dto ) ;
}
return ( dtosCreados , null ) ;
}
catch ( Exception ex )
{
if ( transaction . Connection ! = null ) { try { transaction . Rollback ( ) ; } catch ( Exception exRollback ) { _logger . LogError ( exRollback , "Error durante rollback de transacción." ) ; } }
_logger . LogError ( ex , "Error CrearMovimientosEnLoteAsync para Canilla ID {IdCanilla}, Fecha {Fecha}" , createBulkDto . IdCanilla , createBulkDto . Fecha ) ;
return ( null , $"Error interno al procesar el lote: {ex.Message}" ) ;
}
finally
{
if ( connection ? . State = = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConnClose ) await dbConnClose . CloseAsync ( ) ; else connection . Close ( ) ;
}
}
}
2025-06-09 19:37:07 -03:00
public async Task < IEnumerable < EntradaSalidaCanillaHistorialDto > > ObtenerHistorialAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
int? idUsuarioModifico , string? tipoModificacion ,
int? idParteAfectada )
{
// Asumiendo que _esCanillaRepository es tu IEntradaSalidaCanillaRepository
var historialData = await _esCanillaRepository . GetHistorialAsync ( fechaDesde , fechaHasta , idUsuarioModifico , tipoModificacion , idParteAfectada ) ;
return historialData . Select ( h = > new EntradaSalidaCanillaHistorialDto
{
Id_Parte = h . Historial . Id_Parte ,
Id_Publicacion = h . Historial . Id_Publicacion ,
Id_Canilla = h . Historial . Id_Canilla ,
Fecha = h . Historial . Fecha ,
CantSalida = h . Historial . CantSalida ,
CantEntrada = h . Historial . CantEntrada ,
Id_Precio = h . Historial . Id_Precio ,
Id_Recargo = h . Historial . Id_Recargo ,
Id_PorcMon = h . Historial . Id_PorcMon ,
Observacion = h . Historial . Observacion ,
Id_Usuario = h . Historial . Id_Usuario ,
NombreUsuarioModifico = h . NombreUsuarioModifico ,
FechaMod = h . Historial . FechaMod ,
TipoMod = h . Historial . TipoMod
} ) . ToList ( ) ;
}
2025-05-23 15:47:39 -03:00
}
}