using Oms.Application.Dtos.Channels; using Oms.Domain.ChannelsAggregate.Consts; using Oms.Domain.ChannelsAggregate.Entities; using Oms.Domain.OrdersAggregate.Entities; namespace Oms.Application.Shared; /// /// 排货规则运行时选渠。 /// 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; } /// 候选渠道已算出的应付费用(选渠后可直接落库,避免重复算价)。 public IReadOnlyList PayableFees { get; init; } = []; } public static List FilterProviders( IEnumerable 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 candidates) => SelectCandidate(scheme, candidates).Channel; public static ChannelCandidate SelectCandidate(string? scheme, IReadOnlyList 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() }; } }