Split price/remote zone matching in billing and prefer the 全部客户 column for any price tier key. Co-authored-by: Cursor <cursoragent@cursor.com>
620 lines
18 KiB
C#
620 lines
18 KiB
C#
using FluentAssertions;
|
||
using Oms.Application.Dtos.Channels;
|
||
using Oms.Application.Dtos.Orders;
|
||
using Oms.Application.Services.Orders;
|
||
using Oms.Application.Services.Orders.Issues;
|
||
using Oms.Domain.CustomersAggregate.Enums;
|
||
using Oms.Domain.OrdersAggregate.Consts;
|
||
using Oms.Domain.OrdersAggregate.Entities;
|
||
using Oms.Tests.Support;
|
||
|
||
namespace Oms.Tests;
|
||
|
||
/// <summary>
|
||
/// 小包预报应收/应付计费单元测试(与设计文档 §4.4.3.1 续单价示例对齐)。
|
||
/// </summary>
|
||
public class ParcelBillingCalculatorTests
|
||
{
|
||
private const string Zone = "美西";
|
||
private readonly (string PriceVersion, DateTime EffectiveTime) _meta = ParcelBillingTestData.SnapshotMeta();
|
||
|
||
#region 计重
|
||
|
||
[Fact]
|
||
public void CalculateRawBillableWeight_ShouldUseGrossWeightWhenConditionHits()
|
||
{
|
||
var forecast = new OrderWeight
|
||
{
|
||
Length = 30,
|
||
Width = 20,
|
||
Height = 10,
|
||
ActualWeight = 1.5M
|
||
};
|
||
var rules = new[] { ParcelBillingTestData.GwRule() };
|
||
|
||
var (vw, raw) = ParcelBillingCalculator.CalculateRawBillableWeight(forecast, rules);
|
||
|
||
vw.Should().Be(1M);
|
||
raw.Should().Be(1.5M);
|
||
}
|
||
|
||
[Fact]
|
||
public void ApplyRounding_ShouldCeilToConfiguredUnit()
|
||
{
|
||
var ranges = new[] { ParcelBillingTestData.RoundingRange(0, 30, "0.5") };
|
||
|
||
var rounded = ParcelBillingCalculator.ApplyRounding(1.23M, ranges);
|
||
|
||
rounded.Should().Be(1.5M);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 应收(卖价)
|
||
|
||
[Theory]
|
||
[InlineData(0.8, 18)]
|
||
[InlineData(1.2, 24)]
|
||
[InlineData(1.6, 30)]
|
||
public void CalculateForecastReceivableFees_ContinuePrice_ShouldMatchDesignExamples(
|
||
double chargeableWeight,
|
||
decimal expectedFreight)
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.ContinueFreightDetail()));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateForecastReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
(decimal)chargeableWeight,
|
||
Zone,
|
||
"general",
|
||
null);
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Type.Should().Be(OrderFeeTypeCodes.Receivable);
|
||
fees[0].CostItem.Should().Be("freight");
|
||
fees[0].Amount.Should().Be(expectedFreight);
|
||
fees[0].ChargingStage.Should().Be(OrderFeeChargingStageCodes.Forecast);
|
||
fees[0].PriceNo.Should().Be(_meta.PriceVersion);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_ShouldIncludeAllEnabledPriceItems()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.ContinueFreightDetail()));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast);
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].ChargingStage.Should().Be(OrderFeeChargingStageCodes.Forecast);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_InboundStage_ShouldSetChargingStage()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.ContinueFreightDetail()));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Inbound);
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].ChargingStage.Should().Be(OrderFeeChargingStageCodes.Inbound);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateForecastReceivableFees_ShouldIncludeForecastAndFixedPriceItems()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.ContinueFreightDetail()),
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"操作费",
|
||
ParcelBillingTestData.FixedPriceDetail(5M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateForecastReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
0.8M,
|
||
Zone,
|
||
"general",
|
||
null);
|
||
|
||
fees.Should().HaveCount(2);
|
||
fees.Should().Contain(x => x.CostItem == "freight" && x.Amount == 18M);
|
||
fees.Should().Contain(x => x.CostItem == "操作费" && x.Amount == 5M);
|
||
|
||
var summary = ParcelBillingCalculator.SummarizeFees(fees);
|
||
summary.Freight.Should().Be(18M);
|
||
summary.OtherFees.Should().Be(5M);
|
||
summary.TotalCost.Should().Be(23M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateForecastReceivableFees_UnitFormula_ShouldMultiplyChargeableWeight()
|
||
{
|
||
var detail = ParcelBillingTestData.UnitPriceDetail(15M);
|
||
detail.CustomerGroupValues = new Dictionary<string, decimal> { ["客户组1"] = 15M };
|
||
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(1, "freight", detail));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateForecastReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
2M,
|
||
Zone,
|
||
"general",
|
||
"客户组1");
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Amount.Should().Be(30M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateQuoteReceivableFees_TieredContinueWithTotalBase_Weight08_ShouldBe106()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.TotalTierDetail("3", 0.5M, 10M, weightInterval: "(0-0.5]"),
|
||
new ChannelPriceDetailOutput
|
||
{
|
||
CalculationFormula = "continue",
|
||
CalculatedValue = 0,
|
||
FactorValuesJson = new Dictionary<string, string>
|
||
{
|
||
["分区"] = "3",
|
||
["重量"] = "(0.5-1]"
|
||
},
|
||
CustomerGroupValues = new Dictionary<string, decimal> { ["普通客户"] = 2M }
|
||
}));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateQuoteReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
0.8M,
|
||
new[] { "3" },
|
||
"general",
|
||
"普通客户");
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Amount.Should().Be(10.6M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateQuoteReceivableFees_ShouldSupportTotalPriceTiers()
|
||
{
|
||
var details = new[]
|
||
{
|
||
ParcelBillingTestData.TotalTierDetail("3", 0.5M, 11M),
|
||
ParcelBillingTestData.TotalTierDetail("3", 1M, 12M),
|
||
ParcelBillingTestData.TotalTierDetail("3", 1.5M, 12M),
|
||
ParcelBillingTestData.TotalTierDetail("3", 2M, 14M),
|
||
};
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(1, "freight", details));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateQuoteReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1M,
|
||
new[] { "3" },
|
||
"general",
|
||
null);
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Amount.Should().Be(12M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateForecastReceivableFees_ShouldApplyNormalCustomerLabel()
|
||
{
|
||
var detail = ParcelBillingTestData.TotalTierDetail("3", 1M, 99M);
|
||
detail.CustomerGroupValues = new Dictionary<string, decimal> { ["普通客户"] = 12M };
|
||
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(1, "freight", detail));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateForecastReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1M,
|
||
new[] { "3" },
|
||
"general",
|
||
"普通客户");
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Amount.Should().Be(12M);
|
||
}
|
||
|
||
[Fact]
|
||
public void HasEnabledReceivablePriceItems_ShouldDetectAnyEnabledItems()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(1, "freight", ParcelBillingTestData.ContinueFreightDetail()),
|
||
ParcelBillingTestData.ReceivablePriceItem(0, "freight", ParcelBillingTestData.ContinueFreightDetail()));
|
||
|
||
ParcelBillingCalculator.HasEnabledReceivablePriceItems(snapshot).Should().BeTrue();
|
||
ParcelBillingCalculator.HasEnabledForecastPriceItems(snapshot).Should().BeTrue();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 应付(买价)
|
||
|
||
[Theory]
|
||
[InlineData(0.8, 12)]
|
||
[InlineData(1.2, 16)]
|
||
[InlineData(1.6, 20)]
|
||
public void CalculateForecastPayableFees_ContinuePrice_ShouldUseSameEngine(
|
||
double chargeableWeight,
|
||
decimal expectedFreight)
|
||
{
|
||
var prices = ParcelBillingTestData.BuildPayablePrices(
|
||
ParcelBillingTestData.PayablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.ContinueFreightDetail(
|
||
firstWeight: 1M,
|
||
firstPrice: 12M,
|
||
continueUnit: 0.5M,
|
||
continuePrice: 4M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateForecastPayableFees(
|
||
prices,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
(decimal)chargeableWeight,
|
||
Zone,
|
||
"general");
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Type.Should().Be(OrderFeeTypeCodes.Payable);
|
||
fees[0].Amount.Should().Be(expectedFreight);
|
||
fees[0].ChargingStage.Should().Be(OrderFeeChargingStageCodes.Forecast);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateForecastPayableFees_ShouldSkipDisabledPriceItems()
|
||
{
|
||
var prices = ParcelBillingTestData.BuildPayablePrices(
|
||
ParcelBillingTestData.PayablePriceItem(
|
||
0,
|
||
"freight",
|
||
ParcelBillingTestData.ContinueFreightDetail()));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateForecastPayableFees(
|
||
prices,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
Zone,
|
||
"general");
|
||
|
||
fees.Should().BeEmpty();
|
||
ParcelBillingCalculator.HasEnabledPayablePriceItems(prices).Should().BeFalse();
|
||
}
|
||
|
||
[Fact]
|
||
public void ReceivableAndPayable_ShouldDifferByTypeButShareZoneMatching()
|
||
{
|
||
var detail = ParcelBillingTestData.ContinueFreightDetail();
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(1, "freight", detail));
|
||
var payablePrices = ParcelBillingTestData.BuildPayablePrices(
|
||
ParcelBillingTestData.PayablePriceItem(1, "freight", detail));
|
||
|
||
var receivable = ParcelBillingCalculator.CalculateForecastReceivableFees(
|
||
snapshot, _meta.PriceVersion, _meta.EffectiveTime, 1.2M, Zone, "general", null);
|
||
var payable = ParcelBillingCalculator.CalculateForecastPayableFees(
|
||
payablePrices, _meta.PriceVersion, _meta.EffectiveTime, 1.2M, Zone, "general");
|
||
|
||
receivable[0].Type.Should().Be(OrderFeeTypeCodes.Receivable);
|
||
payable[0].Type.Should().Be(OrderFeeTypeCodes.Payable);
|
||
receivable[0].Amount.Should().Be(payable[0].Amount);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 计费条件 / 申报比例 / 去重
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_BillingCondition_ShouldSkipWhenAdditionalServiceMissing()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"insurance",
|
||
serialNumber: 1,
|
||
chargingCondition: "附加服务包含('insurance')",
|
||
ParcelBillingTestData.FixedPriceDetail(20M)));
|
||
|
||
var context = OrderRuleEvaluationContext.FromOrderOnly(new Order
|
||
{
|
||
AdditionalServices = """["remoteFee"]"""
|
||
});
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast,
|
||
conditionContext: context);
|
||
|
||
fees.Should().BeEmpty();
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_BillingCondition_ShouldHitWhenAdditionalServiceSelected()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"insurance",
|
||
serialNumber: 1,
|
||
chargingCondition: "附加服务包含('insurance')",
|
||
ParcelBillingTestData.FixedPriceDetail(20M)));
|
||
|
||
var context = OrderRuleEvaluationContext.FromOrderOnly(new Order
|
||
{
|
||
AdditionalServices = """["insurance"]"""
|
||
});
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast,
|
||
conditionContext: context);
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].CostItem.Should().Be("insurance");
|
||
fees[0].Amount.Should().Be(20M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_PercentDeclared_ShouldRoundToTwoDecimals()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"insurance",
|
||
ParcelBillingTestData.PercentDeclaredDetail(1.5M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
0M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast,
|
||
declaredSum: 1000M,
|
||
declaredCurrency: "CNY");
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Amount.Should().Be(15M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_PercentFreight_ShouldUseSameBatchFreightBase()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.FixedPriceDetail(100M)),
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"fuel",
|
||
ParcelBillingTestData.PercentFreightDetail(10M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast);
|
||
|
||
fees.Should().HaveCount(2);
|
||
fees.Should().Contain(x => x.CostItem == "freight" && x.Amount == 100M);
|
||
fees.Should().Contain(x => x.CostItem == "fuel" && x.Amount == 10M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_PercentFreight_ShouldSkipWhenNoFreightInBatch()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"fuel",
|
||
ParcelBillingTestData.PercentFreightDetail(10M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast);
|
||
|
||
fees.Should().BeEmpty();
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculatePayableFees_PercentFreight_ShouldUseSameBatchFreightBase()
|
||
{
|
||
var payablePrices = ParcelBillingTestData.BuildPayablePrices(
|
||
ParcelBillingTestData.PayablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.FixedPriceDetail(80M)),
|
||
ParcelBillingTestData.PayablePriceItem(
|
||
1,
|
||
"fuel",
|
||
ParcelBillingTestData.PercentFreightDetail(5M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculatePayableFees(
|
||
payablePrices,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
OrderFeeChargingStageCodes.Forecast);
|
||
|
||
fees.Should().HaveCount(2);
|
||
fees.Should().Contain(x => x.CostItem == "freight" && x.Amount == 80M);
|
||
fees.Should().Contain(x => x.CostItem == "fuel" && x.Amount == 4M);
|
||
}
|
||
|
||
[Fact]
|
||
public void NormalizeCalculationFormula_ShouldAliasPercentFreight()
|
||
{
|
||
ParcelBillingCalculator.NormalizeCalculationFormula("运费比例").Should().Be("percent_freight");
|
||
ParcelBillingCalculator.NormalizeCalculationFormula("percentFreight").Should().Be("percent_freight");
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_ShouldDedupeCostItemBySmallestSerialNumber()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
serialNumber: 20,
|
||
chargingCondition: null,
|
||
ParcelBillingTestData.FixedPriceDetail(99M)),
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
serialNumber: 5,
|
||
chargingCondition: null,
|
||
ParcelBillingTestData.FixedPriceDetail(12M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast);
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Amount.Should().Be(12M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_AllCustomerColumn_ShouldApplyToAnyPriceTierKey()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"freight",
|
||
ParcelBillingTestData.AllCustomerTierDetail(Zone, 33M)));
|
||
|
||
var fees = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
"VIP5",
|
||
OrderFeeChargingStageCodes.Forecast);
|
||
|
||
fees.Should().ContainSingle();
|
||
fees[0].Amount.Should().Be(33M);
|
||
}
|
||
|
||
[Fact]
|
||
public void CalculateReceivableFees_RemoteZoneFactor_ShouldRequireMatchingRemoteKeys()
|
||
{
|
||
var snapshot = ParcelBillingTestData.BuildReceivableSnapshot(
|
||
ParcelBillingTestData.ReceivablePriceItem(
|
||
1,
|
||
"remoteFee",
|
||
ParcelBillingTestData.RemoteZoneFixedDetail(15M, Zone, "88")));
|
||
|
||
var miss = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast,
|
||
remoteZoneKeys: Array.Empty<string>());
|
||
miss.Should().BeEmpty();
|
||
|
||
var hit = ParcelBillingCalculator.CalculateReceivableFees(
|
||
snapshot,
|
||
_meta.PriceVersion,
|
||
_meta.EffectiveTime,
|
||
1.2M,
|
||
new[] { Zone },
|
||
"general",
|
||
null,
|
||
OrderFeeChargingStageCodes.Forecast,
|
||
remoteZoneKeys: ParcelBillingCalculator.BuildRemoteZoneKeys(88));
|
||
hit.Should().ContainSingle();
|
||
hit[0].Amount.Should().Be(15M);
|
||
}
|
||
|
||
#endregion
|
||
}
|