using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Tiku.Api.Contracts; using Tiku.Application.PlatformBilling; using Tiku.Application.Security; using Tiku.Domain.Platform; namespace Tiku.Api.Controllers; [ApiController] [Tags("租户端-账务")] [Route("api/tenant-billing")] [Authorize(Policy = BackendPermissions.TenantBillingManage)] public sealed class TenantBillingController( ITenantBillingService billingService, ICurrentAccessContext accessContext) : ControllerBase { [HttpGet("catalog")] [EndpointSummary("查询租户可购买 SaaS 目录")] public async Task Catalog(CancellationToken cancellationToken) => await billingService.GetCatalogAsync(await ActorAsync(cancellationToken), cancellationToken); [HttpPost("quotes")] [EndpointSummary("创建租户账务报价")] public async Task Quote(CreatePlatformBillingQuoteDto request, CancellationToken cancellationToken) => await billingService.CreateQuoteAsync(await ActorAsync(cancellationToken), request.ToCommand(), cancellationToken); [HttpPost("orders")] [EndpointSummary("创建租户账务订单")] public async Task CreateOrder(CreatePlatformBillingOrderDto request, CancellationToken cancellationToken) => await billingService.CreateOrderAsync(await ActorAsync(cancellationToken), request.ToCommand(), cancellationToken); [HttpPost("orders/{orderNo}/payments")] [EndpointSummary("创建租户账务订单支付")] public async Task CreatePayment(string orderNo, CreatePlatformBillingPaymentDto request, CancellationToken cancellationToken) => await billingService.CreatePaymentAsync(await ActorAsync(cancellationToken), request.ToCommand(orderNo), cancellationToken); [HttpGet("orders")] [EndpointSummary("查询租户账务订单")] public async Task> Orders(int limit = 100, CancellationToken cancellationToken = default) => await billingService.GetOrdersAsync(await ActorAsync(cancellationToken), limit, cancellationToken); [HttpGet("orders/{orderNo}")] [EndpointSummary("查询租户账务订单详情")] public async Task Order(string orderNo, CancellationToken cancellationToken) => await billingService.GetOrderAsync(await ActorAsync(cancellationToken), orderNo, cancellationToken); [HttpGet("subscription")] [EndpointSummary("查询当前租户 SaaS 订阅")] public async Task Subscription(CancellationToken cancellationToken) => await billingService.GetSubscriptionAsync(await ActorAsync(cancellationToken), cancellationToken); [HttpPost("subscription/change")] [EndpointSummary("变更当前租户 SaaS 订阅")] public async Task Change(ChangeTenantSubscriptionDto request, CancellationToken cancellationToken) => await billingService.ChangeSubscriptionAsync(await ActorAsync(cancellationToken), request.ToCommand(), request.IdempotencyKey, cancellationToken); [HttpPost("subscription/renew")] [EndpointSummary("续费当前租户 SaaS 订阅")] public async Task Renew(IdempotentTenantBillingDto request, CancellationToken cancellationToken) => await billingService.RenewSubscriptionAsync(await ActorAsync(cancellationToken), request.IdempotencyKey, cancellationToken); [HttpPost("subscription/cancel")] [EndpointSummary("取消当前租户 SaaS 订阅")] public async Task Cancel(CancellationToken cancellationToken) => await billingService.CancelSubscriptionAsync(await ActorAsync(cancellationToken), cancellationToken); [HttpGet("usage")] [EndpointSummary("查询当前租户功能用量")] public async Task> Usage(CancellationToken cancellationToken) => await billingService.GetUsageAsync(await ActorAsync(cancellationToken), cancellationToken); [HttpGet("invoices")] [EndpointSummary("查询当前租户发票")] public async Task> Invoices(int limit = 100, CancellationToken cancellationToken = default) => await billingService.GetInvoicesAsync(await ActorAsync(cancellationToken), limit, cancellationToken); private async Task ActorAsync(CancellationToken cancellationToken) { var access = await accessContext.GetAsync(cancellationToken); return access.UserId is { } userId && access.TenantId is { } tenantId && access.IsCurrentTenantMember ? new TenantBillingActor(userId, tenantId) : throw new PlatformBillingException("Tenant billing actor was not resolved.", "tenant_access_denied"); } }