164 lines
7.8 KiB
C#
164 lines
7.8 KiB
C#
|
|
using GestionIntegral.Api.Data;
|
||
|
|
using GestionIntegral.Api.Data.Repositories.Contables;
|
||
|
|
using GestionIntegral.Api.Data.Repositories.Distribucion; // Para IDistribuidorRepository, ICanillaRepository
|
||
|
|
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}";
|
||
|
|
}
|
||
|
|
|
||
|
|
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);
|
||
|
|
} else {
|
||
|
|
return (false, "Tipo de destino inválido.", null);
|
||
|
|
}
|
||
|
|
if (await _empresaRepo.GetByIdAsync(ajusteDto.IdEmpresa) == null)
|
||
|
|
return (false, "La empresa especificada no existe.", null);
|
||
|
|
|
||
|
|
|
||
|
|
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;
|
||
|
|
|
||
|
|
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);
|
||
|
|
if(saldoDespuesDeModificacion == null) throw new DataException("No se pudo obtener el saldo después de la modificación.");
|
||
|
|
|
||
|
|
|
||
|
|
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);
|
||
|
|
|
||
|
|
var saldoDtoActualizado = await MapToGestionDto(saldoDespuesDeModificacion);
|
||
|
|
return (true, null, saldoDtoActualizado);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
try { transaction.Rollback(); } catch (Exception rbEx){ _logger.LogError(rbEx, "Error en Rollback de RealizarAjusteManualSaldoAsync."); }
|
||
|
|
_logger.LogError(ex, "Error en RealizarAjusteManualSaldoAsync.");
|
||
|
|
return (false, $"Error interno al realizar el ajuste: {ex.Message}", null);
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
if (connection.State == ConnectionState.Open) { if (connection is System.Data.Common.DbConnection dbConn) await dbConn.CloseAsync(); else connection.Close(); }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|