2025-05-23 15:47:39 -03:00
using GestionIntegral.Api.Data ;
using GestionIntegral.Api.Data.Repositories.Contables ;
using GestionIntegral.Api.Data.Repositories.Distribucion ;
2025-06-09 19:37:07 -03:00
using GestionIntegral.Api.Dtos.Auditoria ;
2025-05-23 15:47:39 -03:00
using GestionIntegral.Api.Dtos.Contables ;
using GestionIntegral.Api.Models.Contables ;
using Microsoft.Extensions.Logging ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Linq ;
using System.Threading.Tasks ;
namespace GestionIntegral.Api.Services.Contables
{
public class PagoDistribuidorService : IPagoDistribuidorService
{
private readonly IPagoDistribuidorRepository _pagoRepo ;
private readonly IDistribuidorRepository _distribuidorRepo ;
private readonly ITipoPagoRepository _tipoPagoRepo ;
private readonly IEmpresaRepository _empresaRepo ;
private readonly ISaldoRepository _saldoRepo ;
private readonly DbConnectionFactory _connectionFactory ;
private readonly ILogger < PagoDistribuidorService > _logger ;
public PagoDistribuidorService (
IPagoDistribuidorRepository pagoRepo ,
IDistribuidorRepository distribuidorRepo ,
ITipoPagoRepository tipoPagoRepo ,
IEmpresaRepository empresaRepo ,
ISaldoRepository saldoRepo ,
DbConnectionFactory connectionFactory ,
ILogger < PagoDistribuidorService > logger )
{
_pagoRepo = pagoRepo ;
_distribuidorRepo = distribuidorRepo ;
_tipoPagoRepo = tipoPagoRepo ;
_empresaRepo = empresaRepo ;
_saldoRepo = saldoRepo ;
_connectionFactory = connectionFactory ;
_logger = logger ;
}
private async Task < PagoDistribuidorDto > MapToDto ( PagoDistribuidor pago )
{
if ( pago = = null ) return null ! ;
var distribuidorData = await _distribuidorRepo . GetByIdAsync ( pago . IdDistribuidor ) ;
var tipoPago = await _tipoPagoRepo . GetByIdAsync ( pago . IdTipoPago ) ;
var empresa = await _empresaRepo . GetByIdAsync ( pago . IdEmpresa ) ;
return new PagoDistribuidorDto
{
IdPago = pago . IdPago ,
IdDistribuidor = pago . IdDistribuidor ,
NombreDistribuidor = distribuidorData . Distribuidor ? . Nombre ? ? "N/A" ,
Fecha = pago . Fecha . ToString ( "yyyy-MM-dd" ) ,
TipoMovimiento = pago . TipoMovimiento ,
Recibo = pago . Recibo ,
Monto = pago . Monto ,
IdTipoPago = pago . IdTipoPago ,
NombreTipoPago = tipoPago ? . Nombre ? ? "N/A" ,
Detalle = pago . Detalle ,
IdEmpresa = pago . IdEmpresa ,
NombreEmpresa = empresa ? . Nombre ? ? "N/A"
} ;
}
public async Task < IEnumerable < PagoDistribuidorDto > > ObtenerTodosAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
int? idDistribuidor , int? idEmpresa , string? tipoMovimiento )
{
var pagos = await _pagoRepo . GetAllAsync ( fechaDesde , fechaHasta , idDistribuidor , idEmpresa , tipoMovimiento ) ;
var dtos = new List < PagoDistribuidorDto > ( ) ;
foreach ( var pago in pagos )
{
dtos . Add ( await MapToDto ( pago ) ) ;
}
return dtos ;
}
public async Task < PagoDistribuidorDto ? > ObtenerPorIdAsync ( int idPago )
{
var pago = await _pagoRepo . GetByIdAsync ( idPago ) ;
return pago = = null ? null : await MapToDto ( pago ) ;
}
public async Task < ( PagoDistribuidorDto ? Pago , string? Error ) > CrearAsync ( CreatePagoDistribuidorDto createDto , int idUsuario )
{
if ( await _distribuidorRepo . GetByIdSimpleAsync ( createDto . IdDistribuidor ) = = null )
return ( null , "Distribuidor no válido." ) ;
if ( await _tipoPagoRepo . GetByIdAsync ( createDto . IdTipoPago ) = = null )
return ( null , "Tipo de pago no válido." ) ;
if ( await _empresaRepo . GetByIdAsync ( createDto . IdEmpresa ) = = null )
return ( null , "Empresa no válida." ) ;
if ( await _pagoRepo . ExistsByReciboAndTipoMovimientoAsync ( createDto . Recibo , createDto . TipoMovimiento ) )
2025-06-09 19:37:07 -03:00
return ( null , $"Ya existe un pago '{createDto.TipoMovimiento}' con el número de recibo '{createDto.Recibo}'." ) ;
2025-05-23 15:47:39 -03:00
var nuevoPago = new PagoDistribuidor
{
IdDistribuidor = createDto . IdDistribuidor ,
Fecha = createDto . Fecha . Date ,
TipoMovimiento = createDto . TipoMovimiento ,
Recibo = createDto . Recibo ,
Monto = createDto . Monto ,
IdTipoPago = createDto . IdTipoPago ,
Detalle = createDto . Detalle ,
IdEmpresa = createDto . IdEmpresa
} ;
using var connection = _connectionFactory . CreateConnection ( ) ;
2025-06-06 18:33:09 -03:00
IDbTransaction ? transaction = null ; // Declarar fuera para el finally
2025-05-23 15:47:39 -03:00
try
{
2025-06-06 18:33:09 -03:00
if ( connection . State ! = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . OpenAsync ( ) ; else connection . Open ( ) ;
}
transaction = connection . BeginTransaction ( ) ;
2025-06-09 19:37:07 -03:00
2025-05-23 15:47:39 -03:00
var pagoCreado = await _pagoRepo . CreateAsync ( nuevoPago , idUsuario , transaction ) ;
if ( pagoCreado = = null ) throw new DataException ( "Error al registrar el pago." ) ;
2025-06-06 18:33:09 -03:00
decimal montoParaSaldo ;
if ( createDto . TipoMovimiento = = "Recibido" )
{
2025-06-09 19:37:07 -03:00
montoParaSaldo = - createDto . Monto ;
2025-06-06 18:33:09 -03:00
}
2025-06-09 19:37:07 -03:00
else
2025-06-06 18:33:09 -03:00
{
2025-06-09 19:37:07 -03:00
montoParaSaldo = createDto . Monto ;
2025-06-06 18:33:09 -03:00
}
2025-05-23 15:47:39 -03:00
2025-06-06 18:33:09 -03:00
bool saldoActualizado = await _saldoRepo . ModificarSaldoAsync ( "Distribuidores" , pagoCreado . IdDistribuidor , pagoCreado . IdEmpresa , montoParaSaldo , transaction ) ;
2025-05-23 15:47:39 -03:00
if ( ! saldoActualizado ) throw new DataException ( "Error al actualizar el saldo del distribuidor." ) ;
transaction . Commit ( ) ;
_logger . LogInformation ( "PagoDistribuidor ID {Id} creado y saldo afectado por Usuario ID {UserId}." , pagoCreado . IdPago , idUsuario ) ;
return ( await MapToDto ( pagoCreado ) , null ) ;
}
catch ( Exception ex )
{
2025-06-06 18:33:09 -03:00
try { transaction ? . Rollback ( ) ; } catch ( Exception rbEx ) { _logger . LogError ( rbEx , "Error en Rollback de CrearAsync PagoDistribuidor." ) ; }
2025-05-23 15:47:39 -03:00
_logger . LogError ( ex , "Error CrearAsync PagoDistribuidor." ) ;
return ( null , $"Error interno: {ex.Message}" ) ;
}
2025-06-09 19:37:07 -03:00
finally
2025-06-06 18:33:09 -03:00
{
if ( connection . State = = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . CloseAsync ( ) ; else connection . Close ( ) ;
}
}
2025-05-23 15:47:39 -03:00
}
public async Task < ( bool Exito , string? Error ) > ActualizarAsync ( int idPago , UpdatePagoDistribuidorDto updateDto , int idUsuario )
{
using var connection = _connectionFactory . CreateConnection ( ) ;
2025-06-06 18:33:09 -03:00
IDbTransaction ? transaction = null ;
2025-05-23 15:47:39 -03:00
try
{
2025-06-06 18:33:09 -03:00
if ( connection . State ! = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . OpenAsync ( ) ; else connection . Open ( ) ;
}
transaction = connection . BeginTransaction ( ) ;
2025-06-09 19:37:07 -03:00
var pagoExistente = await _pagoRepo . GetByIdAsync ( idPago ) ;
if ( pagoExistente = = null )
2025-06-06 18:33:09 -03:00
{
transaction . Rollback ( ) ; // Rollback si no se encuentra
return ( false , "Pago no encontrado." ) ;
}
2025-05-23 15:47:39 -03:00
if ( await _tipoPagoRepo . GetByIdAsync ( updateDto . IdTipoPago ) = = null )
2025-06-06 18:33:09 -03:00
{
transaction . Rollback ( ) ;
2025-05-23 15:47:39 -03:00
return ( false , "Tipo de pago no válido." ) ;
2025-06-06 18:33:09 -03:00
}
2025-06-09 19:37:07 -03:00
2025-06-06 18:33:09 -03:00
decimal impactoOriginalSaldo = pagoExistente . TipoMovimiento = = "Recibido" ? - pagoExistente . Monto : pagoExistente . Monto ;
decimal impactoNuevoSaldo = pagoExistente . TipoMovimiento = = "Recibido" ? - updateDto . Monto : updateDto . Monto ;
decimal diferenciaAjusteSaldo = impactoNuevoSaldo - impactoOriginalSaldo ;
2025-05-23 15:47:39 -03:00
2025-06-06 18:33:09 -03:00
var pagoParaActualizarEnRepo = new PagoDistribuidor
{
IdPago = pagoExistente . IdPago ,
2025-06-09 19:37:07 -03:00
IdDistribuidor = pagoExistente . IdDistribuidor ,
Fecha = pagoExistente . Fecha ,
TipoMovimiento = pagoExistente . TipoMovimiento ,
Recibo = pagoExistente . Recibo ,
Monto = updateDto . Monto ,
IdTipoPago = updateDto . IdTipoPago ,
Detalle = updateDto . Detalle ,
IdEmpresa = pagoExistente . IdEmpresa
2025-06-06 18:33:09 -03:00
} ;
2025-05-23 15:47:39 -03:00
2025-06-06 18:33:09 -03:00
var actualizado = await _pagoRepo . UpdateAsync ( pagoParaActualizarEnRepo , idUsuario , transaction ) ;
if ( ! actualizado ) throw new DataException ( "Error al actualizar el pago en la base de datos." ) ;
2025-05-23 15:47:39 -03:00
if ( diferenciaAjusteSaldo ! = 0 )
{
bool saldoActualizado = await _saldoRepo . ModificarSaldoAsync ( "Distribuidores" , pagoExistente . IdDistribuidor , pagoExistente . IdEmpresa , diferenciaAjusteSaldo , transaction ) ;
if ( ! saldoActualizado ) throw new DataException ( "Error al ajustar el saldo del distribuidor tras la actualización del pago." ) ;
}
transaction . Commit ( ) ;
_logger . LogInformation ( "PagoDistribuidor ID {Id} actualizado por Usuario ID {UserId}." , idPago , idUsuario ) ;
return ( true , null ) ;
}
2025-06-06 18:33:09 -03:00
catch ( KeyNotFoundException ) { try { transaction ? . Rollback ( ) ; } catch ( Exception rbEx ) { _logger . LogError ( rbEx , "Error en Rollback de ActualizarAsync PagoDistribuidor (KeyNotFound)." ) ; } return ( false , "Pago no encontrado." ) ; }
2025-05-23 15:47:39 -03:00
catch ( Exception ex )
{
2025-06-06 18:33:09 -03:00
try { transaction ? . Rollback ( ) ; } catch ( Exception rbEx ) { _logger . LogError ( rbEx , "Error en Rollback de ActualizarAsync PagoDistribuidor." ) ; }
2025-05-23 15:47:39 -03:00
_logger . LogError ( ex , "Error ActualizarAsync PagoDistribuidor ID: {Id}" , idPago ) ;
return ( false , $"Error interno: {ex.Message}" ) ;
}
2025-06-09 19:37:07 -03:00
finally
2025-06-06 18:33:09 -03:00
{
if ( connection . State = = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . CloseAsync ( ) ; else connection . Close ( ) ;
}
}
2025-05-23 15:47:39 -03:00
}
public async Task < ( bool Exito , string? Error ) > EliminarAsync ( int idPago , int idUsuario )
{
using var connection = _connectionFactory . CreateConnection ( ) ;
2025-06-06 18:33:09 -03:00
IDbTransaction ? transaction = null ;
2025-05-23 15:47:39 -03:00
try
{
2025-06-06 18:33:09 -03:00
if ( connection . State ! = ConnectionState . Open )
{
2025-06-09 19:37:07 -03:00
if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . OpenAsync ( ) ; else connection . Open ( ) ;
2025-06-06 18:33:09 -03:00
}
transaction = connection . BeginTransaction ( ) ;
2025-06-09 19:37:07 -03:00
2025-05-23 15:47:39 -03:00
var pagoExistente = await _pagoRepo . GetByIdAsync ( idPago ) ;
2025-06-09 19:37:07 -03:00
if ( pagoExistente = = null )
2025-06-06 18:33:09 -03:00
{
transaction . Rollback ( ) ;
return ( false , "Pago no encontrado." ) ;
}
2025-06-09 19:37:07 -03:00
2025-06-06 18:33:09 -03:00
decimal montoReversion = pagoExistente . TipoMovimiento = = "Recibido" ? pagoExistente . Monto : - pagoExistente . Monto ;
2025-05-23 15:47:39 -03:00
var eliminado = await _pagoRepo . DeleteAsync ( idPago , idUsuario , transaction ) ;
2025-06-06 18:33:09 -03:00
if ( ! eliminado ) throw new DataException ( "Error al eliminar el pago de la base de datos." ) ;
2025-05-23 15:47:39 -03:00
bool saldoActualizado = await _saldoRepo . ModificarSaldoAsync ( "Distribuidores" , pagoExistente . IdDistribuidor , pagoExistente . IdEmpresa , montoReversion , transaction ) ;
if ( ! saldoActualizado ) throw new DataException ( "Error al revertir el saldo del distribuidor tras la eliminación del pago." ) ;
transaction . Commit ( ) ;
_logger . LogInformation ( "PagoDistribuidor ID {Id} eliminado por Usuario ID {UserId}." , idPago , idUsuario ) ;
return ( true , null ) ;
}
2025-06-06 18:33:09 -03:00
catch ( KeyNotFoundException ) { try { transaction ? . Rollback ( ) ; } catch ( Exception rbEx ) { _logger . LogError ( rbEx , "Error en Rollback de EliminarAsync PagoDistribuidor (KeyNotFound)." ) ; } return ( false , "Pago no encontrado." ) ; }
2025-05-23 15:47:39 -03:00
catch ( Exception ex )
{
2025-06-06 18:33:09 -03:00
try { transaction ? . Rollback ( ) ; } catch ( Exception rbEx ) { _logger . LogError ( rbEx , "Error en Rollback de EliminarAsync PagoDistribuidor." ) ; }
2025-05-23 15:47:39 -03:00
_logger . LogError ( ex , "Error EliminarAsync PagoDistribuidor ID: {Id}" , idPago ) ;
return ( false , $"Error interno: {ex.Message}" ) ;
}
2025-06-06 18:33:09 -03:00
finally
{
if ( connection . State = = ConnectionState . Open )
{
if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . CloseAsync ( ) ; else connection . Close ( ) ;
}
}
2025-05-23 15:47:39 -03:00
}
2025-06-09 19:37:07 -03:00
public async Task < IEnumerable < PagoDistribuidorHistorialDto > > ObtenerHistorialAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
int? idUsuarioModifico , string? tipoModificacion ,
int? idPagoAfectado )
{
var historialData = await _pagoRepo . GetHistorialAsync ( fechaDesde , fechaHasta , idUsuarioModifico , tipoModificacion , idPagoAfectado ) ;
return historialData . Select ( h = > new PagoDistribuidorHistorialDto
{
Id_Pago = h . Historial . Id_Pago ,
Id_Distribuidor = h . Historial . Id_Distribuidor ,
Fecha = h . Historial . Fecha ,
TipoMovimiento = h . Historial . TipoMovimiento ,
Recibo = h . Historial . Recibo ,
Monto = h . Historial . Monto ,
Id_TipoPago = h . Historial . Id_TipoPago ,
Detalle = h . Historial . Detalle ,
Id_Empresa = h . Historial . Id_Empresa ,
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
}
}