157 lines
5.7 KiB
C#
157 lines
5.7 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// 创建订单命令处理器。
|
|
/// </summary>
|
|
public sealed class CreateOrderCommandHandler(
|
|
IOrderRepository orderRepository,
|
|
IIdGenerator idGenerator,
|
|
ILogger<CreateOrderCommandHandler> logger)
|
|
: IRequestHandler<CreateOrderCommand, OrderDto>
|
|
{
|
|
private readonly IOrderRepository _orderRepository = orderRepository;
|
|
private readonly IIdGenerator _idGenerator = idGenerator;
|
|
private readonly ILogger<CreateOrderCommandHandler> _logger = logger;
|
|
|
|
/// <inheritdoc />
|
|
public async Task<OrderDto> 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<OrderItem> items,
|
|
IReadOnlyList<OrderStatusHistory> histories,
|
|
IReadOnlyList<RefundRequest> 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()
|
|
};
|
|
}
|