using System.Text.Json; using FluentAssertions; using Oms.Application.Dtos.Orders; using Oms.Application.Services.Orders; using Oms.Domain.ChannelsAggregate.Entities; using Oms.Domain.OrdersAggregate.Consts; using Oms.Domain.OrdersAggregate.Entities; using Oms.Tests.Support; using Xunit.Abstractions; namespace Oms.Tests; /// /// 模拟小包订单预报计费全流程,便于在 ParcelBillingCalculator 打断点调试。 /// F5 选「调试:模拟订单计费」或对本类测试方法 Debug Test。 /// public class ParcelBillingCalculatorDemoTests { private readonly ITestOutputHelper _output; public ParcelBillingCalculatorDemoTests(ITestOutputHelper output) => _output = output; /// /// 模拟一单美国美西普货小包:30×20×10cm、实重 1.5kg,走计重→进位→应收/应付算价。 /// [Fact] public void SimulateParcelOrderBilling_FullPipeline_ShouldMatchDesignDoc() { // —— 1. 模拟 OrderParcelCreateInput 件重尺 —— var orderInput = new { RequestId = "demo-req-001", ClientNo = "CLIENT-DEMO-001", ProductCode = "US-EXPRESS-01", ChannelCode = "CH-US-WEST", CargoAttribute = "普货", Length = 30M, Width = 20M, Height = 10M, ActualWeight = 1.5M, Destination = new { CountryCode = "US", Province = "CA", PostalCode = "90001" } }; _output.WriteLine("=== 模拟订单入参 ==="); _output.WriteLine(JsonSerializer.Serialize(orderInput, new JsonSerializerOptions { WriteIndented = true })); var quoteContext = new ParcelQuoteContext { CountryCode = orderInput.Destination.CountryCode, Province = orderInput.Destination.Province, PostalCode = orderInput.Destination.PostalCode, CargoAttribute = ParcelBillingCalculator.MapCargoTypeToAttribute(orderInput.CargoAttribute), Length = orderInput.Length, Width = orderInput.Width, Height = orderInput.Height, ActualWeight = orderInput.ActualWeight }; // —— 2. KPI 分区匹配(美国 90001 → 美西)—— var kpiRule = new KpiAreaInfo { Id = 1, CountryCode = "US", LeftPostcode = "90000", RightPostcode = "96199" }; var kpiArea = new KpiArea { Id = 1, Name = "美西分区" }; var zoneMatched = ParcelBillingCalculator.IsAreaMatched( kpiRule, quoteContext.CountryCode, quoteContext.Province, quoteContext.City, quoteContext.PostalCode); var zoneKeys = ParcelBillingCalculator.BuildPriceZoneKeys(kpiRule, kpiArea); var zoneName = ParcelBillingCalculator.ResolveZoneName(kpiRule, kpiArea) ?? "美西"; zoneMatched.Should().BeTrue($"邮编 {quoteContext.PostalCode} 应命中美西分区"); _output.WriteLine($"分区匹配: {zoneMatched}, 分区名: {zoneName}, 分区键: {string.Join(',', zoneKeys)}"); // —— 3. 计重(可在 ParcelBillingCalculator.CalculateRawBillableWeight 打断点)—— var forecastWeight = ParcelBillingCalculator.BuildForecastWeight(quoteContext); var weightRules = new[] { ParcelBillingTestData.GwRule() }; var (volumetricWeight, rawBillable) = ParcelBillingCalculator.CalculateRawBillableWeight(forecastWeight, weightRules); var roundingRules = new[] { ParcelBillingTestData.RoundingRange(0, 30, "0.5") }; var chargeableWeight = ParcelBillingCalculator.ApplyRounding(rawBillable, roundingRules); _output.WriteLine($"材积重: {volumetricWeight} kg, 原始计费重: {rawBillable} kg, 进位后计费重: {chargeableWeight} kg"); chargeableWeight.Should().Be(1.5M); // —— 4. 应收(卖价)—— var (priceVersion, effectiveTime) = ParcelBillingTestData.SnapshotMeta(); var receivableSnapshot = ParcelBillingTestData.BuildReceivableSnapshot( ParcelBillingTestData.ReceivablePriceItem( 1, "freight", ParcelBillingTestData.ContinueFreightDetail()), ParcelBillingTestData.ReceivablePriceItem( 1, "操作费", ParcelBillingTestData.FixedPriceDetail(5M))); var receivableFees = ParcelBillingCalculator.CalculateForecastReceivableFees( receivableSnapshot, priceVersion, effectiveTime, chargeableWeight, new[] { "美西" }, quoteContext.CargoAttribute, null); var receivableSummary = ParcelBillingCalculator.SummarizeFees(receivableFees); _output.WriteLine("=== 应收费用 ==="); foreach (var fee in receivableFees) { _output.WriteLine($" {fee.CostItem}: {fee.Amount} {fee.Currency} ({fee.ChargingStage})"); } _output.WriteLine($"应收合计: {receivableSummary.TotalCost} (运费 {receivableSummary.Freight} + 杂费 {receivableSummary.OtherFees})"); receivableSummary.Freight.Should().Be(24M); // 1.5kg 续单价:首重18 + 续重6 receivableSummary.TotalCost.Should().Be(29M); // —— 5. 应付(买价)—— var payablePrices = ParcelBillingTestData.BuildPayablePrices( ParcelBillingTestData.PayablePriceItem( 1, "freight", ParcelBillingTestData.ContinueFreightDetail( firstWeight: 1M, firstPrice: 12M, continueUnit: 0.5M, continuePrice: 4M))); var payableFees = ParcelBillingCalculator.CalculateForecastPayableFees( payablePrices, priceVersion, effectiveTime, chargeableWeight, "美西", quoteContext.CargoAttribute); var payableSummary = ParcelBillingCalculator.SummarizeFees(payableFees); _output.WriteLine("=== 应付费用 ==="); foreach (var fee in payableFees) { _output.WriteLine($" {fee.CostItem}: {fee.Amount} {fee.Currency}"); } _output.WriteLine($"应付合计: {payableSummary.TotalCost}"); payableSummary.Freight.Should().Be(16M); // 买价:12 + 4 _output.WriteLine($"毛利(应收-应付运费): {receivableSummary.Freight - payableSummary.Freight}"); } }