|
|
@@ -155,8 +155,8 @@ public class S8OrderDeliveryRule02Tests
|
|
|
|
|
|
// ETA 必须来自源系统字段,且缺失即出局。
|
|
|
// (「ETA 是否晚于交期」不在这里判 —— 那是 evaluator 的事,见 T6 / T15 / T16。)
|
|
|
- Assert.Contains("e.sys_capacity_date IS NOT NULL", sql, StringComparison.Ordinal);
|
|
|
- Assert.Contains("DATEDIFF(e.sys_capacity_date, e.plan_date)", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("s.capacity_date IS NOT NULL", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("DATEDIFF(s.capacity_date, s.plan_delivery_date)", sql, StringComparison.Ordinal);
|
|
|
|
|
|
// 以下任何一个出现,都意味着有人在自造 ETA:
|
|
|
// DATE_ADD / DATE_SUB / INTERVAL → 用「交期前 N 天」冒充预测
|
|
|
@@ -194,11 +194,11 @@ public class S8OrderDeliveryRule02Tests
|
|
|
Assert.DoesNotContain("CURDATE", sql, StringComparison.OrdinalIgnoreCase);
|
|
|
Assert.DoesNotContain("CURRENT_DATE", sql, StringComparison.OrdinalIgnoreCase);
|
|
|
Assert.DoesNotContain("@Now", sql, StringComparison.OrdinalIgnoreCase);
|
|
|
- Assert.DoesNotContain("e.sys_capacity_date > e.plan_date", sql, StringComparison.Ordinal);
|
|
|
+ Assert.DoesNotContain("s.capacity_date > s.plan_delivery_date", sql, StringComparison.Ordinal);
|
|
|
|
|
|
// 反面:取数仍必须要求 ETA 存在 —— 没有 ETA 就没有判定依据,
|
|
|
// 这条过滤与生命周期无关,去掉它会让 350 条无 ETA 的行涌进来。
|
|
|
- Assert.Contains("e.sys_capacity_date IS NOT NULL", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("s.capacity_date IS NOT NULL", sql, StringComparison.Ordinal);
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
@@ -206,10 +206,10 @@ public class S8OrderDeliveryRule02Tests
|
|
|
{
|
|
|
var sql = SqlWithoutComments();
|
|
|
|
|
|
- Assert.Contains("e.tenant_id = @TenantId", sql, StringComparison.Ordinal);
|
|
|
- Assert.Contains("o.closed = 0", sql, StringComparison.Ordinal);
|
|
|
- Assert.Contains("o.IsDeleted = 0", sql, StringComparison.Ordinal);
|
|
|
- Assert.Contains("e.IsDeleted = 0", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("s.tenant_id = @TenantId", sql, StringComparison.Ordinal);
|
|
|
+ // 中台标准层把源侧的 o.closed / o.IsDeleted / e.IsDeleted 归一为两个标准列。
|
|
|
+ Assert.Contains("IFNULL(s.closed, 0) = 0", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("IFNULL(s.deleted_flag, 0) = 0", sql, StringComparison.Ordinal);
|
|
|
|
|
|
// 租户是唯一的安全边界(Phase 1 拍板)。补 factory_id 过滤会让规则恒返 0 行且不报错。
|
|
|
Assert.DoesNotContain("factory_id", sql, StringComparison.OrdinalIgnoreCase);
|
|
|
@@ -232,13 +232,16 @@ public class S8OrderDeliveryRule02Tests
|
|
|
var sql = SqlWithoutComments();
|
|
|
|
|
|
// 身份 = 单号 + 行号。退化成单号会让同一张订单的多个风险行只留下一条异常。
|
|
|
- Assert.Contains("CONCAT(e.bill_no, '#', e.entry_seq)", sql, StringComparison.Ordinal);
|
|
|
- Assert.Contains("e.entry_seq IS NOT NULL", sql, StringComparison.Ordinal);
|
|
|
- Assert.Contains("e.bill_no <> ''", sql, StringComparison.Ordinal);
|
|
|
-
|
|
|
- // 明细挂在 crm_seorderentry 上;主表只用来取客户与关闭状态。
|
|
|
- Assert.Contains("FROM crm_seorderentry e", sql, StringComparison.Ordinal);
|
|
|
- Assert.Contains("JOIN crm_seorder o ON o.Id = e.seorder_id", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("CONCAT(s.order_no, '#', s.order_line)", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("s.order_line IS NOT NULL", sql, StringComparison.Ordinal);
|
|
|
+ Assert.Contains("s.order_no <> ''", sql, StringComparison.Ordinal);
|
|
|
+
|
|
|
+ // 数据来自中台标准层。原先的「明细 JOIN 主表」已在中台侧内化:
|
|
|
+ // mdp_std_so 本身就是订单行 ⋈ 订单头的产物,消费者不再需要认识这两张业务表。
|
|
|
+ Assert.Contains("FROM mdp_std_so s", sql, StringComparison.Ordinal);
|
|
|
+ Assert.DoesNotContain("crm_seorderentry", sql, StringComparison.Ordinal);
|
|
|
+ Assert.DoesNotContain("crm_seorder", sql, StringComparison.Ordinal);
|
|
|
+ Assert.DoesNotContain("JOIN", sql, StringComparison.OrdinalIgnoreCase);
|
|
|
}
|
|
|
|
|
|
[Fact]
|