Split price/remote zone matching in billing and prefer the 全部客户 column for any price tier key. Co-authored-by: Cursor <cursoragent@cursor.com>
204 lines
5.8 KiB
C#
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);
|
|
}
|