From a035334c94df07376efbc2780b3c902ec53f00d0 Mon Sep 17 00:00:00 2001 From: MSuMshk <2039814060@qq.com> Date: Thu, 29 Jan 2026 13:11:09 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E4=BB=98=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E6=94=AF=E6=8C=81tenantId=E5=8F=AF=E9=80=89=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/PaymentsController.cs | 2 ++ .../Handlers/CreatePaymentCommandHandler.cs | 28 ++++++++++++---- .../Handlers/DeletePaymentCommandHandler.cs | 17 ++++------ .../Handlers/GetPaymentByIdQueryHandler.cs | 14 +++----- .../Handlers/SearchPaymentsQueryHandler.cs | 14 ++++---- .../Handlers/UpdatePaymentCommandHandler.cs | 21 ++++++------ .../Payments/Queries/SearchPaymentsQuery.cs | 5 +++ .../Repositories/IPaymentRepository.cs | 17 ++++++++++ .../App/Repositories/EfPaymentRepository.cs | 32 +++++++++++++++++++ 9 files changed, 103 insertions(+), 47 deletions(-) diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs index 287f893..f299623 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs @@ -44,6 +44,7 @@ public sealed class PaymentsController(IMediator mediator) : BaseApiController [PermissionAuthorize("payment:read")] [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] public async Task>> List( + [FromQuery] long? tenantId, [FromQuery] long? orderId, [FromQuery] PaymentStatus? status, [FromQuery] int page = 1, @@ -55,6 +56,7 @@ public sealed class PaymentsController(IMediator mediator) : BaseApiController // 1. 组装查询参数并执行查询 var result = await mediator.Send(new SearchPaymentsQuery { + TenantId = tenantId, OrderId = orderId, Status = status, Page = page, diff --git a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/CreatePaymentCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/CreatePaymentCommandHandler.cs index 793a2a9..59f4d04 100644 --- a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/CreatePaymentCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/CreatePaymentCommandHandler.cs @@ -2,25 +2,37 @@ using MediatR; using Microsoft.Extensions.Logging; using TakeoutSaaS.Application.App.Payments.Commands; using TakeoutSaaS.Application.App.Payments.Dto; +using TakeoutSaaS.Domain.Orders.Repositories; using TakeoutSaaS.Domain.Payments.Entities; using TakeoutSaaS.Domain.Payments.Repositories; +using TakeoutSaaS.Shared.Abstractions.Constants; +using TakeoutSaaS.Shared.Abstractions.Exceptions; namespace TakeoutSaaS.Application.App.Payments.Handlers; /// /// 创建支付记录命令处理器。 /// -public sealed class CreatePaymentCommandHandler(IPaymentRepository paymentRepository, ILogger logger) +public sealed class CreatePaymentCommandHandler( + IPaymentRepository paymentRepository, + IOrderRepository orderRepository, + ILogger logger) : IRequestHandler { - private readonly IPaymentRepository _paymentRepository = paymentRepository; - private readonly ILogger _logger = logger; - /// public async Task Handle(CreatePaymentCommand request, CancellationToken cancellationToken) { + // 1. 查询订单以确定租户 + var order = await orderRepository.FindByIdAsync(request.OrderId, cancellationToken); + if (order is null) + { + throw new BusinessException(ErrorCodes.NotFound, "订单不存在"); + } + + // 2. (空行后) 构建支付记录并写入租户 var payment = new PaymentRecord { + TenantId = order.TenantId, OrderId = request.OrderId, Method = request.Method, Status = request.Status, @@ -32,10 +44,12 @@ public sealed class CreatePaymentCommandHandler(IPaymentRepository paymentReposi Payload = request.Payload }; - await _paymentRepository.AddPaymentAsync(payment, cancellationToken); - await _paymentRepository.SaveChangesAsync(cancellationToken); - _logger.LogInformation("创建支付记录 {PaymentId} 对应订单 {OrderId}", payment.Id, payment.OrderId); + // 3. (空行后) 持久化 + await paymentRepository.AddPaymentAsync(payment, cancellationToken); + await paymentRepository.SaveChangesAsync(cancellationToken); + logger.LogInformation("创建支付记录 {PaymentId} 对应订单 {OrderId}", payment.Id, payment.OrderId); + // 4. (空行后) 返回 DTO return MapToDto(payment, []); } diff --git a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/DeletePaymentCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/DeletePaymentCommandHandler.cs index 07b2ca9..935ed6f 100644 --- a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/DeletePaymentCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/DeletePaymentCommandHandler.cs @@ -2,7 +2,6 @@ using MediatR; using Microsoft.Extensions.Logging; using TakeoutSaaS.Application.App.Payments.Commands; using TakeoutSaaS.Domain.Payments.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Payments.Handlers; @@ -11,27 +10,23 @@ namespace TakeoutSaaS.Application.App.Payments.Handlers; /// public sealed class DeletePaymentCommandHandler( IPaymentRepository paymentRepository, - ITenantProvider tenantProvider, ILogger logger) : IRequestHandler { - private readonly IPaymentRepository _paymentRepository = paymentRepository; - private readonly ITenantProvider _tenantProvider = tenantProvider; - private readonly ILogger _logger = logger; - /// public async Task Handle(DeletePaymentCommand request, CancellationToken cancellationToken) { - var tenantId = _tenantProvider.GetCurrentTenantId(); - var existing = await _paymentRepository.FindByIdAsync(request.PaymentId, tenantId, cancellationToken); + // 1. 查询支付记录(跨租户) + var existing = await paymentRepository.FindByIdAsync(request.PaymentId, cancellationToken); if (existing == null) { return false; } - await _paymentRepository.DeletePaymentAsync(request.PaymentId, tenantId, cancellationToken); - await _paymentRepository.SaveChangesAsync(cancellationToken); - _logger.LogInformation("删除支付记录 {PaymentId}", request.PaymentId); + // 2. (空行后) 删除并持久化(按支付租户) + await paymentRepository.DeletePaymentAsync(request.PaymentId, existing.TenantId, cancellationToken); + await paymentRepository.SaveChangesAsync(cancellationToken); + logger.LogInformation("删除支付记录 {PaymentId}", request.PaymentId); return true; } diff --git a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/GetPaymentByIdQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/GetPaymentByIdQueryHandler.cs index 8e5db7a..8cd34a1 100644 --- a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/GetPaymentByIdQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/GetPaymentByIdQueryHandler.cs @@ -3,7 +3,6 @@ using TakeoutSaaS.Application.App.Payments.Dto; using TakeoutSaaS.Application.App.Payments.Queries; using TakeoutSaaS.Domain.Payments.Entities; using TakeoutSaaS.Domain.Payments.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Payments.Handlers; @@ -11,24 +10,21 @@ namespace TakeoutSaaS.Application.App.Payments.Handlers; /// 支付记录详情查询处理器。 /// public sealed class GetPaymentByIdQueryHandler( - IPaymentRepository paymentRepository, - ITenantProvider tenantProvider) + IPaymentRepository paymentRepository) : IRequestHandler { - private readonly IPaymentRepository _paymentRepository = paymentRepository; - private readonly ITenantProvider _tenantProvider = tenantProvider; - /// public async Task Handle(GetPaymentByIdQuery request, CancellationToken cancellationToken) { - var tenantId = _tenantProvider.GetCurrentTenantId(); - var payment = await _paymentRepository.FindByIdAsync(request.PaymentId, tenantId, cancellationToken); + // 1. 查询支付记录(跨租户) + var payment = await paymentRepository.FindByIdAsync(request.PaymentId, cancellationToken); if (payment == null) { return null; } - var refunds = await _paymentRepository.GetRefundsAsync(payment.Id, tenantId, cancellationToken); + // 2. (空行后) 查询退款记录(按支付租户) + var refunds = await paymentRepository.GetRefundsAsync(payment.Id, payment.TenantId, cancellationToken); return MapToDto(payment, refunds); } diff --git a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/SearchPaymentsQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/SearchPaymentsQueryHandler.cs index a265022..dcf5b9b 100644 --- a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/SearchPaymentsQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/SearchPaymentsQueryHandler.cs @@ -3,7 +3,6 @@ using TakeoutSaaS.Application.App.Payments.Dto; using TakeoutSaaS.Application.App.Payments.Queries; using TakeoutSaaS.Domain.Payments.Repositories; using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Payments.Handlers; @@ -11,30 +10,29 @@ namespace TakeoutSaaS.Application.App.Payments.Handlers; /// 支付记录列表查询处理器。 /// public sealed class SearchPaymentsQueryHandler( - IPaymentRepository paymentRepository, - ITenantProvider tenantProvider) + IPaymentRepository paymentRepository) : IRequestHandler> { - private readonly IPaymentRepository _paymentRepository = paymentRepository; - private readonly ITenantProvider _tenantProvider = tenantProvider; - /// public async Task> Handle(SearchPaymentsQuery request, CancellationToken cancellationToken) { - var tenantId = _tenantProvider.GetCurrentTenantId(); - var payments = await _paymentRepository.SearchAsync(tenantId, request.Status, cancellationToken); + // 1. 查询支付记录(可选租户过滤) + var payments = await paymentRepository.SearchAsync(request.TenantId, request.Status, cancellationToken); + // 2. (空行后) 可选过滤:订单 if (request.OrderId.HasValue) { payments = payments.Where(x => x.OrderId == request.OrderId.Value).ToList(); } + // 3. (空行后) 排序与分页 var sorted = ApplySorting(payments, request.SortBy, request.SortDescending); var paged = sorted .Skip((request.Page - 1) * request.PageSize) .Take(request.PageSize) .ToList(); + // 4. (空行后) 映射 DTO 并返回分页结果 var items = paged.Select(payment => new PaymentDto { Id = payment.Id, diff --git a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/UpdatePaymentCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/UpdatePaymentCommandHandler.cs index e0e9fec..750f2d1 100644 --- a/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/UpdatePaymentCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Payments/Handlers/UpdatePaymentCommandHandler.cs @@ -4,7 +4,6 @@ using TakeoutSaaS.Application.App.Payments.Commands; using TakeoutSaaS.Application.App.Payments.Dto; using TakeoutSaaS.Domain.Payments.Entities; using TakeoutSaaS.Domain.Payments.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Payments.Handlers; @@ -13,24 +12,20 @@ namespace TakeoutSaaS.Application.App.Payments.Handlers; /// public sealed class UpdatePaymentCommandHandler( IPaymentRepository paymentRepository, - ITenantProvider tenantProvider, ILogger logger) : IRequestHandler { - private readonly IPaymentRepository _paymentRepository = paymentRepository; - private readonly ITenantProvider _tenantProvider = tenantProvider; - private readonly ILogger _logger = logger; - /// public async Task Handle(UpdatePaymentCommand request, CancellationToken cancellationToken) { - var tenantId = _tenantProvider.GetCurrentTenantId(); - var existing = await _paymentRepository.FindByIdAsync(request.PaymentId, tenantId, cancellationToken); + // 1. 查询支付记录(跨租户) + var existing = await paymentRepository.FindByIdAsync(request.PaymentId, cancellationToken); if (existing == null) { return null; } + // 2. (空行后) 更新字段 existing.OrderId = request.OrderId; existing.Method = request.Method; existing.Status = request.Status; @@ -41,11 +36,13 @@ public sealed class UpdatePaymentCommandHandler( existing.Remark = request.Remark?.Trim(); existing.Payload = request.Payload; - await _paymentRepository.UpdatePaymentAsync(existing, cancellationToken); - await _paymentRepository.SaveChangesAsync(cancellationToken); - _logger.LogInformation("更新支付记录 {PaymentId}", existing.Id); + // 3. (空行后) 持久化 + await paymentRepository.UpdatePaymentAsync(existing, cancellationToken); + await paymentRepository.SaveChangesAsync(cancellationToken); + logger.LogInformation("更新支付记录 {PaymentId}", existing.Id); - var refunds = await _paymentRepository.GetRefundsAsync(existing.Id, tenantId, cancellationToken); + // 4. (空行后) 查询退款记录并返回 + var refunds = await paymentRepository.GetRefundsAsync(existing.Id, existing.TenantId, cancellationToken); return MapToDto(existing, refunds); } diff --git a/src/Application/TakeoutSaaS.Application/App/Payments/Queries/SearchPaymentsQuery.cs b/src/Application/TakeoutSaaS.Application/App/Payments/Queries/SearchPaymentsQuery.cs index 2fbf13f..c99daad 100644 --- a/src/Application/TakeoutSaaS.Application/App/Payments/Queries/SearchPaymentsQuery.cs +++ b/src/Application/TakeoutSaaS.Application/App/Payments/Queries/SearchPaymentsQuery.cs @@ -10,6 +10,11 @@ namespace TakeoutSaaS.Application.App.Payments.Queries; /// public sealed class SearchPaymentsQuery : IRequest> { + /// + /// 租户 ID(可选,空表示跨租户查询)。 + /// + public long? TenantId { get; init; } + /// /// 订单 ID(可选)。 /// diff --git a/src/Domain/TakeoutSaaS.Domain/Payments/Repositories/IPaymentRepository.cs b/src/Domain/TakeoutSaaS.Domain/Payments/Repositories/IPaymentRepository.cs index 7983a5a..4a7d5c7 100644 --- a/src/Domain/TakeoutSaaS.Domain/Payments/Repositories/IPaymentRepository.cs +++ b/src/Domain/TakeoutSaaS.Domain/Payments/Repositories/IPaymentRepository.cs @@ -17,6 +17,14 @@ public interface IPaymentRepository /// 支付记录或 null。 Task FindByIdAsync(long paymentId, long tenantId, CancellationToken cancellationToken = default); + /// + /// 依据标识获取支付记录(跨租户)。 + /// + /// 支付记录 ID。 + /// 取消标记。 + /// 支付记录或 null。 + Task FindByIdAsync(long paymentId, CancellationToken cancellationToken = default); + /// /// 依据订单标识获取支付记录。 /// @@ -67,6 +75,15 @@ public interface IPaymentRepository /// 支付记录列表。 Task> SearchAsync(long tenantId, PaymentStatus? status, CancellationToken cancellationToken = default); + /// + /// 按状态筛选支付记录(可选租户过滤)。 + /// + /// 租户 ID(可选,空表示跨租户查询)。 + /// 支付状态。 + /// 取消标记。 + /// 支付记录列表。 + Task> SearchAsync(long? tenantId, PaymentStatus? status, CancellationToken cancellationToken = default); + /// /// 更新支付记录。 /// diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfPaymentRepository.cs b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfPaymentRepository.cs index 323656f..486a88a 100644 --- a/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfPaymentRepository.cs +++ b/src/Infrastructure/TakeoutSaaS.Infrastructure/App/Repositories/EfPaymentRepository.cs @@ -23,6 +23,16 @@ public sealed class EfPaymentRepository(TakeoutAdminDbContext context) : IPaymen .FirstOrDefaultAsync(cancellationToken); } + /// + public Task FindByIdAsync(long paymentId, CancellationToken cancellationToken = default) + { + // 1. 按主键查询(跨租户) + return context.PaymentRecords + .AsNoTracking() + .Where(x => x.Id == paymentId) + .FirstOrDefaultAsync(cancellationToken); + } + /// public Task FindByOrderIdAsync(long orderId, long tenantId, CancellationToken cancellationToken = default) { @@ -73,6 +83,28 @@ public sealed class EfPaymentRepository(TakeoutAdminDbContext context) : IPaymen .ToListAsync(cancellationToken); } + /// + public async Task> SearchAsync(long? tenantId, PaymentStatus? status, CancellationToken cancellationToken = default) + { + // 1. 构建查询(可选租户过滤) + var query = context.PaymentRecords.AsNoTracking(); + if (tenantId.HasValue) + { + query = query.Where(x => x.TenantId == tenantId.Value); + } + + // 2. (空行后) 可选过滤:支付状态 + if (status.HasValue) + { + query = query.Where(x => x.Status == status.Value); + } + + // 3. (空行后) 排序并返回 + return await query + .OrderByDescending(x => x.CreatedAt) + .ToListAsync(cancellationToken); + } + /// public Task SaveChangesAsync(CancellationToken cancellationToken = default) {