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