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); [HttpGet("metrics")] [EndpointSummary("查询 SaaS 商业经营指标")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task Metrics(CancellationToken cancellationToken) => billingService.GetCommercialMetricsAsync(Actor(), cancellationToken); [HttpPost("subscriptions/trial")] [EndpointSummary("为已有租户补录试用订阅")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task GrantTrial(GrantTenantTrialDto request, CancellationToken cancellationToken) => billingService.GrantTrialAsync(Actor(), request.ToCommand(), cancellationToken); [HttpPost("subscriptions/{subscriptionId:guid}/suspend")] [EndpointSummary("暂停租户 SaaS 订阅")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task SuspendSubscription(Guid subscriptionId, ChangePlatformSubscriptionDto request, CancellationToken cancellationToken) => billingService.SuspendSubscriptionAsync(Actor(), request.ToCommand(subscriptionId), cancellationToken); [HttpPost("subscriptions/{subscriptionId:guid}/resume")] [EndpointSummary("恢复租户 SaaS 订阅")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task ResumeSubscription(Guid subscriptionId, ChangePlatformSubscriptionDto request, CancellationToken cancellationToken) => billingService.ResumeSubscriptionAsync(Actor(), request.ToCommand(subscriptionId), cancellationToken); [HttpPost("subscriptions/{subscriptionId:guid}/cancel")] [EndpointSummary("立即取消租户 SaaS 订阅")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task CancelSubscription(Guid subscriptionId, ChangePlatformSubscriptionDto request, CancellationToken cancellationToken) => billingService.CancelSubscriptionAsync(Actor(), request.ToCommand(subscriptionId), cancellationToken); [HttpPost("subscriptions/{subscriptionId:guid}/extend")] [EndpointSummary("延长租户 SaaS 订阅账期")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task ExtendSubscription(Guid subscriptionId, ChangePlatformSubscriptionDto request, CancellationToken cancellationToken) => billingService.ExtendSubscriptionAsync(Actor(), request.ToCommand(subscriptionId), cancellationToken); [HttpPost("refunds")] [EndpointSummary("申请平台 SaaS 退款")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task RequestRefund(RequestPlatformRefundDto request, CancellationToken cancellationToken) => billingService.RequestRefundAsync(Actor(), request.ToCommand(), cancellationToken); [HttpPost("refunds/{refundId:guid}/approve")] [EndpointSummary("批准平台 SaaS 退款")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task ApproveRefund(Guid refundId, ReviewPlatformRefundDto request, CancellationToken cancellationToken) => billingService.ApproveRefundAsync(Actor(), request.ToCommand(refundId), cancellationToken); [HttpPost("refunds/{refundId:guid}/reject")] [EndpointSummary("拒绝平台 SaaS 退款")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task RejectRefund(Guid refundId, ReviewPlatformRefundDto request, CancellationToken cancellationToken) => billingService.RejectRefundAsync(Actor(), request.ToCommand(refundId), cancellationToken); [HttpPost("refunds/{refundId:guid}/retry")] [EndpointSummary("重试失败的平台 SaaS 退款")] [Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)] public Task RetryRefund(Guid refundId, ReviewPlatformRefundDto request, CancellationToken cancellationToken) => billingService.RetryRefundAsync(Actor(), request.ToCommand(refundId), cancellationToken); private SaasCatalogActor Actor() => currentUser.UserId is { } userId ? new SaasCatalogActor(userId) : throw new PlatformBillingException("Platform actor was not resolved.", "platform_access_denied"); }