|
|
@@ -32,10 +32,9 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
private const string RuleCode = "RULE_S4_PURCHASE_DELIVERY_DATE_DELAY";
|
|
|
|
|
|
private static S8MonitoringDataRequest Request(
|
|
|
- long tenantId = 838257186181189, long factoryId = 838257186320453) => new()
|
|
|
+ long tenantId = 838257186181189) => new()
|
|
|
{
|
|
|
TenantId = tenantId,
|
|
|
- FactoryId = factoryId,
|
|
|
DatasetCode = PurchaseDelivery,
|
|
|
RuleCode = RuleCode,
|
|
|
RuleType = "TIMEOUT"
|
|
|
@@ -118,14 +117,14 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
- public void T5b_FactoryId_DoesNotAlterQuery_ButTenantIdDoes()
|
|
|
+ public void T5b_FactoryIsNotAQueryDimension_ButTenantIdIs()
|
|
|
{
|
|
|
- // 同一租户下换工厂:SQL 与唯一参数都不受影响(工厂根本不进 SQL)。
|
|
|
- // 换租户:参数随之改变。二者共同证明"隔离维度只有租户"。
|
|
|
- var sameTenantOtherFactory = Request(factoryId: 999_999_999);
|
|
|
- var otherTenant = Request(tenantId: 838257212780613);
|
|
|
+ // S8-TENANT-ONLY-BATCH5:原用例构造「同租户换工厂」的请求来证明工厂不影响取数。
|
|
|
+ // 现在连构造都做不到了 —— 请求上没有工厂这一维,该结论由类型系统保证。
|
|
|
+ // 保留断言的另一半:租户仍然是、且是唯一的取数作用域。
|
|
|
+ Assert.Null(typeof(S8MonitoringDataRequest).GetProperty("FactoryId"));
|
|
|
|
|
|
- Assert.Equal(Request().TenantId, sameTenantOtherFactory.TenantId);
|
|
|
+ var otherTenant = Request(tenantId: 838257212780613);
|
|
|
Assert.NotEqual(Request().TenantId, otherTenant.TenantId);
|
|
|
// 工厂不在 SQL 中,因此不可能成为取数差异的来源。
|
|
|
Assert.DoesNotContain("@FactoryId", S8PurchaseDeliveryDataProvider.Sql);
|
|
|
@@ -168,9 +167,11 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
provider.LoadAsync(Request(tenantId: 0)));
|
|
|
Assert.Equal("dataset_scope_invalid", ex.Reason);
|
|
|
|
|
|
- var ex2 = await Assert.ThrowsAsync<S8RuleEvaluatorException>(() =>
|
|
|
- provider.LoadAsync(Request(factoryId: 0)));
|
|
|
- Assert.Equal("dataset_scope_invalid", ex2.Reason);
|
|
|
+ // 原用例第二段断言「factoryId = 0 同样被拒」。工厂不再是作用域之后该断言必须反向:
|
|
|
+ // 合法租户下不存在任何以工厂为由的拒绝,请求校验必须直接通过。
|
|
|
+ // (这正是 Batch 2 供给的 factory_id = 0 运行策略此前过不去的那道门。)
|
|
|
+ Request().EnsureValid();
|
|
|
+ Assert.DoesNotContain("Factory", ex.Message, StringComparison.OrdinalIgnoreCase);
|
|
|
}
|
|
|
|
|
|
// ============================================================
|
|
|
@@ -211,7 +212,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
{
|
|
|
// 实测该租户最长 source_object_id 为 16 字符;此处按真实规则编码与作用域算完整 DedupKey。
|
|
|
var key = S8TimeoutRuleEvaluator.BuildDedupKey(
|
|
|
- 838257186181189, 838257186320453, RuleCode, "PURCHASE_ORDER_LINE", "PO202608260002#4");
|
|
|
+ 838257186181189, RuleCode, "PURCHASE_ORDER_LINE", "PO202608260002#4");
|
|
|
|
|
|
Assert.True(key.Length <= S8PurchaseDeliveryDataProvider.DedupKeyMaxLength,
|
|
|
$"DedupKey 长度 {key.Length} 超过 {S8PurchaseDeliveryDataProvider.DedupKeyMaxLength}:{key}");
|
|
|
@@ -230,7 +231,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
// 预算 + 前缀必须正好等于上限,证明算式与 BuildDedupKey 的格式一致。
|
|
|
var probe = new string('x', budget);
|
|
|
var key = S8TimeoutRuleEvaluator.BuildDedupKey(
|
|
|
- Request().TenantId, Request().FactoryId, RuleCode, "PURCHASE_ORDER_LINE", probe);
|
|
|
+ Request().TenantId, RuleCode, "PURCHASE_ORDER_LINE", probe);
|
|
|
Assert.Equal(S8PurchaseDeliveryDataProvider.DedupKeyMaxLength, key.Length);
|
|
|
}
|
|
|
|
|
|
@@ -241,7 +242,6 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
var longRule = new S8MonitoringDataRequest
|
|
|
{
|
|
|
TenantId = Request().TenantId,
|
|
|
- FactoryId = Request().FactoryId,
|
|
|
DatasetCode = PurchaseDelivery,
|
|
|
RuleCode = RuleCode + "_MUCH_LONGER_SUFFIX",
|
|
|
RuleType = "TIMEOUT"
|
|
|
@@ -305,7 +305,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
new DateTime(2026, 8, 17, 4, 33, 7), new DateTime(2026, 9, 10), "DELAYED"));
|
|
|
|
|
|
var hits = S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- rowSet, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5));
|
|
|
+ rowSet, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5));
|
|
|
|
|
|
var hit = Assert.Single(hits);
|
|
|
Assert.Equal("PO202608260002#3", hit.SourceObjectId);
|
|
|
@@ -321,7 +321,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
new DateTime(2026, 9, 17), new DateTime(2026, 8, 9), "OPEN", supplierName: "怡祥"));
|
|
|
|
|
|
var hits = S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- rowSet, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5));
|
|
|
+ rowSet, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5));
|
|
|
|
|
|
Assert.Empty(hits);
|
|
|
}
|
|
|
@@ -336,7 +336,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
new DateTime(2026, 8, 17, 4, 33, 7), new DateTime(2026, 9, 10), "COMPLETED"));
|
|
|
|
|
|
var hits = S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- rowSet, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5));
|
|
|
+ rowSet, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5));
|
|
|
|
|
|
Assert.Empty(hits);
|
|
|
}
|
|
|
@@ -351,7 +351,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
Row("PO-CANCELLED", "1", new DateTime(2026, 8, 1), null, "CANCELLED"));
|
|
|
|
|
|
var hits = S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- rowSet, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5));
|
|
|
+ rowSet, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5));
|
|
|
|
|
|
Assert.Empty(hits);
|
|
|
}
|
|
|
@@ -363,7 +363,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
var rowSet = RowSet(Row("PO-PARTIAL", "1", new DateTime(2026, 8, 1), null, "PARTIAL"));
|
|
|
|
|
|
var hits = S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- rowSet, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5));
|
|
|
+ rowSet, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5));
|
|
|
|
|
|
Assert.Single(hits);
|
|
|
}
|
|
|
@@ -380,9 +380,9 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
new DateTime(2026, 8, 17, 4, 33, 7), new DateTime(2026, 9, 10), "COMPLETED"));
|
|
|
|
|
|
var hitsBefore = S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- before, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5));
|
|
|
+ before, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5));
|
|
|
var hitsAfter = S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- after, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5));
|
|
|
+ after, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5));
|
|
|
|
|
|
var dedupKey = Assert.Single(hitsBefore).DedupKey;
|
|
|
Assert.Empty(hitsAfter);
|
|
|
@@ -396,12 +396,12 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
new DateTime(2026, 8, 17, 4, 33, 7), new DateTime(2026, 9, 10), "DELAYED"));
|
|
|
|
|
|
var hit = Assert.Single(S8TimeoutRuleEvaluator.EvaluateRows(
|
|
|
- rowSet, Effective(NewRule()), 838257186181189, 838257186320453, new DateTime(2026, 9, 5)));
|
|
|
+ rowSet, Effective(NewRule()), 838257186181189, new DateTime(2026, 9, 5)));
|
|
|
|
|
|
Assert.Equal("PURCHASE_DELIVERY_ABNORMAL", hit.ExceptionTypeCode);
|
|
|
Assert.Equal("PURCHASE_ORDER_LINE", hit.SourceObjectType);
|
|
|
Assert.Equal("PO202608260002#3", hit.SourceObjectId);
|
|
|
- Assert.Equal("T838257186181189:F838257186320453:RRULE_S4_PURCHASE_DELIVERY_DATE_DELAY:PURCHASE_ORDER_LINE:PO202608260002#3",
|
|
|
+ Assert.Equal("T838257186181189:RRULE_S4_PURCHASE_DELIVERY_DATE_DELAY:PURCHASE_ORDER_LINE:PO202608260002#3",
|
|
|
hit.DedupKey);
|
|
|
|
|
|
// 诊断列必须随 payload 落盘:remaining_qty 供后续数据治理观察,
|
|
|
@@ -436,7 +436,7 @@ public class S8PurchaseDeliveryProviderMappingTests
|
|
|
NullLogger<S8MonitoringDataGateway>.Instance);
|
|
|
|
|
|
var ex = await Assert.ThrowsAsync<S8RuleEvaluatorException>(() =>
|
|
|
- gateway.LoadAsync(838257186181189, 838257186320453, NewRule(), "TIMEOUT", 1000));
|
|
|
+ gateway.LoadAsync(838257186181189, NewRule(), "TIMEOUT", 1000));
|
|
|
|
|
|
Assert.Equal(S8DatasetReasonCode.QueryFailed, ex.Reason);
|
|
|
}
|