Files
GestionIntegralWeb/Backend/GestionIntegral.Api/Controllers/Suscripciones/FacturacionController.cs

94 lines
3.5 KiB
C#
Raw Normal View History

Feat: Implementa flujo completo de facturación y promociones Este commit introduce la funcionalidad completa para la facturación mensual, la gestión de promociones y la comunicación con el cliente en el módulo de suscripciones. Backend: - Se añade el servicio de Facturación que calcula automáticamente los importes mensuales basándose en las suscripciones activas, días de entrega y precios. - Se implementa el servicio DebitoAutomaticoService, capaz de generar el archivo de texto plano para "Pago Directo Galicia" y de procesar el archivo de respuesta para la conciliación de pagos. - Se desarrolla el ABM completo para Promociones (Servicio, Repositorio, Controlador y DTOs), permitiendo la creación de descuentos por porcentaje o monto fijo. - Se implementa la lógica para asignar y desasignar promociones a suscripciones específicas. - Se añade un servicio de envío de email (EmailService) integrado con MailKit y un endpoint para notificar facturas a los clientes. - Se crea la lógica para registrar pagos manuales (efectivo, tarjeta, etc.) y actualizar el estado de las facturas. - Se añaden todos los permisos necesarios a la base de datos para segmentar el acceso a las nuevas funcionalidades. Frontend: - Se crea la página de Facturación, que permite al usuario seleccionar un período, generar la facturación, listar los resultados y generar el archivo de débito para el banco. - Se implementa la funcionalidad para subir y procesar el archivo de respuesta del banco, actualizando la UI en consecuencia. - Se añade la página completa para el ABM de Promociones. - Se integra un modal en la gestión de suscripciones para asignar y desasignar promociones a un cliente. - Se añade la opción "Enviar Email" en el menú de acciones de las facturas, conectada al nuevo endpoint del backend. - Se completan y corrigen los componentes `PagoManualModal` y `FacturacionPage` para incluir la lógica de registro de pagos y solucionar errores de TypeScript.
2025-08-01 12:53:17 -03:00
using GestionIntegral.Api.Dtos.Suscripciones;
using GestionIntegral.Api.Services.Suscripciones;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
namespace GestionIntegral.Api.Controllers.Suscripciones
{
[Route("api/facturacion")]
[ApiController]
[Authorize]
public class FacturacionController : ControllerBase
{
private readonly IFacturacionService _facturacionService;
private readonly ILogger<FacturacionController> _logger;
// Permiso para generar facturación (a crear en la BD)
private const string PermisoGenerarFacturacion = "SU006";
public FacturacionController(IFacturacionService facturacionService, ILogger<FacturacionController> logger)
{
_facturacionService = facturacionService;
_logger = logger;
}
private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc);
private int? GetCurrentUserId()
{
if (int.TryParse(User.FindFirstValue(ClaimTypes.NameIdentifier) ?? User.FindFirstValue("sub"), out int userId)) return userId;
return null;
}
// POST: api/facturacion/{anio}/{mes}
[HttpPost("{anio:int}/{mes:int}")]
public async Task<IActionResult> GenerarFacturacion(int anio, int mes)
{
if (!TienePermiso(PermisoGenerarFacturacion)) return Forbid();
var userId = GetCurrentUserId();
if (userId == null) return Unauthorized();
if (anio < 2020 || mes < 1 || mes > 12)
{
return BadRequest(new { message = "El año y el mes proporcionados no son válidos." });
}
var (exito, mensaje, facturasGeneradas) = await _facturacionService.GenerarFacturacionMensual(anio, mes, userId.Value);
if (!exito)
{
return StatusCode(StatusCodes.Status500InternalServerError, new { message = mensaje });
}
return Ok(new { message = mensaje, facturasGeneradas });
}
// GET: api/facturacion/{anio}/{mes}
[HttpGet("{anio:int}/{mes:int}")]
[ProducesResponseType(typeof(IEnumerable<FacturaDto>), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<IActionResult> GetFacturas(int anio, int mes)
{
// Usamos el permiso de generar facturación también para verlas.
if (!TienePermiso(PermisoGenerarFacturacion)) return Forbid();
if (anio < 2020 || mes < 1 || mes > 12)
{
return BadRequest(new { message = "El período no es válido." });
}
var facturas = await _facturacionService.ObtenerFacturasPorPeriodo(anio, mes);
return Ok(facturas);
}
// POST: api/facturacion/{idFactura}/enviar-email
[HttpPost("{idFactura:int}/enviar-email")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<IActionResult> EnviarEmail(int idFactura)
{
// Usaremos un nuevo permiso para esta acción
if (!TienePermiso("SU009")) return Forbid();
var (exito, error) = await _facturacionService.EnviarFacturaPorEmail(idFactura);
if (!exito)
{
return BadRequest(new { message = error });
}
return Ok(new { message = "Email enviado a la cola de procesamiento." });
}
}
}