218 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using GestionIntegral.Api.Data;
 | |
| using GestionIntegral.Api.Data.Repositories.Contables;
 | |
| using GestionIntegral.Api.Data.Repositories.Distribucion;
 | |
| 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))
 | |
|                  return (null, $"Ya existe un pago '{createDto.TipoMovimiento}' con el número de recibo '{createDto.Recibo}'.");
 | |
| 
 | |
| 
 | |
|             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();
 | |
|             if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
 | |
|             using var transaction = connection.BeginTransaction();
 | |
|             try
 | |
|             {
 | |
|                 var pagoCreado = await _pagoRepo.CreateAsync(nuevoPago, idUsuario, transaction);
 | |
|                 if (pagoCreado == null) throw new DataException("Error al registrar el pago.");
 | |
| 
 | |
|                 // Afectar Saldo
 | |
|                 // Si TipoMovimiento es "Recibido", el monto DISMINUYE la deuda del distribuidor (monto positivo para el servicio de saldo).
 | |
|                 // Si TipoMovimiento es "Realizado" (empresa paga a distribuidor), el monto AUMENTA la deuda (monto negativo para el servicio de saldo).
 | |
|                 decimal montoAjusteSaldo = createDto.TipoMovimiento == "Recibido" ? createDto.Monto : -createDto.Monto;
 | |
| 
 | |
|                 bool saldoActualizado = await _saldoRepo.ModificarSaldoAsync("Distribuidores", pagoCreado.IdDistribuidor, pagoCreado.IdEmpresa, montoAjusteSaldo, transaction);
 | |
|                 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)
 | |
|             {
 | |
|                 try { transaction.Rollback(); } catch { }
 | |
|                 _logger.LogError(ex, "Error CrearAsync PagoDistribuidor.");
 | |
|                 return (null, $"Error interno: {ex.Message}");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task<(bool Exito, string? Error)> ActualizarAsync(int idPago, UpdatePagoDistribuidorDto updateDto, int idUsuario)
 | |
|         {
 | |
|             using var connection = _connectionFactory.CreateConnection();
 | |
|             if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
 | |
|             using var transaction = connection.BeginTransaction();
 | |
|             try
 | |
|             {
 | |
|                 var pagoExistente = await _pagoRepo.GetByIdAsync(idPago);
 | |
|                 if (pagoExistente == null) return (false, "Pago no encontrado.");
 | |
| 
 | |
|                 if (await _tipoPagoRepo.GetByIdAsync(updateDto.IdTipoPago) == null)
 | |
|                     return (false, "Tipo de pago no válido.");
 | |
| 
 | |
|                 // Calcular la diferencia de monto para ajustar el saldo
 | |
|                 decimal montoOriginal = pagoExistente.TipoMovimiento == "Recibido" ? pagoExistente.Monto : -pagoExistente.Monto;
 | |
|                 decimal montoNuevo = pagoExistente.TipoMovimiento == "Recibido" ? updateDto.Monto : -updateDto.Monto;
 | |
|                 decimal diferenciaAjusteSaldo = montoNuevo - montoOriginal;
 | |
| 
 | |
|                 // Actualizar campos permitidos
 | |
|                 pagoExistente.Monto = updateDto.Monto;
 | |
|                 pagoExistente.IdTipoPago = updateDto.IdTipoPago;
 | |
|                 pagoExistente.Detalle = updateDto.Detalle;
 | |
| 
 | |
|                 var actualizado = await _pagoRepo.UpdateAsync(pagoExistente, idUsuario, transaction);
 | |
|                 if (!actualizado) throw new DataException("Error al actualizar el pago.");
 | |
| 
 | |
|                 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);
 | |
|             }
 | |
|             catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Pago no encontrado."); }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 try { transaction.Rollback(); } catch { }
 | |
|                 _logger.LogError(ex, "Error ActualizarAsync PagoDistribuidor ID: {Id}", idPago);
 | |
|                 return (false, $"Error interno: {ex.Message}");
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public async Task<(bool Exito, string? Error)> EliminarAsync(int idPago, int idUsuario)
 | |
|         {
 | |
|             using var connection = _connectionFactory.CreateConnection();
 | |
|             if (connection is System.Data.Common.DbConnection dbConn) await dbConn.OpenAsync(); else connection.Open();
 | |
|             using var transaction = connection.BeginTransaction();
 | |
|             try
 | |
|             {
 | |
|                 var pagoExistente = await _pagoRepo.GetByIdAsync(idPago);
 | |
|                 if (pagoExistente == null) return (false, "Pago no encontrado.");
 | |
| 
 | |
|                 // Revertir el efecto en el saldo
 | |
|                 // Si fue "Recibido", el saldo disminuyó (montoAjusteSaldo fue +Monto). Al eliminar, revertimos sumando -Monto (o restando +Monto).
 | |
|                 // Si fue "Realizado", el saldo aumentó (montoAjusteSaldo fue -Monto). Al eliminar, revertimos sumando +Monto (o restando -Monto).
 | |
|                 decimal montoReversion = pagoExistente.TipoMovimiento == "Recibido" ? -pagoExistente.Monto : pagoExistente.Monto;
 | |
| 
 | |
|                 var eliminado = await _pagoRepo.DeleteAsync(idPago, idUsuario, transaction);
 | |
|                 if (!eliminado) throw new DataException("Error al eliminar el pago.");
 | |
| 
 | |
|                 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);
 | |
|             }
 | |
|             catch (KeyNotFoundException) { try { transaction.Rollback(); } catch { } return (false, "Pago no encontrado."); }
 | |
|             catch (Exception ex)
 | |
|             {
 | |
|                 try { transaction.Rollback(); } catch { }
 | |
|                 _logger.LogError(ex, "Error EliminarAsync PagoDistribuidor ID: {Id}", idPago);
 | |
|                 return (false, $"Error interno: {ex.Message}");
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } |