admin/src/Oms.Application/Shared/AllocationResolver.cs
zzh 3d5eaa223a feat: 小包全链路加固、待排货与运单号 IDE 前缀
查价/下单/入库/出库统一校验与计费上下文;待排货状态及可选入库排货;运单号改为 IDE+yyMMddHHmmss;补充迁移 SQL 与测试修复。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-22 19:00:55 +08:00

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