admin/src/Oms.Tests/Support/ParcelBillingTestData.cs
zzh cc100d40cf feat: support remote-zone factor matching and all-customer price tier
Split price/remote zone matching in billing and prefer the 全部客户 column for any price tier key.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-02 18:22:17 +08:00

204 lines
5.8 KiB
C#

using System.Globalization;
using Oms.Application.Dtos.Channels;
using Oms.Application.Dtos.Orders;
using Oms.Application.Shared;
using Oms.Domain.ChannelsAggregate.Entities;
namespace Oms.Tests.Support;
internal static class ParcelBillingTestData
{
private static readonly DateTime EffectiveTime = new(2026, 4, 1, 0, 0, 0, DateTimeKind.Utc);
private const string PriceVersion = "P20260401001";
private const string Zone = "美西";
public static SalesProductPricePublishSnapshotDto BuildReceivableSnapshot(
params SalesProductPriceListOutput[] prices) =>
new()
{
SalesProductId = 1,
Prices = prices.Select(PublishSnapshotSlimmer.SlimPrice).ToList()
};
public static List<ServiceChannelPriceListOutput> BuildPayablePrices(
params ServiceChannelPriceListOutput[] prices) => prices.ToList();
public static SalesProductPriceListOutput ReceivablePriceItem(
byte status,
string costItem,
params ChannelPriceDetailOutput[] details) =>
ReceivablePriceItem(status, costItem, serialNumber: 1, chargingCondition: null, details);
public static SalesProductPriceListOutput ReceivablePriceItem(
byte status,
string costItem,
int serialNumber,
string? chargingCondition,
params ChannelPriceDetailOutput[] details) =>
new()
{
Status = status == 0 ? (byte)0 : (byte)2,
SerialNumber = serialNumber,
CostItem = costItem,
Currency = "CNY",
ChargingCondition = chargingCondition,
Details = details.ToList()
};
public static ServiceChannelPriceListOutput PayablePriceItem(
byte status,
string costItem,
params ChannelPriceDetailOutput[] details) =>
new()
{
Status = status == 0 ? (byte)0 : (byte)2,
CostItem = costItem,
Currency = "CNY",
Details = details.ToList()
};
public static ChannelPriceDetailOutput PercentDeclaredDetail(
decimal rate,
string zone = Zone,
string cargoType = "普货") =>
new()
{
CalculationFormula = "percent_declared",
CalculatedValue = rate,
FactorValuesJson = new Dictionary<string, string>
{
["分区"] = zone,
["货物类型"] = cargoType
}
};
public static ChannelPriceDetailOutput PercentFreightDetail(
decimal rate,
string zone = Zone,
string cargoType = "普货") =>
new()
{
CalculationFormula = "percent_freight",
CalculatedValue = rate,
FactorValuesJson = new Dictionary<string, string>
{
["分区"] = zone,
["货物类型"] = cargoType
}
};
public static ChannelPriceDetailOutput ContinueFreightDetail(
decimal firstWeight = 1M,
decimal firstPrice = 18M,
decimal continueUnit = 0.5M,
decimal continuePrice = 6M,
string zone = Zone,
string cargoType = "普货") =>
new()
{
CalculationFormula = "续单价",
FactorValuesJson = new Dictionary<string, string>
{
["分区"] = zone,
["货物类型"] = cargoType,
["首重"] = firstWeight.ToString(CultureInfo.InvariantCulture),
["首重价"] = firstPrice.ToString(CultureInfo.InvariantCulture),
["续重单位"] = continueUnit.ToString(CultureInfo.InvariantCulture),
["续重价"] = continuePrice.ToString(CultureInfo.InvariantCulture)
}
};
public static ChannelPriceDetailOutput FixedPriceDetail(
decimal amount,
string zone = Zone,
string cargoType = "普货") =>
new()
{
CalculationFormula = "固定价",
CalculatedValue = amount,
FactorValuesJson = new Dictionary<string, string>
{
["分区"] = zone,
["货物类型"] = cargoType
}
};
public static ChannelPriceDetailOutput UnitPriceDetail(
decimal unitPrice,
string zone = Zone) =>
new()
{
CalculationFormula = "单价",
CalculatedValue = unitPrice,
FactorValuesJson = new Dictionary<string, string> { ["分区"] = zone }
};
public static ChannelPriceDetailOutput TotalTierDetail(
string zone,
decimal weightTier,
decimal normalCustomerPrice,
string? weightInterval = null) =>
new()
{
CalculationFormula = "total",
CalculatedValue = 0,
FactorValuesJson = new Dictionary<string, string>
{
["分区"] = zone,
["重量"] = weightInterval ?? weightTier.ToString(CultureInfo.InvariantCulture)
},
CustomerGroupValues = new Dictionary<string, decimal> { ["普通客户"] = normalCustomerPrice }
};
public static ChannelPriceDetailOutput AllCustomerTierDetail(
string zone,
decimal allCustomerPrice,
string? weightInterval = null) =>
new()
{
CalculationFormula = "total",
CalculatedValue = 0,
FactorValuesJson = new Dictionary<string, string>
{
["价格分区"] = zone,
["重量"] = weightInterval ?? "999"
},
CustomerGroupValues = new Dictionary<string, decimal> { ["全部客户"] = allCustomerPrice }
};
public static ChannelPriceDetailOutput RemoteZoneFixedDetail(
decimal amount,
string priceZone,
string remoteZoneId) =>
new()
{
CalculationFormula = "固定价",
CalculatedValue = amount,
FactorValuesJson = new Dictionary<string, string>
{
["价格分区"] = priceZone,
["偏远分区"] = remoteZoneId
}
};
public static WeightRuleInfo GwRule(string condition = "gw>=vw", string factor = "6000") =>
new()
{
Id = 1,
Condition = condition,
BillableWeight = "gw",
VolumetricFactor = factor
};
public static WeightRoundingInfo RoundingRange(decimal start, decimal end, string unit) =>
new()
{
Id = 1,
StartValue = start,
EndValue = end,
Public = unit
};
public static (string PriceVersion, DateTime EffectiveTime) SnapshotMeta() => (PriceVersion, EffectiveTime);
}