查价/下单/入库/出库统一校验与计费上下文;待排货状态及可选入库排货;运单号改为 IDE+yyMMddHHmmss;补充迁移 SQL 与测试修复。 Co-authored-by: Cursor <cursoragent@cursor.com>
66 lines
2.4 KiB
C#
66 lines
2.4 KiB
C#
using Oms.Application.Dtos.Channels;
|
|
using Oms.Domain.ChannelsAggregate.Consts;
|
|
using Oms.Domain.ChannelsAggregate.Entities;
|
|
using Oms.Domain.OrdersAggregate.Entities;
|
|
|
|
namespace Oms.Application.Shared;
|
|
|
|
/// <summary>
|
|
/// 排货规则运行时选渠。
|
|
/// </summary>
|
|
public static class AllocationResolver
|
|
{
|
|
public sealed class ChannelCandidate
|
|
{
|
|
public SalesProductAllocationProviderSnapshotDto Provider { get; init; } = null!;
|
|
|
|
public ServiceChannel Channel { get; init; } = null!;
|
|
|
|
public decimal TotalPayableCost { get; init; }
|
|
|
|
/// <summary>候选渠道已算出的应付费用(选渠后可直接落库,避免重复算价)。</summary>
|
|
public IReadOnlyList<OrderFee> PayableFees { get; init; } = [];
|
|
}
|
|
|
|
public static List<SalesProductAllocationProviderSnapshotDto> FilterProviders(
|
|
IEnumerable<SalesProductAllocationProviderSnapshotDto> providers,
|
|
int? customerId) =>
|
|
providers
|
|
.Where(x => x.ServiceChannelId.HasValue && x.ServiceChannelId > 0)
|
|
.Where(x => x.CustomerIds.Count == 0
|
|
|| (customerId.HasValue && x.CustomerIds.Contains(customerId.Value)))
|
|
.OrderBy(x => x.SerialNumber)
|
|
.ToList();
|
|
|
|
public static ServiceChannel SelectChannel(string? scheme, IReadOnlyList<ChannelCandidate> candidates) =>
|
|
SelectCandidate(scheme, candidates).Channel;
|
|
|
|
public static ChannelCandidate SelectCandidate(string? scheme, IReadOnlyList<ChannelCandidate> candidates)
|
|
{
|
|
if (candidates.Count == 0)
|
|
{
|
|
throw new InvalidOperationException("无可用排货候选渠道");
|
|
}
|
|
|
|
var normalizedScheme = string.IsNullOrWhiteSpace(scheme)
|
|
? AllocationSchemeCodes.CostLowest
|
|
: scheme.Trim();
|
|
|
|
return normalizedScheme switch
|
|
{
|
|
AllocationSchemeCodes.TimeFastest => candidates
|
|
.OrderBy(x => x.Channel.MinTime ?? int.MaxValue)
|
|
.ThenBy(x => x.Provider.SerialNumber)
|
|
.First(),
|
|
AllocationSchemeCodes.OverallBest => candidates
|
|
.OrderByDescending(x => x.Provider.Weight)
|
|
.ThenBy(x => x.Provider.SerialNumber)
|
|
.First(),
|
|
_ => candidates
|
|
.OrderBy(x => x.TotalPayableCost)
|
|
.ThenBy(x => x.Provider.SerialNumber)
|
|
.First()
|
|
};
|
|
}
|
|
}
|