2025-06-06 18:33:09 -03:00
using GestionIntegral.Api.Data ;
using GestionIntegral.Api.Data.Repositories.Contables ;
using GestionIntegral.Api.Data.Repositories.Distribucion ; // Para IDistribuidorRepository, ICanillaRepository
2025-06-09 19:37:07 -03:00
using GestionIntegral.Api.Dtos.Auditoria ;
2025-06-06 18:33:09 -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 SaldoService : ISaldoService
{
private readonly ISaldoRepository _saldoRepo ;
private readonly IDistribuidorRepository _distribuidorRepo ; // Para nombres
private readonly ICanillaRepository _canillaRepo ; // Para nombres
private readonly IEmpresaRepository _empresaRepo ; // Para nombres
private readonly DbConnectionFactory _connectionFactory ;
private readonly ILogger < SaldoService > _logger ;
public SaldoService (
ISaldoRepository saldoRepo ,
IDistribuidorRepository distribuidorRepo ,
ICanillaRepository canillaRepo ,
IEmpresaRepository empresaRepo ,
DbConnectionFactory connectionFactory ,
ILogger < SaldoService > logger )
{
_saldoRepo = saldoRepo ;
_distribuidorRepo = distribuidorRepo ;
_canillaRepo = canillaRepo ;
_empresaRepo = empresaRepo ;
_connectionFactory = connectionFactory ;
_logger = logger ;
}
private async Task < SaldoGestionDto > MapToGestionDto ( Saldo saldo )
{
if ( saldo = = null ) return null ! ;
string nombreDestinatario = "N/A" ;
if ( saldo . Destino = = "Distribuidores" )
{
var distData = await _distribuidorRepo . GetByIdAsync ( saldo . IdDestino ) ;
nombreDestinatario = distData . Distribuidor ? . Nombre ? ? $"Dist. ID {saldo.IdDestino}" ;
}
else if ( saldo . Destino = = "Canillas" )
{
var canData = await _canillaRepo . GetByIdAsync ( saldo . IdDestino ) ;
nombreDestinatario = canData . Canilla ? . NomApe ? ? $"Can. ID {saldo.IdDestino}" ;
}
2025-06-09 19:37:07 -03:00
2025-06-06 18:33:09 -03:00
var empresa = await _empresaRepo . GetByIdAsync ( saldo . IdEmpresa ) ;
return new SaldoGestionDto
{
IdSaldo = saldo . IdSaldo ,
Destino = saldo . Destino ,
IdDestino = saldo . IdDestino ,
NombreDestinatario = nombreDestinatario ,
IdEmpresa = saldo . IdEmpresa ,
NombreEmpresa = empresa ? . Nombre ? ? $"Emp. ID {saldo.IdEmpresa}" ,
Monto = saldo . Monto ,
FechaUltimaModificacion = saldo . FechaUltimaModificacion
} ;
}
public async Task < IEnumerable < SaldoGestionDto > > ObtenerSaldosParaGestionAsync ( string? destinoFilter , int? idDestinoFilter , int? idEmpresaFilter )
{
var saldos = await _saldoRepo . GetSaldosParaGestionAsync ( destinoFilter , idDestinoFilter , idEmpresaFilter ) ;
var dtos = new List < SaldoGestionDto > ( ) ;
foreach ( var saldo in saldos )
{
dtos . Add ( await MapToGestionDto ( saldo ) ) ;
}
return dtos ;
}
public async Task < ( bool Exito , string? Error , SaldoGestionDto ? SaldoActualizado ) > RealizarAjusteManualSaldoAsync ( AjusteSaldoRequestDto ajusteDto , int idUsuarioAjuste )
{
if ( ajusteDto . MontoAjuste = = 0 )
return ( false , "El monto de ajuste no puede ser cero." , null ) ;
// Validar existencia de Destino y Empresa
if ( ajusteDto . Destino = = "Distribuidores" )
{
if ( await _distribuidorRepo . GetByIdSimpleAsync ( ajusteDto . IdDestino ) = = null )
return ( false , "El distribuidor especificado no existe." , null ) ;
}
else if ( ajusteDto . Destino = = "Canillas" )
{
if ( await _canillaRepo . GetByIdSimpleAsync ( ajusteDto . IdDestino ) = = null )
return ( false , "El canillita especificado no existe." , null ) ;
2025-06-09 19:37:07 -03:00
}
else
{
return ( false , "Tipo de destino inválido." , null ) ;
2025-06-06 18:33:09 -03:00
}
if ( await _empresaRepo . GetByIdAsync ( ajusteDto . IdEmpresa ) = = null )
2025-06-09 19:37:07 -03:00
return ( false , "La empresa especificada no existe." , null ) ;
2025-06-06 18:33:09 -03:00
using var connection = _connectionFactory . CreateConnection ( ) ;
if ( connection . State ! = ConnectionState . Open ) { if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . OpenAsync ( ) ; else connection . Open ( ) ; }
using var transaction = connection . BeginTransaction ( ) ;
try
{
var saldoActual = await _saldoRepo . GetSaldoAsync ( ajusteDto . Destino , ajusteDto . IdDestino , ajusteDto . IdEmpresa , transaction ) ;
if ( saldoActual = = null )
{
// Podríamos crear el saldo aquí si no existe y se quiere permitir un ajuste sobre un saldo nuevo.
// O devolver error. Por ahora, error.
transaction . Rollback ( ) ;
return ( false , "No se encontró un saldo existente para el destinatario y empresa especificados." , null ) ;
}
decimal saldoAnterior = saldoActual . Monto ;
2025-06-09 19:37:07 -03:00
2025-06-06 18:33:09 -03:00
bool modificado = await _saldoRepo . ModificarSaldoAsync ( ajusteDto . Destino , ajusteDto . IdDestino , ajusteDto . IdEmpresa , ajusteDto . MontoAjuste , transaction ) ;
if ( ! modificado )
{
throw new DataException ( "No se pudo modificar el saldo principal." ) ;
}
// Obtener el saldo después de la modificación para el historial
var saldoDespuesDeModificacion = await _saldoRepo . GetSaldoAsync ( ajusteDto . Destino , ajusteDto . IdDestino , ajusteDto . IdEmpresa , transaction ) ;
2025-06-09 19:37:07 -03:00
if ( saldoDespuesDeModificacion = = null ) throw new DataException ( "No se pudo obtener el saldo después de la modificación." ) ;
2025-06-06 18:33:09 -03:00
var historial = new SaldoAjusteHistorial
{
Destino = ajusteDto . Destino ,
IdDestino = ajusteDto . IdDestino ,
IdEmpresa = ajusteDto . IdEmpresa ,
MontoAjuste = ajusteDto . MontoAjuste ,
SaldoAnterior = saldoAnterior ,
SaldoNuevo = saldoDespuesDeModificacion . Monto , // saldoActual.Monto + ajusteDto.MontoAjuste,
Justificacion = ajusteDto . Justificacion ,
FechaAjuste = DateTime . Now , // O UtcNow
IdUsuarioAjuste = idUsuarioAjuste
} ;
await _saldoRepo . CreateSaldoAjusteHistorialAsync ( historial , transaction ) ;
transaction . Commit ( ) ;
_logger . LogInformation ( "Ajuste manual de saldo realizado para {Destino} ID {IdDestino}, Empresa ID {IdEmpresa} por Usuario ID {IdUsuarioAjuste}. Monto: {MontoAjuste}" ,
ajusteDto . Destino , ajusteDto . IdDestino , ajusteDto . IdEmpresa , idUsuarioAjuste , ajusteDto . MontoAjuste ) ;
2025-06-09 19:37:07 -03:00
2025-06-06 18:33:09 -03:00
var saldoDtoActualizado = await MapToGestionDto ( saldoDespuesDeModificacion ) ;
return ( true , null , saldoDtoActualizado ) ;
}
catch ( Exception ex )
{
2025-06-09 19:37:07 -03:00
try { transaction . Rollback ( ) ; } catch ( Exception rbEx ) { _logger . LogError ( rbEx , "Error en Rollback de RealizarAjusteManualSaldoAsync." ) ; }
2025-06-06 18:33:09 -03:00
_logger . LogError ( ex , "Error en RealizarAjusteManualSaldoAsync." ) ;
return ( false , $"Error interno al realizar el ajuste: {ex.Message}" , null ) ;
}
finally
{
2025-06-09 19:37:07 -03:00
if ( connection . State = = ConnectionState . Open ) { if ( connection is System . Data . Common . DbConnection dbConn ) await dbConn . CloseAsync ( ) ; else connection . Close ( ) ; }
2025-06-06 18:33:09 -03:00
}
}
2025-06-09 19:37:07 -03:00
public async Task < IEnumerable < SaldoAjusteHistorialDto > > ObtenerHistorialAjustesAsync (
DateTime ? fechaDesde , DateTime ? fechaHasta ,
int? idUsuarioModifico ,
string? destino , int? idDestino , int? idEmpresa )
{
var historialData = await _saldoRepo . GetHistorialAjustesAsync ( fechaDesde , fechaHasta , idUsuarioModifico , destino , idDestino , idEmpresa ) ;
return historialData . Select ( h = > new SaldoAjusteHistorialDto
{
IdSaldoAjusteHist = h . Historial . IdSaldoAjusteHist ,
Destino = h . Historial . Destino ,
Id_Destino = h . Historial . IdDestino ,
Id_Empresa = h . Historial . IdEmpresa ,
MontoAjuste = h . Historial . MontoAjuste ,
SaldoAnterior = h . Historial . SaldoAnterior ,
SaldoNuevo = h . Historial . SaldoNuevo ,
Justificacion = h . Historial . Justificacion ,
FechaAjuste = h . Historial . FechaAjuste ,
Id_UsuarioAjuste = h . Historial . IdUsuarioAjuste ,
NombreUsuarioModifico = h . NombreUsuarioModifico
// TipoMod es implícito "AjusteManualSaldo"
} ) . ToList ( ) ;
}
2025-06-06 18:33:09 -03:00
}
}