feat: 订单支付时选券,新增支付预览接口并按所选券扣款核销
All checks were successful
Build and Deploy / deploy (push) Successful in 1m3s
All checks were successful
Build and Deploy / deploy (push) Successful in 1m3s
- 新增 GET /order/pay-preview:返回会员折/券互斥后的应付拆解与本单可选券 - POST /order/pay 支持 couponInstanceId(null 沿用已绑定券,0 不用券,>0 指定券),按试算应付扣款并核销券、释放被替换券的锁定 - 被当前订单锁定的券视为可用,修复入库/编辑重算营销金额时误报券被占用 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
983dff12c5
commit
223d32f62a
81
src/Oms.Application/Dtos/Orders/OrderPayDtos.cs
Normal file
81
src/Oms.Application/Dtos/Orders/OrderPayDtos.cs
Normal file
@ -0,0 +1,81 @@
|
||||
using Oms.Application.Dtos.Marketing;
|
||||
|
||||
namespace Oms.Application.Dtos.Orders;
|
||||
|
||||
/// <summary>
|
||||
/// 订单支付入参(支付时选券)。
|
||||
/// </summary>
|
||||
public class OrderPayInput : OrderActionInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 选用的优惠券实例 Id:null 沿用订单已绑定的券(不可用则不使用);0 不使用券;大于 0 使用指定券。
|
||||
/// </summary>
|
||||
public int? CouponInstanceId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 订单支付预览入参。
|
||||
/// </summary>
|
||||
public class OrderPayPreviewInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订单主键。
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 试算用券:null 自动推荐(优先已绑定券,否则选优惠最大且优于会员折的券);0 不使用券;大于 0 使用指定券。
|
||||
/// </summary>
|
||||
public int? CouponInstanceId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 订单支付预览:应付拆解与可选券。
|
||||
/// </summary>
|
||||
public class OrderPayPreviewOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 订单主键。
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应收小计(折前)。
|
||||
/// </summary>
|
||||
public decimal ReceivableSubtotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 基础运费(券门槛与抵扣口径)。
|
||||
/// </summary>
|
||||
public decimal BaseFreightAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会员折扣金额(与券互斥,用券时为 0)。
|
||||
/// </summary>
|
||||
public decimal LevelDiscountAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 优惠券抵扣金额。
|
||||
/// </summary>
|
||||
public decimal CouponDiscountAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实际应付金额(支付扣款金额)。
|
||||
/// </summary>
|
||||
public decimal PayableAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 会员等级名称。
|
||||
/// </summary>
|
||||
public string? MemberLevelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 本次试算实际生效的券实例 Id;为空表示未用券。
|
||||
/// </summary>
|
||||
public int? AppliedCouponInstanceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前客户可选券(CanUse=false 时附不可用原因,含「优惠不高于会员折扣」)。
|
||||
/// </summary>
|
||||
public List<CouponAvailableOutput> AvailableCoupons { get; set; } = [];
|
||||
}
|
||||
@ -11,7 +11,7 @@ namespace Oms.Application.Services.Orders;
|
||||
public partial class OrderService
|
||||
{
|
||||
internal Task PayForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
||||
PayAsync(new OrderActionInput { Id = orderId });
|
||||
PayAsync(new OrderPayInput { Id = orderId });
|
||||
|
||||
internal Task PreDeclareForBatchAsync(int orderId, CancellationToken cancellationToken = default) =>
|
||||
PreDeclareAsync(new OrderActionInput { Id = orderId });
|
||||
|
||||
@ -3378,7 +3378,8 @@ public partial class OrderService
|
||||
receivableSubtotal,
|
||||
baseFreightAmount,
|
||||
order.CouponInstanceId,
|
||||
order.ConsigneeCountry);
|
||||
order.ConsigneeCountry,
|
||||
order.Id);
|
||||
marketingHelper.ApplySnapshotToOrder(order, breakdown, order.CouponInstanceId);
|
||||
}
|
||||
|
||||
|
||||
142
src/Oms.Application/Services/Orders/OrderService.PayCoupon.cs
Normal file
142
src/Oms.Application/Services/Orders/OrderService.PayCoupon.cs
Normal file
@ -0,0 +1,142 @@
|
||||
using Fake.Application;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oms.Application.Dtos.Marketing;
|
||||
using Oms.Application.Dtos.Orders;
|
||||
using Oms.Application.Shared;
|
||||
using Oms.Domain.OrdersAggregate.Entities;
|
||||
|
||||
namespace Oms.Application.Services.Orders;
|
||||
|
||||
public partial class OrderService
|
||||
{
|
||||
private const string CouponNotBetterThanLevelReason = "优惠不高于会员折扣";
|
||||
|
||||
/// <summary>
|
||||
/// 支付预览:按当前应收计算会员折/券互斥后的应付,并返回本单可选券。
|
||||
/// </summary>
|
||||
/// <param name="input">入参:订单 Id;couponInstanceId 为 null 自动推荐,0 不用券,大于 0 试算指定券。</param>
|
||||
/// <returns>应付拆解、实际生效券与可选券列表;指定券不可用(未解锁/过期/线路不符等)时抛业务异常。</returns>
|
||||
[HttpGet("/order/pay-preview")]
|
||||
public async Task<OrderPayPreviewOutput> GetPayPreviewAsync([FromQuery] OrderPayPreviewInput input)
|
||||
{
|
||||
var order = await GetOrderOrThrowAsync(input.Id);
|
||||
var fees = await OrderRepository.GetFeesByOrderIdsAsync([order.Id]);
|
||||
var receivableSubtotal = MarketingFeeHelper.SumReceivable(fees);
|
||||
var baseFreightAmount = MarketingFeeHelper.SumReceivableBaseFreight(fees);
|
||||
var marketingHelper = LazyServiceProvider.GetRequiredService<MarketingOrderHelper>();
|
||||
|
||||
var memberOnly = await marketingHelper.BuildBreakdownAsync(
|
||||
order.CustomerId,
|
||||
receivableSubtotal,
|
||||
baseFreightAmount,
|
||||
null,
|
||||
order.ConsigneeCountry,
|
||||
order.Id);
|
||||
var coupons = await marketingHelper.BuildAvailableCouponsAsync(
|
||||
order.CustomerId,
|
||||
baseFreightAmount,
|
||||
order.ConsigneeCountry,
|
||||
order.Id);
|
||||
foreach (var coupon in coupons.Where(x => x.CanUse
|
||||
&& (x.EstimatedDiscount ?? 0M) <= memberOnly.LevelDiscountAmount))
|
||||
{
|
||||
coupon.CanUse = false;
|
||||
coupon.UnavailableReason = CouponNotBetterThanLevelReason;
|
||||
}
|
||||
|
||||
coupons = coupons
|
||||
.OrderByDescending(x => x.CanUse)
|
||||
.ThenByDescending(x => x.EstimatedDiscount ?? 0M)
|
||||
.ThenBy(x => x.ValidEndTime)
|
||||
.ToList();
|
||||
|
||||
var targetCouponId = input.CouponInstanceId switch
|
||||
{
|
||||
0 => null,
|
||||
> 0 => input.CouponInstanceId,
|
||||
_ => ResolveRecommendedPayCouponId(order, coupons)
|
||||
};
|
||||
|
||||
var breakdown = targetCouponId.HasValue
|
||||
? await marketingHelper.BuildBreakdownAsync(
|
||||
order.CustomerId,
|
||||
receivableSubtotal,
|
||||
baseFreightAmount,
|
||||
targetCouponId,
|
||||
order.ConsigneeCountry,
|
||||
order.Id)
|
||||
: memberOnly;
|
||||
|
||||
return new OrderPayPreviewOutput
|
||||
{
|
||||
Id = order.Id,
|
||||
ReceivableSubtotal = breakdown.ReceivableSubtotal,
|
||||
BaseFreightAmount = breakdown.BaseFreightAmount,
|
||||
LevelDiscountAmount = breakdown.LevelDiscountAmount,
|
||||
CouponDiscountAmount = breakdown.CouponDiscountAmount,
|
||||
PayableAmount = breakdown.PayableAmount,
|
||||
MemberLevelName = breakdown.MemberLevelName,
|
||||
AppliedCouponInstanceId = breakdown.CouponInstanceId,
|
||||
AvailableCoupons = coupons
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算支付应付:couponInstanceId 为 null 沿用订单已绑定券(不可用则不用券),0 不用券,大于 0 使用指定券。
|
||||
/// </summary>
|
||||
private async Task<MarketingPriceBreakdown> BuildPayBreakdownAsync(
|
||||
Order order,
|
||||
IEnumerable<OrderFee> fees,
|
||||
int? couponInstanceId)
|
||||
{
|
||||
var feeList = fees as IList<OrderFee> ?? fees.ToList();
|
||||
var receivableSubtotal = MarketingFeeHelper.SumReceivable(feeList);
|
||||
var baseFreightAmount = MarketingFeeHelper.SumReceivableBaseFreight(feeList);
|
||||
var marketingHelper = LazyServiceProvider.GetRequiredService<MarketingOrderHelper>();
|
||||
|
||||
Task<MarketingPriceBreakdown> Build(int? couponId) =>
|
||||
marketingHelper.BuildBreakdownAsync(
|
||||
order.CustomerId,
|
||||
receivableSubtotal,
|
||||
baseFreightAmount,
|
||||
couponId,
|
||||
order.ConsigneeCountry,
|
||||
order.Id);
|
||||
|
||||
if (couponInstanceId is > 0)
|
||||
{
|
||||
var breakdown = await Build(couponInstanceId);
|
||||
if (breakdown.CouponInstanceId != couponInstanceId)
|
||||
{
|
||||
throw new BusinessException("所选优惠券未达使用门槛或优惠不高于会员折扣,请重新选择");
|
||||
}
|
||||
|
||||
return breakdown;
|
||||
}
|
||||
|
||||
if (couponInstanceId == 0 || order.CouponInstanceId is not > 0)
|
||||
{
|
||||
return await Build(null);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return await Build(order.CouponInstanceId);
|
||||
}
|
||||
catch (BusinessException)
|
||||
{
|
||||
return await Build(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static int? ResolveRecommendedPayCouponId(Order order, List<CouponAvailableOutput> coupons)
|
||||
{
|
||||
if (order.CouponInstanceId is > 0
|
||||
&& coupons.Any(x => x.CanUse && x.CouponInstanceId == order.CouponInstanceId.Value))
|
||||
{
|
||||
return order.CouponInstanceId;
|
||||
}
|
||||
|
||||
return coupons.FirstOrDefault(x => x.CanUse)?.CouponInstanceId;
|
||||
}
|
||||
}
|
||||
@ -127,12 +127,12 @@ public partial class OrderService : ApplicationService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行订单支付。
|
||||
/// 执行订单支付(余额扣款,支持支付时选券)。
|
||||
/// </summary>
|
||||
/// <param name="input">入参:订单操作参数。</param>
|
||||
/// <returns>无返回体,仅完成订单支付处理。</returns>
|
||||
/// <param name="input">入参:订单 Id;couponInstanceId 为 null 沿用已绑定券,0 不用券,大于 0 使用指定券。</param>
|
||||
/// <returns>无返回体;指定券不可用、余额不足或订单状态不可支付时抛业务异常。</returns>
|
||||
[HttpPost("/order/pay")]
|
||||
public async Task PayAsync(OrderActionInput input)
|
||||
public async Task PayAsync(OrderPayInput input)
|
||||
{
|
||||
var order = await GetOrderOrThrowAsync(input.Id);
|
||||
if (order.IsPaid > 0)
|
||||
@ -152,33 +152,42 @@ public partial class OrderService : ApplicationService
|
||||
|
||||
var beforeSnap = await CaptureOrderAuditSnapshotAsync(order);
|
||||
var fees = await OrderRepository.GetFeesByOrderIdsAsync([order.Id]);
|
||||
var payAmount = order.PayableAmount ?? fees
|
||||
.Where(x => x.Type == OrderFeeTypeCodes.Receivable)
|
||||
.Sum(x => x.Amount);
|
||||
if (payAmount <= 0)
|
||||
var breakdown = await BuildPayBreakdownAsync(order, fees, input.CouponInstanceId);
|
||||
if (breakdown.ReceivableSubtotal <= 0)
|
||||
{
|
||||
throw new BusinessException("订单应付金额无效,无法支付");
|
||||
}
|
||||
|
||||
var payAmount = breakdown.PayableAmount;
|
||||
var customer = await CustomerRepository.FirstOrDefaultAsync(x => x.Id == order.CustomerId.Value);
|
||||
if (customer == null)
|
||||
{
|
||||
throw new BusinessException("客户不存在");
|
||||
}
|
||||
|
||||
var balanceMutator = LazyServiceProvider.GetRequiredService<CustomerBalanceMutator>();
|
||||
await balanceMutator.DebitOrderPayAsync(
|
||||
customer,
|
||||
payAmount,
|
||||
order.Id,
|
||||
order.ServiceNo,
|
||||
$"订单支付 {order.ServiceNo}");
|
||||
|
||||
if (order.CouponInstanceId.HasValue)
|
||||
if (payAmount > 0)
|
||||
{
|
||||
var balanceMutator = LazyServiceProvider.GetRequiredService<CustomerBalanceMutator>();
|
||||
await balanceMutator.DebitOrderPayAsync(
|
||||
customer,
|
||||
payAmount,
|
||||
order.Id,
|
||||
order.ServiceNo,
|
||||
$"订单支付 {order.ServiceNo}");
|
||||
}
|
||||
|
||||
var couponManager = LazyServiceProvider.GetRequiredService<MarketingCouponManager>();
|
||||
if (order.CouponInstanceId is > 0 && order.CouponInstanceId != breakdown.CouponInstanceId)
|
||||
{
|
||||
await couponManager.ReleaseLockAsync(order.CouponInstanceId.Value, order.Id);
|
||||
}
|
||||
|
||||
LazyServiceProvider.GetRequiredService<MarketingOrderHelper>()
|
||||
.ApplySnapshotToOrder(order, breakdown, null);
|
||||
if (breakdown.CouponInstanceId.HasValue)
|
||||
{
|
||||
var couponManager = LazyServiceProvider.GetRequiredService<MarketingCouponManager>();
|
||||
var mainCustomerId = await couponManager.ResolveMainCustomerIdAsync(customer.Id);
|
||||
await couponManager.MarkUsedAsync(order.CouponInstanceId.Value, mainCustomerId, order.Id);
|
||||
await couponManager.MarkUsedAsync(breakdown.CouponInstanceId.Value, mainCustomerId, order.Id);
|
||||
}
|
||||
|
||||
var mainCustomer = await MarketingCustomerHelper.ResolveMarketingMainCustomerAsync(CustomerRepository, customer);
|
||||
@ -197,12 +206,15 @@ public partial class OrderService : ApplicationService
|
||||
order = await GetOrderOrThrowAsync(order.Id);
|
||||
var afterSnap = await CaptureOrderAuditSnapshotAsync(order);
|
||||
var amountText = payAmount.ToString("0.####", CultureInfo.InvariantCulture);
|
||||
var couponText = breakdown.CouponDiscountAmount > 0
|
||||
? $",优惠券抵扣 {breakdown.CouponDiscountAmount.ToString("0.####", CultureInfo.InvariantCulture)}"
|
||||
: string.Empty;
|
||||
await OperationLogWriter.TryWriteAsync(
|
||||
order,
|
||||
OrderOperationActionCodes.Pay,
|
||||
beforeSnap,
|
||||
afterSnap,
|
||||
$"支付金额 {amountText}");
|
||||
$"支付金额 {amountText}{couponText}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -314,7 +314,10 @@ public class MarketingCouponManager : IScopedDependency
|
||||
await _instanceRepository.UpdateAsync(instance, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task ReleaseLockAsync(int couponInstanceId, CancellationToken cancellationToken = default)
|
||||
/// <summary>
|
||||
/// 释放券锁定;传 <paramref name="ownerOrderId"/> 时仅释放被该订单锁定的券。
|
||||
/// </summary>
|
||||
public async Task ReleaseLockAsync(int couponInstanceId, int? ownerOrderId = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var instance = await _instanceRepository.FirstOrDefaultAsync(x => x.Id == couponInstanceId, cancellationToken);
|
||||
if (instance == null || instance.Status != CouponInstanceStatus.Locked)
|
||||
@ -322,6 +325,11 @@ public class MarketingCouponManager : IScopedDependency
|
||||
return;
|
||||
}
|
||||
|
||||
if (ownerOrderId.HasValue && instance.OrderId != ownerOrderId.Value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
instance.Status = CouponInstanceStatus.Available;
|
||||
instance.OrderId = null;
|
||||
instance.LockExpireTime = null;
|
||||
@ -383,10 +391,14 @@ public class MarketingCouponManager : IScopedDependency
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解析券抵扣参数;<paramref name="ownerOrderId"/> 为当前订单时,被该订单锁定的券视为可用。
|
||||
/// </summary>
|
||||
public async Task<CouponDiscountInput?> ResolveCouponDiscountInputAsync(
|
||||
int? couponInstanceId,
|
||||
int mainCustomerId,
|
||||
string? destinationCountry = null,
|
||||
int? ownerOrderId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!couponInstanceId.HasValue)
|
||||
@ -395,7 +407,7 @@ public class MarketingCouponManager : IScopedDependency
|
||||
}
|
||||
|
||||
var instance = await GetOwnedInstanceAsync(couponInstanceId.Value, mainCustomerId, cancellationToken);
|
||||
EnsureUsable(instance);
|
||||
EnsureUsable(instance, ownerOrderId);
|
||||
var template = await _templateRepository.FirstOrDefaultAsync(x => x.Id == instance.TemplateId, cancellationToken)
|
||||
?? throw new BusinessException("券模板不存在");
|
||||
if (!MarketingCouponScope.Matches(template.ApplyScopeJson, destinationCountry))
|
||||
@ -422,13 +434,31 @@ public class MarketingCouponManager : IScopedDependency
|
||||
return await MarketingCustomerHelper.ResolveMarketingMainCustomerIdAsync(_customerRepository, customer, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建可选券列表;传 <paramref name="ownerOrderId"/> 时额外包含被该订单锁定且仍在有效期内的券。
|
||||
/// </summary>
|
||||
public async Task<List<CouponAvailableOutput>> BuildAvailableCouponsAsync(
|
||||
int mainCustomerId,
|
||||
decimal? baseFreightAmount,
|
||||
string? destinationCountry = null,
|
||||
int? ownerOrderId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var instances = await _instanceRepository.GetAvailableByCustomerAsync(mainCustomerId, cancellationToken);
|
||||
if (ownerOrderId is > 0)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
var orderId = ownerOrderId.Value;
|
||||
var ownLocked = await _instanceRepository.GetListAsync(
|
||||
x => x.CustomerId == mainCustomerId
|
||||
&& x.Status == CouponInstanceStatus.Locked
|
||||
&& x.OrderId == orderId
|
||||
&& x.ValidStartTime <= now
|
||||
&& x.ValidEndTime >= now);
|
||||
var knownIds = instances.Select(x => x.Id).ToHashSet();
|
||||
instances.AddRange(ownLocked.Where(x => !knownIds.Contains(x.Id)));
|
||||
}
|
||||
|
||||
if (instances.Count == 0)
|
||||
{
|
||||
return [];
|
||||
@ -541,7 +571,7 @@ public class MarketingCouponManager : IScopedDependency
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static void EnsureUsable(CouponInstance instance)
|
||||
private static void EnsureUsable(CouponInstance instance, int? ownerOrderId = null)
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
if (instance.Status == CouponInstanceStatus.PendingUnlock)
|
||||
@ -566,7 +596,8 @@ public class MarketingCouponManager : IScopedDependency
|
||||
|
||||
if (instance.Status == CouponInstanceStatus.Locked
|
||||
&& instance.LockExpireTime.HasValue
|
||||
&& instance.LockExpireTime.Value >= now)
|
||||
&& instance.LockExpireTime.Value >= now
|
||||
&& !(ownerOrderId.HasValue && instance.OrderId == ownerOrderId.Value))
|
||||
{
|
||||
throw new BusinessException("优惠券已被其他订单占用");
|
||||
}
|
||||
|
||||
@ -53,15 +53,19 @@ public class MarketingOrderHelper : IScopedDependency
|
||||
baseFreightAmount,
|
||||
couponInstanceId,
|
||||
null,
|
||||
cancellationToken);
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算会员折/券互斥后的应付拆解;<paramref name="ownerOrderId"/> 为当前订单时允许使用被该订单锁定的券。
|
||||
/// </summary>
|
||||
public async Task<MarketingPriceBreakdown> BuildBreakdownAsync(
|
||||
int? customerId,
|
||||
decimal receivableSubtotal,
|
||||
decimal baseFreightAmount,
|
||||
int? couponInstanceId,
|
||||
string? destinationCountry,
|
||||
int? ownerOrderId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!customerId.HasValue || customerId.Value <= 0)
|
||||
@ -87,7 +91,7 @@ public class MarketingOrderHelper : IScopedDependency
|
||||
|
||||
var priceTierKey = MarketingCustomerHelper.NormalizePriceTierKeyOrDefault(mainCustomer.PriceTierKey);
|
||||
var couponInput = await _couponManager.ResolveCouponDiscountInputAsync(
|
||||
couponInstanceId, mainCustomerId, destinationCountry, cancellationToken);
|
||||
couponInstanceId, mainCustomerId, destinationCountry, ownerOrderId, cancellationToken);
|
||||
|
||||
return MarketingBillingCalculator.Calculate(
|
||||
receivableSubtotal,
|
||||
@ -114,6 +118,7 @@ public class MarketingOrderHelper : IScopedDependency
|
||||
int? customerId,
|
||||
decimal? baseFreightAmount,
|
||||
string? destinationCountry = null,
|
||||
int? ownerOrderId = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!customerId.HasValue || customerId.Value <= 0)
|
||||
@ -132,6 +137,6 @@ public class MarketingOrderHelper : IScopedDependency
|
||||
sessionCustomer,
|
||||
cancellationToken);
|
||||
return await _couponManager.BuildAvailableCouponsAsync(
|
||||
mainCustomer.Id, baseFreightAmount, destinationCountry, cancellationToken);
|
||||
mainCustomer.Id, baseFreightAmount, destinationCountry, ownerOrderId, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user