using Fitness_core_BE.DTOs.PlatformBilling; using Fitness_core_BE.Helpers; using Fitness_core_BE.Interfaces.Services; using Fitness_core_BE.Models.IOs; using Microsoft.AspNetCore.Mvc; using static Fitness_core_BE.Helpers.JwtMiddleware; using static Fitness_core_BE.Helpers.ApiResponseHelper; namespace Fitness_core_BE.Controllers { // The gym owner's own HexaFitness platform subscription bill — distinct from // CustomerPaymentsController, which handles invoices billed to gym members. [ApiController] [Route("api/client")] public class ClientInvoiceController : ControllerBase { private readonly IClientInvoiceService _clientInvoiceService; private readonly IPaymentService _paymentService; private readonly IReceiptService _receiptService; private readonly IClientPaymentMethodService _clientPaymentMethodService; private readonly UserRoleHelper _userRoleHelper; public ClientInvoiceController( IClientInvoiceService clientInvoiceService, IPaymentService paymentService, IReceiptService receiptService, IClientPaymentMethodService clientPaymentMethodService, UserRoleHelper userRoleHelper) { _clientInvoiceService = clientInvoiceService; _paymentService = paymentService; _receiptService = receiptService; _clientPaymentMethodService = clientPaymentMethodService; _userRoleHelper = userRoleHelper; } [CustomMiddleware] [TenantResolution] [RequiresPermission("billing")] [HttpGet("customer-invoices")] public async Task>> GetCustomerInvoices() { var clientId = await _userRoleHelper.GetClientId(DataExtractor.GetUserIdFromContext(HttpContext)); return Response(await _clientInvoiceService.GetClientInvoicesByClientId(new { clientId }, HttpContext)); } [CustomMiddleware] [TenantResolution] [RequiresPermission("billing")] [HttpGet("customer-invoices/{id:guid}")] public async Task>> GetCustomerInvoice(Guid id) => Response(await _clientInvoiceService.GetClientInvoiceById(new { clientInvoiceId = id }, HttpContext)); // Pay this gym's own HexaFitness platform invoice. Records a pending payment // attempt (an admin approves it, which flips the invoice to Paid and issues a receipt). [CustomMiddleware] [TenantResolution] [RequiresPermission("billing")] [HttpPost("customer-invoices/{id:guid}/pay")] public async Task>> PayCustomerInvoice(Guid id, [FromBody] PayPlatformInvoiceRequest request) => Response(await _paymentService.CreateClientPayment(new { clientInvoiceId = id, payAmount = request.PayAmount, cardId = request.CardId, payNote = request.PayNote }, HttpContext)); // Branded receipt PDF for a platform invoice (download), once paid. [CustomMiddleware] [TenantResolution] [RequiresPermission("billing")] [HttpGet("customer-invoices/{id:guid}/receipt.pdf")] public async Task DownloadPlatformInvoiceReceipt(Guid id) { var clientId = await _userRoleHelper.GetClientId(DataExtractor.GetUserIdFromContext(HttpContext)); var model = await _receiptService.BuildForClientInvoiceAsync(id, requireClientId: clientId); var pdf = _receiptService.GeneratePdf(model); return File(pdf, "application/pdf", $"{model.ReceiptNo}.pdf"); } // The gym's own saved card(s) for paying their HexaFitness platform subscription // (real Payment-Service-backed flow — distinct from the manual PayCustomerInvoice // above, which just records a pending payment for an admin to approve). [CustomMiddleware] [RequiresPermission("billing")] [HttpPost("customer-invoices/cards/onboard")] public async Task>> StartCardOnboarding( [FromBody] StartCardOnboardingRequest request) => Response(await _clientPaymentMethodService.StartCardOnboardingAsync(HttpContext, request)); [CustomMiddleware] [RequiresPermission("billing")] [HttpGet("customer-invoices/cards/onboard/complete")] public async Task>> CompleteCardOnboarding([FromQuery] string sessionId) => Response(await _clientPaymentMethodService.CompleteCardOnboardingAsync(HttpContext, sessionId)); [CustomMiddleware] [RequiresPermission("billing")] [HttpGet("customer-invoices/cards")] public async Task>>> ListCards() => Response(await _clientPaymentMethodService.ListCardsAsync(HttpContext)); [CustomMiddleware] [RequiresPermission("billing")] [HttpDelete("customer-invoices/cards/{cardToken}")] public async Task>> RemoveCard(string cardToken) { await _clientPaymentMethodService.RemoveCardAsync(HttpContext, cardToken); return Response(new { removed = true }); } [CustomMiddleware] [RequiresPermission("billing")] [HttpPatch("customer-invoices/cards/{cardToken}/default")] public async Task>> SetDefaultCard(string cardToken) => Response(await _clientPaymentMethodService.SetDefaultCardAsync(HttpContext, cardToken)); [CustomMiddleware] [RequiresPermission("billing")] [HttpGet("customer-invoices/transactions")] public async Task>> GetTransactionHistory( [FromQuery] int page = 1, [FromQuery] int pageSize = 20) => Response(await _clientPaymentMethodService.GetTransactionHistoryAsync(HttpContext, page, pageSize)); public class PayPlatformInvoiceRequest { public decimal PayAmount { get; set; } public string? CardId { get; set; } public string? PayNote { get; set; } } } }