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("平台端-SaaS 套餐")] [Route("api/platform-admin/saas")] [Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)] public sealed class PlatformSaasController( ISaasCatalogAdminService catalogService, IPlatformBillingAdminService billingService, ICurrentUser currentUser) : ControllerBase { [HttpGet("catalog")] [EndpointSummary("查询平台 SaaS 商品目录")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task Catalog(CancellationToken cancellationToken) => catalogService.GetCatalogAsync(Actor(), cancellationToken); [HttpPut("features")] [EndpointSummary("新增或更新 SaaS 功能")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task UpsertFeature(UpsertSaasFeatureDto request, CancellationToken cancellationToken) => catalogService.UpsertFeatureAsync(Actor(), request.ToCommand(), cancellationToken); [HttpPut("feature-limits")] [EndpointSummary("新增或更新 SaaS 功能限额")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task UpsertFeatureLimit( UpsertSaasFeatureLimitDto request, CancellationToken cancellationToken) => catalogService.UpsertLimitDefinitionAsync(Actor(), request.ToCommand(), cancellationToken); [HttpPut("offerings")] [EndpointSummary("新增或更新 SaaS 套餐")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task UpsertOffering(UpsertSaasOfferingDto request, CancellationToken cancellationToken) => catalogService.UpsertOfferingAsync(Actor(), request.ToCommand(), cancellationToken); [HttpPut("offering-versions")] [EndpointSummary("新增或更新 SaaS 套餐版本草稿")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task UpsertVersion(UpsertSaasOfferingVersionDto request, CancellationToken cancellationToken) => catalogService.UpsertDraftVersionAsync(Actor(), request.ToCommand(), cancellationToken); [HttpPost("offering-versions/{versionId:guid}/publish")] [EndpointSummary("发布 SaaS 套餐版本")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task PublishVersion(Guid versionId, CancellationToken cancellationToken) => catalogService.PublishVersionAsync(Actor(), versionId, cancellationToken); [HttpPost("offering-versions/{versionId:guid}/clone")] [EndpointSummary("克隆 SaaS 套餐版本")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task CloneVersion(Guid versionId, CancellationToken cancellationToken) => catalogService.CloneVersionAsync(Actor(), versionId, cancellationToken); [HttpPost("offering-versions/{versionId:guid}/retire")] [EndpointSummary("下架 SaaS 套餐版本")] [Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)] public Task RetireVersion(Guid versionId, CancellationToken cancellationToken) => catalogService.RetireVersionAsync(Actor(), versionId, cancellationToken); [HttpGet("orders")] [EndpointSummary("查询平台 SaaS 订单")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task> Orders(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) => billingService.GetOrdersAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken); [HttpGet("payments")] [EndpointSummary("查询平台 SaaS 支付记录")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task> Payments(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) => billingService.GetPaymentsAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken); [HttpGet("refunds")] [EndpointSummary("查询平台 SaaS 退款记录")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task> Refunds(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) => billingService.GetRefundsAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken); [HttpGet("invoices")] [EndpointSummary("查询平台 SaaS 发票")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task> Invoices(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) => billingService.GetInvoicesAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken); [HttpGet("usage")] [EndpointSummary("查询租户 SaaS 用量")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task> Usage(Guid? tenantId, int limit = 100, CancellationToken cancellationToken = default) => billingService.GetUsageAsync(Actor(), new PlatformBillingAdminQuery(tenantId, null, limit), cancellationToken); [HttpGet("invoices/reminders")] [EndpointSummary("查询平台 SaaS 账单提醒")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task> InvoiceReminders(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) => billingService.GetInvoiceRemindersAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken); [HttpGet("subscriptions")] [EndpointSummary("查询租户 SaaS 订阅")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task> Subscriptions(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) => billingService.GetSubscriptionsAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken); [HttpPost("payments/manual/confirm")] [EndpointSummary("确认平台手工支付")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task ConfirmManualPayment(ConfirmManualPlatformPaymentDto request, CancellationToken cancellationToken) => billingService.ConfirmManualPaymentAsync(Actor(), request.ToCommand(), cancellationToken); [HttpPut("tenant-feature-overrides")] [EndpointSummary("新增或更新租户功能覆盖规则")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task UpsertFeatureOverride(UpsertTenantFeatureOverrideDto request, CancellationToken cancellationToken) => billingService.UpsertFeatureOverrideAsync(Actor(), request.ToCommand(), cancellationToken); private SaasCatalogActor Actor() => currentUser.UserId is { } userId ? new SaasCatalogActor(userId) : throw new PlatformBillingException("Platform actor was not resolved.", "platform_access_denied"); }