using Fake.DependencyInjection; using Oms.Application.Dtos.Marketing; using Oms.Domain.CustomersAggregate.Repositories; using Oms.Domain.MarketingAggregate.Entities; using Oms.Domain.MarketingAggregate.Repositories; using Oms.Domain.OrdersAggregate.Entities; namespace Oms.Application.Shared; /// /// 订单营销快照写入与查价叠加。 /// public class MarketingOrderHelper : IScopedDependency { private readonly ICustomerRepository _customerRepository; private readonly IMemberLevelRepository _memberLevelRepository; private readonly MarketingCouponManager _couponManager; public MarketingOrderHelper( ICustomerRepository customerRepository, IMemberLevelRepository memberLevelRepository, MarketingCouponManager couponManager) { _customerRepository = customerRepository; _memberLevelRepository = memberLevelRepository; _couponManager = couponManager; } public async Task BuildBreakdownAsync( int? customerId, decimal receivableSubtotal, int? couponInstanceId, CancellationToken cancellationToken = default) { return await BuildBreakdownAsync( customerId, receivableSubtotal, receivableSubtotal, couponInstanceId, cancellationToken); } public async Task BuildBreakdownAsync( int? customerId, decimal receivableSubtotal, decimal baseFreightAmount, int? couponInstanceId, CancellationToken cancellationToken = default) { return await BuildBreakdownAsync( customerId, receivableSubtotal, baseFreightAmount, couponInstanceId, null, cancellationToken: cancellationToken); } /// /// 计算会员折/券互斥后的应付拆解; 为当前订单时允许使用被该订单锁定的券。 /// public async Task BuildBreakdownAsync( int? customerId, decimal receivableSubtotal, decimal baseFreightAmount, int? couponInstanceId, string? destinationCountry, int? ownerOrderId = null, CancellationToken cancellationToken = default) { if (!customerId.HasValue || customerId.Value <= 0) { return MarketingBillingCalculator.Calculate( receivableSubtotal, baseFreightAmount, 0M, null, null, null, null); } var sessionCustomer = await _customerRepository.FirstOrDefaultAsync(x => x.Id == customerId.Value, cancellationToken); if (sessionCustomer == null) { return MarketingBillingCalculator.Calculate( receivableSubtotal, baseFreightAmount, 0M, null, null, null, null); } var mainCustomer = await MarketingCustomerHelper.ResolveMarketingMainCustomerAsync(_customerRepository, sessionCustomer, cancellationToken); var mainCustomerId = mainCustomer.Id; MemberLevel? level = null; if (mainCustomer.MemberLevelId.HasValue) { level = await _memberLevelRepository.FirstOrDefaultAsync(x => x.Id == mainCustomer.MemberLevelId.Value, cancellationToken); } var priceTierKey = MarketingCustomerHelper.NormalizePriceTierKeyOrDefault(mainCustomer.PriceTierKey); var couponInput = await _couponManager.ResolveCouponDiscountInputAsync( couponInstanceId, mainCustomerId, destinationCountry, ownerOrderId, cancellationToken); return MarketingBillingCalculator.Calculate( receivableSubtotal, baseFreightAmount, level?.ExtraDiscountRate ?? 0M, level?.Id, level?.LevelName, priceTierKey, couponInput); } public void ApplySnapshotToOrder(Order order, MarketingPriceBreakdown breakdown, int? couponInstanceId) { order.MemberLevelId = breakdown.MemberLevelId; order.PriceTierKey = breakdown.PriceTierKey; order.ReceivableSubtotal = breakdown.ReceivableSubtotal; order.LevelDiscountAmount = breakdown.LevelDiscountAmount; order.CouponInstanceId = couponInstanceId ?? breakdown.CouponInstanceId; order.CouponDiscountAmount = breakdown.CouponDiscountAmount; order.PayableAmount = breakdown.PayableAmount; } public async Task> BuildAvailableCouponsAsync( int? customerId, decimal? baseFreightAmount, string? destinationCountry = null, int? ownerOrderId = null, CancellationToken cancellationToken = default) { if (!customerId.HasValue || customerId.Value <= 0) { return []; } var sessionCustomer = await _customerRepository.FirstOrDefaultAsync(x => x.Id == customerId.Value, cancellationToken); if (sessionCustomer == null) { return []; } var mainCustomer = await MarketingCustomerHelper.ResolveMarketingMainCustomerAsync( _customerRepository, sessionCustomer, cancellationToken); return await _couponManager.BuildAvailableCouponsAsync( mainCustomer.Id, baseFreightAmount, destinationCountry, ownerOrderId, cancellationToken); } }