using GestionIntegral.Api.Data; using GestionIntegral.Api.Data.Repositories.Suscripciones; using GestionIntegral.Api.Data.Repositories.Usuarios; using GestionIntegral.Api.Dtos.Suscripciones; using GestionIntegral.Api.Models.Suscripciones; using System.Data; namespace GestionIntegral.Api.Services.Suscripciones { public class PagoService : IPagoService { private readonly IPagoRepository _pagoRepository; private readonly IFacturaRepository _facturaRepository; private readonly IFormaPagoRepository _formaPagoRepository; private readonly IUsuarioRepository _usuarioRepository; private readonly DbConnectionFactory _connectionFactory; private readonly ILogger _logger; public PagoService( IPagoRepository pagoRepository, IFacturaRepository facturaRepository, IFormaPagoRepository formaPagoRepository, IUsuarioRepository usuarioRepository, DbConnectionFactory connectionFactory, ILogger logger) { _pagoRepository = pagoRepository; _facturaRepository = facturaRepository; _formaPagoRepository = formaPagoRepository; _usuarioRepository = usuarioRepository; _connectionFactory = connectionFactory; _logger = logger; } private async Task MapToDto(Pago pago) { if (pago == null) return null; var formaPago = await _formaPagoRepository.GetByIdAsync(pago.IdFormaPago); var usuario = await _usuarioRepository.GetByIdAsync(pago.IdUsuarioRegistro); return new PagoDto { IdPago = pago.IdPago, IdFactura = pago.IdFactura, FechaPago = pago.FechaPago.ToString("yyyy-MM-dd"), IdFormaPago = pago.IdFormaPago, NombreFormaPago = formaPago?.Nombre ?? "Desconocida", Monto = pago.Monto, Estado = pago.Estado, Referencia = pago.Referencia, Observaciones = pago.Observaciones, IdUsuarioRegistro = pago.IdUsuarioRegistro, NombreUsuarioRegistro = usuario != null ? $"{usuario.Nombre} {usuario.Apellido}" : "Usuario Desconocido" }; } public async Task> ObtenerPagosPorFacturaId(int idFactura) { var pagos = await _pagoRepository.GetByFacturaIdAsync(idFactura); var dtosTasks = pagos.Select(p => MapToDto(p)); var dtos = await Task.WhenAll(dtosTasks); return dtos.Where(dto => dto != null)!; } public async Task<(PagoDto? Pago, string? Error)> RegistrarPagoManual(CreatePagoDto createDto, int idUsuario) { using var connection = _connectionFactory.CreateConnection(); await (connection as System.Data.Common.DbConnection)!.OpenAsync(); using var transaction = connection.BeginTransaction(); try { var factura = await _facturaRepository.GetByIdAsync(createDto.IdFactura); if (factura == null) return (null, "La factura especificada no existe."); if (factura.EstadoPago == "Anulada") return (null, "No se puede registrar un pago sobre una factura anulada."); var formaPago = await _formaPagoRepository.GetByIdAsync(createDto.IdFormaPago); if (formaPago == null || !formaPago.Activo) return (null, "La forma de pago no es válida."); var totalPagadoAnteriormente = await _pagoRepository.GetTotalPagadoAprobadoAsync(createDto.IdFactura, transaction); var nuevoPago = new Pago { IdFactura = createDto.IdFactura, FechaPago = createDto.FechaPago, IdFormaPago = createDto.IdFormaPago, Monto = createDto.Monto, Estado = "Aprobado", Referencia = createDto.Referencia, Observaciones = createDto.Observaciones, IdUsuarioRegistro = idUsuario }; // Creamos el nuevo pago var pagoCreado = await _pagoRepository.CreateAsync(nuevoPago, transaction); if (pagoCreado == null) throw new DataException("No se pudo registrar el pago."); var nuevoTotalPagado = totalPagadoAnteriormente + pagoCreado.Monto; // Nueva lógica para manejar todos los estados de pago string nuevoEstadoPago = factura.EstadoPago; if (nuevoTotalPagado >= factura.ImporteFinal) { nuevoEstadoPago = "Pagada"; } else if (nuevoTotalPagado > 0) { nuevoEstadoPago = "Pagada Parcialmente"; } // Si nuevoTotalPagado es 0, el estado no cambia. // Solo actualizamos si el estado calculado es diferente al actual. if (nuevoEstadoPago != factura.EstadoPago) { bool actualizado = await _facturaRepository.UpdateEstadoPagoAsync(factura.IdFactura, nuevoEstadoPago, transaction); if (!actualizado) throw new DataException($"No se pudo actualizar el estado de la factura a '{nuevoEstadoPago}'."); } transaction.Commit(); _logger.LogInformation("Pago manual ID {IdPago} registrado para Factura ID {IdFactura} por Usuario ID {IdUsuario}", pagoCreado.IdPago, pagoCreado.IdFactura, idUsuario); var dto = await MapToDto(pagoCreado); // MapToDto ahora es más simple return (dto, null); } catch (Exception ex) { try { transaction.Rollback(); } catch { } _logger.LogError(ex, "Error al registrar pago manual para Factura ID {IdFactura}", createDto.IdFactura); return (null, $"Error interno al registrar el pago: {ex.Message}"); } } } }