using Fengling.Backend.Domain.AggregatesModel.RedemptionOrderAggregate; using Fengling.Backend.Domain.AggregatesModel.GiftAggregate; using Fengling.Backend.Domain.AggregatesModel.MemberAggregate; using Fengling.Backend.Infrastructure.Repositories; namespace Fengling.Backend.Web.Application.Commands.RedemptionOrders; /// /// 创建兑换订单命令 /// public record CreateRedemptionOrderCommand( MemberId MemberId, GiftId GiftId, int Quantity, CreateRedemptionOrderAddressDto? ShippingAddress = null) : ICommand; public record CreateRedemptionOrderAddressDto( string ReceiverName, string Phone, string Province, string City, string District, string DetailAddress); public class CreateRedemptionOrderCommandHandler( IRedemptionOrderRepository redemptionOrderRepository, IGiftRepository giftRepository, IMemberRepository memberRepository) : ICommandHandler { public async Task Handle(CreateRedemptionOrderCommand request, CancellationToken cancellationToken) { // 1. 获取礼品信息 var gift = await giftRepository.GetByIdAsync(request.GiftId, cancellationToken); if (gift == null) throw new KnownException("礼品不存在"); if (!gift.IsOnShelf) throw new KnownException("礼品已下架"); // 2. 检查库存 if (gift.AvailableStock < request.Quantity) throw new KnownException($"库存不足,当前可用:{gift.AvailableStock}"); // 3. 检查限兑数量 if (gift.LimitPerMember.HasValue) { var redeemedCount = await redemptionOrderRepository.GetMemberRedemptionCountAsync( request.MemberId.Id, request.GiftId.Id, cancellationToken); if (redeemedCount + request.Quantity > gift.LimitPerMember.Value) throw new KnownException($"超出限兑数量,每人限兑{gift.LimitPerMember.Value}个,已兑换{redeemedCount}个"); } // 4. 获取会员信息并检查积分 var member = await memberRepository.GetAsync(request.MemberId, cancellationToken); if (member == null) throw new KnownException("会员不存在"); var consumedPoints = gift.RequiredPoints * request.Quantity; if (member.AvailablePoints < consumedPoints) throw new KnownException($"积分不足,需要{consumedPoints}分,当前{member.AvailablePoints}分"); // 5. 扣减积分 member.ConsumePoints(consumedPoints, "兑换礼品", Guid.NewGuid()); await memberRepository.UpdateAsync(member, cancellationToken); // 6. 构造收货地址 Address? shippingAddress = null; if (request.ShippingAddress != null) { shippingAddress = new Address( request.ShippingAddress.ReceiverName, request.ShippingAddress.Phone, request.ShippingAddress.Province, request.ShippingAddress.City, request.ShippingAddress.District, request.ShippingAddress.DetailAddress); } else if (gift.Type == GiftType.Physical) { throw new KnownException("实物礼品必须提供收货地址"); } // 7. 生成订单号 var orderNo = $"RO{DateTime.UtcNow:yyyyMMddHHmmss}{Random.Shared.Next(1000, 9999)}"; // 8. 创建订单 var order = new RedemptionOrder( orderNo, request.MemberId.Id, request.GiftId.Id, gift.Name, (int)gift.Type, request.Quantity, consumedPoints, shippingAddress); await redemptionOrderRepository.AddAsync(order, cancellationToken); return order.Id; } } /// /// 标记订单为已发货命令 /// public record MarkOrderAsDispatchedCommand(RedemptionOrderId OrderId, string? TrackingNo = null) : ICommand; public class MarkOrderAsDispatchedCommandHandler( IRedemptionOrderRepository redemptionOrderRepository) : ICommandHandler { public async Task Handle(MarkOrderAsDispatchedCommand request, CancellationToken cancellationToken) { var order = await redemptionOrderRepository.GetByIdAsync(request.OrderId, cancellationToken); if (order == null) throw new KnownException("订单不存在"); order.MarkAsDispatched(request.TrackingNo); await redemptionOrderRepository.UpdateAsync(order, cancellationToken); return new ResponseData(); } } /// /// 完成订单命令 /// public record CompleteOrderCommand(RedemptionOrderId OrderId) : ICommand; public class CompleteOrderCommandHandler( IRedemptionOrderRepository redemptionOrderRepository) : ICommandHandler { public async Task Handle(CompleteOrderCommand request, CancellationToken cancellationToken) { var order = await redemptionOrderRepository.GetByIdAsync(request.OrderId, cancellationToken); if (order == null) throw new KnownException("订单不存在"); order.Complete(); await redemptionOrderRepository.UpdateAsync(order, cancellationToken); return new ResponseData(); } } /// /// 取消订单命令 /// public record CancelOrderCommand(RedemptionOrderId OrderId, string Reason) : ICommand; public class CancelOrderCommandHandler( IRedemptionOrderRepository redemptionOrderRepository) : ICommandHandler { public async Task Handle(CancelOrderCommand request, CancellationToken cancellationToken) { var order = await redemptionOrderRepository.GetByIdAsync(request.OrderId, cancellationToken); if (order == null) throw new KnownException("订单不存在"); order.Cancel(request.Reason); await redemptionOrderRepository.UpdateAsync(order, cancellationToken); return new ResponseData(); } }