using MediatR; using Microsoft.Extensions.Logging; using TakeoutSaaS.Application.App.Orders.Commands; using TakeoutSaaS.Application.App.Orders.Dto; using TakeoutSaaS.Domain.Orders.Entities; using TakeoutSaaS.Domain.Orders.Repositories; using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Orders.Handlers; /// /// 更新订单命令处理器。 /// public sealed class UpdateOrderCommandHandler( IOrderRepository orderRepository, ITenantProvider tenantProvider, ILogger logger) : IRequestHandler { /// public async Task Handle(UpdateOrderCommand request, CancellationToken cancellationToken) { // 1. 读取订单 var tenantId = tenantProvider.GetCurrentTenantId(); var existing = await orderRepository.FindByIdAsync(request.OrderId, tenantId, cancellationToken); if (existing == null) { return null; } // 2. 更新字段 existing.OrderNo = request.OrderNo.Trim(); existing.StoreId = request.StoreId; existing.Channel = request.Channel; existing.DeliveryType = request.DeliveryType; existing.Status = request.Status; existing.PaymentStatus = request.PaymentStatus; existing.CustomerName = request.CustomerName?.Trim(); existing.CustomerPhone = request.CustomerPhone?.Trim(); existing.TableNo = request.TableNo?.Trim(); existing.QueueNumber = request.QueueNumber?.Trim(); existing.ReservationId = request.ReservationId; existing.ItemsAmount = request.ItemsAmount; existing.DiscountAmount = request.DiscountAmount; existing.PayableAmount = request.PayableAmount; existing.PaidAmount = request.PaidAmount; existing.PaidAt = request.PaidAt; existing.FinishedAt = request.FinishedAt; existing.CancelledAt = request.CancelledAt; existing.CancelReason = request.CancelReason?.Trim(); existing.Remark = request.Remark?.Trim(); // 3. 持久化 await orderRepository.UpdateOrderAsync(existing, cancellationToken); await orderRepository.SaveChangesAsync(cancellationToken); // 4. 记录更新日志 logger.LogInformation("更新订单 {OrderNo} ({OrderId})", existing.OrderNo, existing.Id); // 5. 读取关联数据并返回 var items = await orderRepository.GetItemsAsync(existing.Id, tenantId, cancellationToken); var histories = await orderRepository.GetStatusHistoryAsync(existing.Id, tenantId, cancellationToken); var refunds = await orderRepository.GetRefundsAsync(existing.Id, tenantId, cancellationToken); return MapToDto(existing, items, histories, refunds); } private static OrderDto MapToDto( Order order, IReadOnlyList items, IReadOnlyList histories, IReadOnlyList refunds) => new() { Id = order.Id, TenantId = order.TenantId, OrderNo = order.OrderNo, StoreId = order.StoreId, Channel = order.Channel, DeliveryType = order.DeliveryType, Status = order.Status, PaymentStatus = order.PaymentStatus, CustomerName = order.CustomerName, CustomerPhone = order.CustomerPhone, TableNo = order.TableNo, QueueNumber = order.QueueNumber, ReservationId = order.ReservationId, ItemsAmount = order.ItemsAmount, DiscountAmount = order.DiscountAmount, PayableAmount = order.PayableAmount, PaidAmount = order.PaidAmount, PaidAt = order.PaidAt, FinishedAt = order.FinishedAt, CancelledAt = order.CancelledAt, CancelReason = order.CancelReason, Remark = order.Remark, Items = items.Select(x => new OrderItemDto { Id = x.Id, OrderId = x.OrderId, ProductId = x.ProductId, ProductName = x.ProductName, SkuName = x.SkuName, Unit = x.Unit, Quantity = x.Quantity, UnitPrice = x.UnitPrice, DiscountAmount = x.DiscountAmount, SubTotal = x.SubTotal, AttributesJson = x.AttributesJson }).ToList(), StatusHistory = histories.Select(x => new OrderStatusHistoryDto { Id = x.Id, OrderId = x.OrderId, Status = x.Status, OperatorId = x.OperatorId, Notes = x.Notes, OccurredAt = x.OccurredAt }).ToList(), Refunds = refunds.Select(x => new RefundRequestDto { Id = x.Id, OrderId = x.OrderId, RefundNo = x.RefundNo, Amount = x.Amount, Reason = x.Reason, Status = x.Status, RequestedAt = x.RequestedAt, ProcessedAt = x.ProcessedAt, ReviewNotes = x.ReviewNotes }).ToList(), CreatedAt = order.CreatedAt }; }