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}"); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |