using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Tiku.Api.Contracts; using Tiku.Application.Commerce; using Tiku.Application.Security; using Tiku.Domain.Commerce; namespace Tiku.Api.Controllers; [ApiController] [Authorize(Policy = BackendPermissions.TenantCommerceOperate)] [Produces("application/json")] [Route("api/tenant-commerce")] public sealed class TenantCommerceController( ICommerceAdminService commerceAdminService, ICurrentUser currentUser, ITenantContext currentTenant) : ControllerBase { [HttpGet("payment-accounts")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询租户支付账号")] [ProducesResponseType>(StatusCodes.Status200OK)] public async Task>> PaymentAccounts( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetPaymentAccountsAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpPut("payment-accounts")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("新增或更新租户支付账号")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertPaymentAccount( UpsertPaymentAccountDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpsertPaymentAccountAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpPut("secrets")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("写入或轮换租户密钥")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertSecret( UpsertTenantSecretDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpsertTenantSecretAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("orders")] [EndpointSummary("查询租户订单")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Orders( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetOrdersAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpGet("payments")] [EndpointSummary("查询租户支付记录")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Payments( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetPaymentsAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpPost("code-batches")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("创建兑换码批次")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateCodeBatch( CreateCodeBatchDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.CreateCodeBatchAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("activation-codes")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询兑换码")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> ActivationCodes( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetActivationCodesAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpPost("activation-codes/redeem")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("后台核销兑换码")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> RedeemActivationCode( RedeemActivationCodeDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.RedeemActivationCodeAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("point-activity-tasks")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询积分活动任务")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> PointTasks( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetPointTasksAsync( ResolveActor(), ToPointQuery(query), cancellationToken)); } [HttpPut("point-activity-tasks")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("新增或更新积分活动任务")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertPointTask( UpsertPointTaskDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpsertPointTaskAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("point-activity-claims")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询积分任务领取记录")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> PointClaims( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetPointClaimsAsync( ResolveActor(), ToPointQuery(query), cancellationToken)); } [HttpGet("point-exchange-items")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询积分兑换项")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> PointExchangeItems( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetPointExchangeItemsAsync( ResolveActor(), ToPointQuery(query), cancellationToken)); } [HttpPut("point-exchange-items")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("新增或更新积分兑换项")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertPointExchangeItem( UpsertPointExchangeItemDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpsertPointExchangeItemAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("point-exchange-orders")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询积分兑换订单")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> PointExchangeOrders( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetPointExchangeOrdersAsync( ResolveActor(), ToPointQuery(query), cancellationToken)); } [HttpPost("point-exchange-orders/status")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("更新积分兑换订单状态")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpdatePointExchangeOrderStatus( UpdatePointExchangeOrderStatusDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpdatePointExchangeOrderStatusAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("coupons")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询租户优惠券")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Coupons( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetCouponsAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpPut("coupons")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("新增或更新租户优惠券")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertCoupon( UpsertTenantCouponDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpsertCouponAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("coupons/redemptions")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询优惠券领取和核销记录")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CouponRedemptions( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetCouponRedemptionsAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpGet("coupons/report")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询优惠券基础报表")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CouponReport( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetCouponReportAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpGet("refunds")] [EndpointSummary("查询退款申请")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Refunds( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetRefundsAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpPost("refunds")] [EndpointSummary("创建退款申请")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateRefund( CreateRefundRequestDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.CreateRefundRequestAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpPost("refunds/status")] [EndpointSummary("更新退款状态")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpdateRefundStatus( UpdateRefundStatusDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpdateRefundStatusAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("refunds/{refundRequestId:guid}/events")] [EndpointSummary("查询退款事件")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> RefundEvents( Guid refundRequestId, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetRefundEventsAsync( ResolveActor(), refundRequestId, cancellationToken)); } [HttpGet("reconciliation/batches")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询对账批次")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> ReconciliationBatches( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetReconciliationBatchesAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpPost("reconciliation/batches")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("创建对账批次")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateReconciliationBatch( CreateReconciliationBatchDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.CreateReconciliationBatchAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("reconciliation/issues")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("查询对账异常")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> ReconciliationIssues( [FromQuery] TenantCommerceQueryDto query, CancellationToken cancellationToken) { return Ok(await commerceAdminService.GetReconciliationIssuesAsync( ResolveActor(), ToQuery(query), cancellationToken)); } [HttpPost("reconciliation/issues/status")] [Authorize(Policy = TikuPolicies.TenantCommerceOperateAllScope)] [EndpointSummary("更新对账异常状态")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpdateReconciliationIssue( UpdateReconciliationIssueDto request, CancellationToken cancellationToken) { return Ok(await commerceAdminService.UpdateReconciliationIssueAsync( ResolveActor(), request.ToCommand(), cancellationToken)); } private CommerceAdminActor ResolveActor() { if (currentTenant.TenantId is null || currentUser.UserId is null) { throw new CommerceException("Tenant commerce actor was not resolved.", "tenant_admin_access_denied"); } return new CommerceAdminActor(currentTenant.TenantId.Value, currentUser.UserId.Value); } private static CommerceAdminQuery ToQuery(TenantCommerceQueryDto query) { return new CommerceAdminQuery(query.Provider, query.Status, query.Limit); } private static TenantPointQuery ToPointQuery(TenantCommerceQueryDto query) { return new TenantPointQuery(query.Status, query.Limit, query.UserId, query.RegionId); } }