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.Ids; namespace TakeoutSaaS.Application.App.Orders.Handlers; /// /// 创建订单命令处理器。 /// public sealed class CreateOrderCommandHandler( IOrderRepository orderRepository, IIdGenerator idGenerator, ILogger logger) : IRequestHandler { private readonly IOrderRepository _orderRepository = orderRepository; private readonly IIdGenerator _idGenerator = idGenerator; private readonly ILogger _logger = logger; /// public async Task Handle(CreateOrderCommand request, CancellationToken cancellationToken) { // 1. 构建订单 var order = new Order { Id = _idGenerator.NextId(), OrderNo = request.OrderNo.Trim(), StoreId = request.StoreId, Channel = request.Channel, DeliveryType = request.DeliveryType, Status = request.Status, PaymentStatus = request.PaymentStatus, CustomerName = request.CustomerName?.Trim(), CustomerPhone = request.CustomerPhone?.Trim(), TableNo = request.TableNo?.Trim(), QueueNumber = request.QueueNumber?.Trim(), ReservationId = request.ReservationId, ItemsAmount = request.ItemsAmount, DiscountAmount = request.DiscountAmount, PayableAmount = request.PayableAmount, PaidAmount = request.PaidAmount, PaidAt = request.PaidAt, FinishedAt = request.FinishedAt, CancelledAt = request.CancelledAt, CancelReason = request.CancelReason?.Trim(), Remark = request.Remark?.Trim() }; // 2. 构建明细 var items = request.Items.Select(item => new OrderItem { OrderId = order.Id, ProductId = item.ProductId, ProductName = item.ProductName.Trim(), SkuName = item.SkuName?.Trim(), Unit = item.Unit?.Trim(), Quantity = item.Quantity, UnitPrice = item.UnitPrice, DiscountAmount = item.DiscountAmount, SubTotal = item.SubTotal, AttributesJson = item.AttributesJson?.Trim() }).ToList(); // 3. 补充金额字段 if (items.Count > 0) { var itemsAmount = items.Sum(x => x.SubTotal); order.ItemsAmount = itemsAmount; if (order.PayableAmount <= 0) { order.PayableAmount = itemsAmount - order.DiscountAmount; } } // 4. 持久化 await _orderRepository.AddOrderAsync(order, cancellationToken); if (items.Count > 0) { await _orderRepository.AddItemsAsync(items, cancellationToken); } await _orderRepository.SaveChangesAsync(cancellationToken); _logger.LogInformation("创建订单 {OrderNo} ({OrderId})", order.OrderNo, order.Id); // 5. 返回 DTO return MapToDto(order, items, [], []); } 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() }; }