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