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()
};
}