diff --git a/db.sql b/db.sql
index 485e33b..3f1111e 100644
--- a/db.sql
+++ b/db.sql
@@ -118,6 +118,7 @@ CREATE TABLE `t_order` (
`ProductCode` VARCHAR(128) NULL COMMENT '产品编码',
`ChannelCode` VARCHAR(128) NULL COMMENT '渠道编码',
`DownstreamSupplierCode` VARCHAR(64) NULL COMMENT '下游 API 服务商编码 supplierCode',
+ `DownstreamSupplierName` VARCHAR(128) NULL COMMENT '下游 API 服务商名称',
`DownstreamAppKey` VARCHAR(128) NULL COMMENT '下游 itfx 应用 AppKey',
`DownstreamAppId` INT NULL COMMENT '下游 itfx 应用 Id',
`ChannelForecastCode` VARCHAR(128) NULL COMMENT '渠道预报编码 ForecastCode',
diff --git a/sql/migrate_20261009_order_warehouse.sql b/sql/migrate_20261009_order_warehouse.sql
new file mode 100644
index 0000000..c8c2b84
--- /dev/null
+++ b/sql/migrate_20261009_order_warehouse.sql
@@ -0,0 +1,105 @@
+-- =============================================================================
+-- migrate_20261009_order_warehouse.sql
+-- 汇总:
+-- 1) t_order.DownstreamSupplierName(下游服务商名称)
+-- 2) t_order_operation_log(运单操作日志)
+-- 3) t_warehouse_address.Sort / Remark(仓库地址排序与备注)
+-- 可重复执行。
+-- =============================================================================
+
+SET @db := DATABASE();
+
+-- -----------------------------------------------------------------------------
+-- 1) 订单:下游服务商名称
+-- -----------------------------------------------------------------------------
+SET @exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db
+ AND TABLE_NAME = 't_order'
+ AND COLUMN_NAME = 'DownstreamSupplierName'
+);
+SET @sql := IF(
+ @exists = 0,
+ 'ALTER TABLE `t_order` ADD COLUMN `DownstreamSupplierName` VARCHAR(128) NULL COMMENT ''下游 API 服务商名称'' AFTER `DownstreamSupplierCode`',
+ 'SELECT ''t_order.DownstreamSupplierName already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+-- -----------------------------------------------------------------------------
+-- 2) 运单操作日志表
+-- -----------------------------------------------------------------------------
+SET @tbl := (
+ SELECT COUNT(1)
+ FROM information_schema.TABLES
+ WHERE TABLE_SCHEMA = @db
+ AND TABLE_NAME = 't_order_operation_log'
+);
+SET @sql := IF(
+ @tbl = 0,
+ 'CREATE TABLE `t_order_operation_log` (
+ `Id` INT NOT NULL AUTO_INCREMENT COMMENT ''主键'',
+ `OrderId` INT NOT NULL COMMENT ''运单Id'',
+ `ServiceNo` VARCHAR(64) NULL COMMENT ''运单号冗余'',
+ `Action` VARCHAR(32) NOT NULL COMMENT ''动作码 editBasic/editWeight/recalcReceivable/recalcPayable/reallocate'',
+ `ActionName` VARCHAR(64) NOT NULL COMMENT ''动作中文名'',
+ `OperatorId` INT NOT NULL DEFAULT 0 COMMENT ''操作人用户Id'',
+ `OperatorName` VARCHAR(64) NULL COMMENT ''操作人展示名'',
+ `OperatorType` VARCHAR(16) NOT NULL DEFAULT ''staff'' COMMENT ''staff/customer/system/openapi'',
+ `Source` VARCHAR(16) NOT NULL DEFAULT ''pc'' COMMENT ''pc/h5/openapi/job'',
+ `ChangesJson` JSON NULL COMMENT ''字段 diff 数组 [{path,label,before,after}]'',
+ `Remark` VARCHAR(512) NULL COMMENT ''补充说明'',
+ `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT ''软删除:0-否,1-是'',
+ `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT ''并发戳'',
+ `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT ''创建人'',
+ `CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ''创建时间'',
+ `UpdateUserId` INT NULL COMMENT ''更新人'',
+ `UpdateTime` DATETIME NULL COMMENT ''更新时间'',
+ PRIMARY KEY (`Id`),
+ KEY `idx_ool_order_time` (`OrderId`, `CreateTime`),
+ KEY `idx_ool_service_no` (`ServiceNo`)
+ ) COMMENT=''运单操作日志''',
+ 'SELECT ''t_order_operation_log already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+-- -----------------------------------------------------------------------------
+-- 3) 仓库地址:展示排序 + 备注
+-- -----------------------------------------------------------------------------
+SET @col := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db
+ AND TABLE_NAME = 't_warehouse_address'
+ AND COLUMN_NAME = 'Sort'
+);
+SET @sql := IF(
+ @col = 0,
+ 'ALTER TABLE `t_warehouse_address`
+ ADD COLUMN `Sort` INT NULL DEFAULT NULL COMMENT ''展示排序,越小越靠前'' AFTER `ShippingAddress`',
+ 'SELECT ''t_warehouse_address.Sort already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+SET @col := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db
+ AND TABLE_NAME = 't_warehouse_address'
+ AND COLUMN_NAME = 'Remark'
+);
+SET @sql := IF(
+ @col = 0,
+ 'ALTER TABLE `t_warehouse_address`
+ ADD COLUMN `Remark` VARCHAR(512) NULL DEFAULT NULL COMMENT ''备注'' AFTER `Sort`',
+ 'SELECT ''t_warehouse_address.Remark already exists'' AS info'
+);
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/sql/migrate_order_downstream_supplier_name.sql b/sql/migrate_order_downstream_supplier_name.sql
new file mode 100644
index 0000000..f3ba5ad
--- /dev/null
+++ b/sql/migrate_order_downstream_supplier_name.sql
@@ -0,0 +1,22 @@
+-- 订单增加下游服务商名称(排货确认时写入 itfx 服务商名 / 分组名)。
+-- 可重复执行。
+
+SET @db := DATABASE();
+
+SET @exists := (
+ SELECT COUNT(1)
+ FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = @db
+ AND TABLE_NAME = 't_order'
+ AND COLUMN_NAME = 'DownstreamSupplierName'
+);
+
+SET @sql := IF(
+ @exists = 0,
+ 'ALTER TABLE `t_order` ADD COLUMN `DownstreamSupplierName` VARCHAR(128) NULL COMMENT ''下游 API 服务商名称'' AFTER `DownstreamSupplierCode`',
+ 'SELECT ''t_order.DownstreamSupplierName already exists'' AS info'
+);
+
+PREPARE stmt FROM @sql;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
diff --git a/src/Oms.Application/Dtos/Orders/OrderBindSnapshotVersionsDtos.cs b/src/Oms.Application/Dtos/Orders/OrderBindSnapshotVersionsDtos.cs
new file mode 100644
index 0000000..2abfce4
--- /dev/null
+++ b/src/Oms.Application/Dtos/Orders/OrderBindSnapshotVersionsDtos.cs
@@ -0,0 +1,34 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Oms.Application.Dtos.Orders;
+
+///
+/// 切换订单绑定的销售产品规则/价格发布版本。
+///
+public class OrderBindSnapshotVersionsInput
+{
+ [Required]
+ public int Id { get; set; }
+
+ ///
+ /// 目标规则版本;空表示不改。特殊值 CURRENT 表示绑定当前有效规则发布。
+ ///
+ [StringLength(64)]
+ public string? RulesVersion { get; set; }
+
+ ///
+ /// 目标价格版本;空表示不改。特殊值 CURRENT 表示绑定当前有效价格发布。
+ ///
+ [StringLength(64)]
+ public string? PriceVersion { get; set; }
+
+ ///
+ /// 绑定后是否立即重算应收(已支付会拒绝)。
+ ///
+ public bool RecalculateReceivable { get; set; }
+
+ ///
+ /// 绑定后是否立即重算应付(锁定当前渠道)。
+ ///
+ public bool RecalculatePayable { get; set; }
+}
diff --git a/src/Oms.Application/Dtos/Orders/OrderOutput.cs b/src/Oms.Application/Dtos/Orders/OrderOutput.cs
index a82aea9..4eaed1f 100644
--- a/src/Oms.Application/Dtos/Orders/OrderOutput.cs
+++ b/src/Oms.Application/Dtos/Orders/OrderOutput.cs
@@ -55,6 +55,11 @@ public class OrderOutput
///
public string? DownstreamSupplierCode { get; set; }
+ ///
+ /// 下游 API 服务商名称。
+ ///
+ public string? DownstreamSupplierName { get; set; }
+
///
/// 下游 itfx 应用 AppKey。
///
@@ -363,6 +368,16 @@ public class OrderOutput
///
public decimal? ForecastPayableAmount { get; set; }
+ ///
+ /// 订单绑定的销售产品规则发布版本。
+ ///
+ public string? SalesProductRulesVersion { get; set; }
+
+ ///
+ /// 订单绑定的销售产品价格发布版本。
+ ///
+ public string? SalesProductPriceVersion { get; set; }
+
///
/// 创建时间。
///
diff --git a/src/Oms.Application/Services/Orders/OrderOperationLogSnapshot.cs b/src/Oms.Application/Services/Orders/OrderOperationLogSnapshot.cs
index 8a3d31c..527471a 100644
--- a/src/Oms.Application/Services/Orders/OrderOperationLogSnapshot.cs
+++ b/src/Oms.Application/Services/Orders/OrderOperationLogSnapshot.cs
@@ -28,6 +28,8 @@ public static class OrderOperationLogSnapshot
["payableAmount"] = "应付金额",
["downstreamServiceNo"] = "服务商单号",
["allocationScheme"] = "排货方案",
+ ["salesProductRulesVersion"] = "规则版本",
+ ["salesProductPriceVersion"] = "价格版本",
["isPaid"] = "是否已支付",
["sender.name"] = "发件人姓名",
["sender.phone"] = "发件人电话",
@@ -70,6 +72,8 @@ public static class OrderOperationLogSnapshot
["payableAmount"] = FormatDecimal(order.PayableAmount),
["downstreamServiceNo"] = Norm(order.DownstreamServiceNo),
["allocationScheme"] = Norm(order.AllocationScheme),
+ ["salesProductRulesVersion"] = Norm(order.SalesProductRulesVersion),
+ ["salesProductPriceVersion"] = Norm(order.SalesProductPriceVersion),
["isPaid"] = FormatByte(order.IsPaid),
};
}
diff --git a/src/Oms.Application/Services/Orders/OrderService.Helpers.cs b/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
index c5d6e34..40f81fa 100644
--- a/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.Helpers.cs
@@ -165,6 +165,7 @@ public partial class OrderService
MaxTimeliness = product?.MaxTimeliness,
ChannelCode = order.ChannelCode,
DownstreamSupplierCode = order.DownstreamSupplierCode,
+ DownstreamSupplierName = order.DownstreamSupplierName,
DownstreamAppKey = order.DownstreamAppKey,
DownstreamAppId = order.DownstreamAppId,
ChannelForecastCode = order.ChannelForecastCode,
@@ -262,6 +263,12 @@ public partial class OrderService
HasInsurance = hasInsurance,
ForecastReceivableAmount = order.ForecastReceivableAmount,
ForecastPayableAmount = order.ForecastPayableAmount,
+ SalesProductRulesVersion = string.IsNullOrWhiteSpace(order.SalesProductRulesVersion)
+ ? null
+ : order.SalesProductRulesVersion.Trim(),
+ SalesProductPriceVersion = string.IsNullOrWhiteSpace(order.SalesProductPriceVersion)
+ ? null
+ : order.SalesProductPriceVersion.Trim(),
CreateTime = order.CreateTime,
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(order.CreateUserId, auditUserNameMap),
UpdateTime = OmsDocHelper.NullIfDefault(order.UpdateTime),
@@ -387,6 +394,7 @@ public partial class OrderService
output.ChannelCode = null;
output.ChannelName = null;
output.DownstreamSupplierCode = null;
+ output.DownstreamSupplierName = null;
output.DownstreamAppKey = null;
output.DownstreamAppId = null;
output.ChannelForecastCode = null;
diff --git a/src/Oms.Application/Services/Orders/OrderService.OrderEdit.cs b/src/Oms.Application/Services/Orders/OrderService.OrderEdit.cs
index b0e9653..9049e59 100644
--- a/src/Oms.Application/Services/Orders/OrderService.OrderEdit.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.OrderEdit.cs
@@ -286,6 +286,127 @@ public partial class OrderService
return (await MapOrderOutputsAsync([order])).First();
}
+ ///
+ /// 切换订单绑定的销售产品规则/价格发布版本(显式改契约后再重算)。
+ ///
+ [HttpPost("/order/fee/bind-snapshot-versions")]
+ public async Task BindSnapshotVersionsAsync([FromBody] OrderBindSnapshotVersionsInput input)
+ {
+ var order = await GetOrderOrThrowAsync(input.Id);
+ var beforeSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true);
+
+ if (string.IsNullOrWhiteSpace(order.ProductCode))
+ {
+ throw new BusinessException("订单未绑定销售产品,无法切换版本");
+ }
+
+ var product = await SalesProductRepository.GetByProductCodeAsync(order.ProductCode.Trim());
+ if (product == null)
+ {
+ throw new BusinessException("销售产品不存在");
+ }
+
+ var wantRules = !string.IsNullOrWhiteSpace(input.RulesVersion);
+ var wantPrice = !string.IsNullOrWhiteSpace(input.PriceVersion);
+ if (!wantRules && !wantPrice)
+ {
+ throw new BusinessException("请至少指定规则版本或价格版本");
+ }
+
+ var remarkParts = new List();
+ if (wantRules)
+ {
+ var resolved = await ResolveBindTargetVersionAsync(
+ product,
+ RulesOperatorType,
+ input.RulesVersion!.Trim(),
+ "规则");
+ if (!string.Equals(order.SalesProductRulesVersion, resolved, StringComparison.Ordinal))
+ {
+ remarkParts.Add($"rules:{order.SalesProductRulesVersion ?? "-"}→{resolved}");
+ order.SalesProductRulesVersion = resolved;
+ }
+ }
+
+ if (wantPrice)
+ {
+ var resolved = await ResolveBindTargetVersionAsync(
+ product,
+ PriceOperatorType,
+ input.PriceVersion!.Trim(),
+ "价格");
+ if (!string.Equals(order.SalesProductPriceVersion, resolved, StringComparison.Ordinal))
+ {
+ remarkParts.Add($"price:{order.SalesProductPriceVersion ?? "-"}→{resolved}");
+ order.SalesProductPriceVersion = resolved;
+ }
+ }
+
+ if (remarkParts.Count == 0 && !input.RecalculateReceivable && !input.RecalculatePayable)
+ {
+ throw new BusinessException("目标版本与当前绑定相同,且未勾选重算");
+ }
+
+ order.UpdateTime = DateTime.Now;
+ await OrderRepository.UpdateAsync(order);
+
+ if (input.RecalculateReceivable)
+ {
+ EnsureReceivableMutable(order);
+ await RecalculateReceivableCoreAsync(order);
+ }
+
+ if (input.RecalculatePayable)
+ {
+ await RecalculatePayableCoreAsync(order);
+ }
+
+ order = await GetOrderOrThrowAsync(order.Id);
+ var afterSnap = await CaptureOrderAuditSnapshotAsync(order, includeFees: true);
+ await OperationLogWriter.TryWriteAsync(
+ order,
+ OrderOperationActionCodes.BindSnapshotVersions,
+ beforeSnap,
+ afterSnap,
+ remarkParts.Count == 0 ? null : string.Join(';', remarkParts));
+ return (await MapOrderOutputsAsync([order])).First();
+ }
+
+ ///
+ /// 解析绑定目标版本:CURRENT 取当前有效发布,否则按版本号校验存在。
+ ///
+ private async Task ResolveBindTargetVersionAsync(
+ SalesProduct product,
+ string operatorType,
+ string versionOrCurrent,
+ string label)
+ {
+ if (string.Equals(versionOrCurrent, "CURRENT", StringComparison.OrdinalIgnoreCase))
+ {
+ var effective = await SalesProductRepository.GetEffectivePublishRecordAsync(
+ product.Id,
+ operatorType,
+ DateTime.Now);
+ if (effective == null || string.IsNullOrWhiteSpace(effective.Version))
+ {
+ throw new BusinessException($"未命中当前有效{label}发布版本");
+ }
+
+ return effective.Version.Trim();
+ }
+
+ var record = await SalesProductRepository.GetPublishRecordByVersionAsync(
+ product.Id,
+ operatorType,
+ versionOrCurrent);
+ if (record == null || string.IsNullOrWhiteSpace(record.Version))
+ {
+ throw new BusinessException($"未找到{label}发布版本:{versionOrCurrent}");
+ }
+
+ return record.Version.Trim();
+ }
+
///
/// 重跑入库计费(应收 wipe+upsert + 排货应付)。用于队列投递失败或待排货补救。
///
@@ -1010,6 +1131,7 @@ public partial class OrderService
// 重新排货:产品规则/分区与渠道买价均取当前有效发布,避免沿用下单时旧快照。
// 对账重算 / 普通重算应付:沿用订单快照绑定(分区等),买价仍由排货评估取当前有效发布。
+ // 锁渠道重算应付:允许渠道不在旧规则排货池内(渠道已确认,只重算买价)。
var snapshotBinding = enforceReallocateGate
? await ResolveSnapshotBindingAsync(product, DateTime.Now)
: await ResolveSnapshotBindingFromOrderAsync(product, order);
@@ -1032,7 +1154,14 @@ public partial class OrderService
billing,
chargingStage,
schemeOverride,
- forceChannelId);
+ forceChannelId,
+ allowDesignatedOutsidePool: lockCurrentChannel);
+
+ // 重新排货成功后写回规则版本,使后续重算应付与当前排货池一致;卖价版本保持契约,不随排货改写。
+ if (enforceReallocateGate)
+ {
+ order.SalesProductRulesVersion = snapshotBinding.RulesVersion;
+ }
if (string.Equals(order.OrderStatus, OrderStatusCodes.PendingAllocation, StringComparison.OrdinalIgnoreCase))
{
diff --git a/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs b/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs
index 2fd317d..8f7bc82 100644
--- a/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs
+++ b/src/Oms.Application/Services/Orders/OrderService.ParcelBilling.cs
@@ -848,7 +848,8 @@ public partial class OrderService
string chargingStage,
string? _,
string? schemeOverride = null,
- int? forceServiceChannelId = null)
+ int? forceServiceChannelId = null,
+ bool allowDesignatedOutsidePool = false)
{
var evaluation = await EvaluateAllocationAsync(
order,
@@ -858,7 +859,8 @@ public partial class OrderService
chargeableWeight,
chargingStage,
schemeOverride,
- forceServiceChannelId);
+ forceServiceChannelId,
+ allowDesignatedOutsidePool);
ApplyAllocationTraceToOrder(order, evaluation);
@@ -928,7 +930,8 @@ public partial class OrderService
decimal chargeableWeight,
string chargingStage,
string? schemeOverride,
- int? forceServiceChannelId)
+ int? forceServiceChannelId,
+ bool allowDesignatedOutsidePool = false)
{
var warehouseName = await ResolveWarehouseNameAsync(order.WarehouseId);
var providers = await ResolveAllocationProvidersAsync(product, snapshotBinding.Rules);
@@ -985,27 +988,61 @@ public partial class OrderService
if (designated.Count == 0)
{
var poolRow = providers.FirstOrDefault(x => x.ServiceChannelId == forceServiceChannelId.Value);
- var failReason = poolRow == null
- ? "指定渠道不在该销售产品排货池"
- : "指定渠道不满足判断条件";
- if (poolRow != null
- && skipped.All(x => x.ServiceChannelId != forceServiceChannelId.Value))
+ // 重算应付锁定已确认渠道:渠道已在单上,不再用旧规则排货池/判断条件拦截,只重算买价。
+ if (allowDesignatedOutsidePool)
{
- skipped.Add(new OrderAllocationSkippedOutput
+ var lockedChannel = await ServiceChannelRepository.FirstOrDefaultAsync(x =>
+ x.Id == forceServiceChannelId.Value);
+ if (lockedChannel == null)
{
- ServiceChannelId = forceServiceChannelId.Value,
- ChannelCode = poolRow.ChannelCode,
- ChannelName = poolRow.ServiceChannelName ?? poolRow.ProviderName,
- Stage = AllocationResolver.SkipStageCondition,
- MatchCondition = AllocationResolver.TruncateMatchCondition(poolRow.MatchCondition),
- Reason = failReason
- });
+ return BaseEval("订单服务渠道不存在,无法重算应付");
+ }
+
+ var lockedProvider = poolRow ?? new SalesProductAllocationProviderSnapshotDto
+ {
+ SalesProductId = product.Id,
+ ServiceChannelId = lockedChannel.Id,
+ ServiceChannelName = lockedChannel.ChannelName,
+ ProviderName = lockedChannel.ChannelName ?? lockedChannel.ChannelCode,
+ ChannelCode = lockedChannel.ChannelCode,
+ Weight = 0,
+ CustomerIds = [],
+ MatchCondition = null
+ };
+ if (poolRow == null
+ || AllocationProviderSnapshotEnricher.NeedsDownstreamEnrichment(lockedProvider))
+ {
+ await AllocationProviderSnapshotEnricher.EnrichAsync([lockedProvider]);
+ }
+
+ filtered = [lockedProvider];
}
+ else
+ {
+ var failReason = poolRow == null
+ ? "指定渠道不在该销售产品排货池"
+ : "指定渠道不满足判断条件";
+ if (poolRow != null
+ && skipped.All(x => x.ServiceChannelId != forceServiceChannelId.Value))
+ {
+ skipped.Add(new OrderAllocationSkippedOutput
+ {
+ ServiceChannelId = forceServiceChannelId.Value,
+ ChannelCode = poolRow.ChannelCode,
+ ChannelName = poolRow.ServiceChannelName ?? poolRow.ProviderName,
+ Stage = AllocationResolver.SkipStageCondition,
+ MatchCondition = AllocationResolver.TruncateMatchCondition(poolRow.MatchCondition),
+ Reason = failReason
+ });
+ }
- return BaseEval(failReason);
+ return BaseEval(failReason);
+ }
+ }
+ else
+ {
+ filtered = designated;
}
-
- filtered = designated;
}
if (filtered.Count == 0)
@@ -1304,7 +1341,8 @@ public partial class OrderService
OrderBillingContext billing,
string chargingStage,
string? schemeOverride = null,
- int? forceServiceChannelId = null) =>
+ int? forceServiceChannelId = null,
+ bool allowDesignatedOutsidePool = false) =>
ConfirmServiceChannelAndPayableAsync(
order,
product,
@@ -1314,7 +1352,8 @@ public partial class OrderService
chargingStage,
billing.PriceTierKey,
schemeOverride,
- forceServiceChannelId);
+ forceServiceChannelId,
+ allowDesignatedOutsidePool);
///
/// 尝试排货并写入应付;失败时不抛异常,写入 供运营补配置。
@@ -1325,7 +1364,8 @@ public partial class OrderService
OrderBillingContext billing,
string chargingStage,
string? schemeOverride = null,
- int? forceServiceChannelId = null)
+ int? forceServiceChannelId = null,
+ bool allowDesignatedOutsidePool = false)
{
try
{
@@ -1335,7 +1375,8 @@ public partial class OrderService
billing,
chargingStage,
schemeOverride,
- forceServiceChannelId);
+ forceServiceChannelId,
+ allowDesignatedOutsidePool);
return true;
}
catch (BusinessException ex)
diff --git a/src/Oms.Application/Shared/AllocationProviderSnapshotEnricher.cs b/src/Oms.Application/Shared/AllocationProviderSnapshotEnricher.cs
index afb1ef4..4073363 100644
--- a/src/Oms.Application/Shared/AllocationProviderSnapshotEnricher.cs
+++ b/src/Oms.Application/Shared/AllocationProviderSnapshotEnricher.cs
@@ -108,6 +108,9 @@ public class AllocationProviderSnapshotEnricher(
ServiceChannel? channelFallback = null)
{
order.DownstreamSupplierCode = NullIfEmpty(provider.SupplierCode);
+ order.DownstreamSupplierName = NullIfEmpty(provider.ApiServiceProviderName)
+ ?? NullIfEmpty(provider.GroupName)
+ ?? NullIfEmpty(provider.ProviderName);
order.DownstreamAppKey = NullIfEmpty(provider.AppKey);
order.DownstreamAppId = provider.AppId;
order.ChannelForecastCode = NullIfEmpty(provider.ForecastCode)
diff --git a/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs b/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs
index 866ac0d..17d6f8b 100644
--- a/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs
+++ b/src/Oms.Domain/OrdersAggregate/Consts/OrderOperationActionCodes.cs
@@ -7,6 +7,7 @@ public static class OrderOperationActionCodes
public const string RecalcReceivable = "recalcReceivable";
public const string RecalcPayable = "recalcPayable";
public const string Reallocate = "reallocate";
+ public const string BindSnapshotVersions = "bindSnapshotVersions";
public static string GetActionName(string action) => action switch
{
@@ -15,6 +16,7 @@ public static class OrderOperationActionCodes
RecalcReceivable => "重算应收",
RecalcPayable => "重算应付",
Reallocate => "重新排货",
+ BindSnapshotVersions => "切换价格/规则版本",
_ => action
};
}
diff --git a/src/Oms.Domain/OrdersAggregate/Entities/Order.cs b/src/Oms.Domain/OrdersAggregate/Entities/Order.cs
index 3aea651..2f2b77e 100644
--- a/src/Oms.Domain/OrdersAggregate/Entities/Order.cs
+++ b/src/Oms.Domain/OrdersAggregate/Entities/Order.cs
@@ -29,6 +29,12 @@ public class Order : OmsAuditedAggregateRoot
///
public string? DownstreamSupplierCode { get; set; }
+ ///
+ /// 下游 API 服务商名称(itfx service provider name)。
+ ///
+ [SugarColumn(Length = 128, IsNullable = true)]
+ public string? DownstreamSupplierName { get; set; }
+
///
/// 下游 itfx 应用 AppKey。
///