|
|
@@ -459,6 +459,18 @@ public class S8ConfigDraftService : ITransient
|
|
|
private const string ValuePlaceholderExpression =
|
|
|
"SELECT 'DEMO-OBJECT-001' AS related_object_code, 'DEMO-OBJECT-001' AS source_object_id, 'DEMO-OBJECT-001' AS related_object_name, 0 AS measured_value WHERE 1=0";
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// 含逻辑删除字段的源表追加过滤,避免规则启用后误命中已软删行。
|
|
|
+ /// 当前仅 ic_item_stock 含 IsDeleted bit(1);其他表无 schema 元数据,不追加。
|
|
|
+ /// </summary>
|
|
|
+ private static string BuildSoftDeletePredicate(string? sourceTable)
|
|
|
+ {
|
|
|
+ if (string.IsNullOrWhiteSpace(sourceTable)) return string.Empty;
|
|
|
+ if (sourceTable.Equals("ic_item_stock", StringComparison.OrdinalIgnoreCase))
|
|
|
+ return " AND IsDeleted = 0";
|
|
|
+ return string.Empty;
|
|
|
+ }
|
|
|
+
|
|
|
private static string BuildExpression(string mechanism, AdoS8MonitorObject monitorObject, AdoS8MonitorMetric metric, S8WizardFormV1 form)
|
|
|
{
|
|
|
var sourceTable = NormalizeOrNull(monitorObject.SourceTable);
|
|
|
@@ -493,7 +505,8 @@ public class S8ConfigDraftService : ITransient
|
|
|
stateClause = $" AND {statusCol} NOT IN ({quoted})";
|
|
|
}
|
|
|
|
|
|
- return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {dueCol} AS due_at, {statusCol} AS status FROM {table} WHERE {dueCol} IS NOT NULL AND {dueCol} < {graceClause}{stateClause}";
|
|
|
+ var softDeleteClause = BuildSoftDeletePredicate(table);
|
|
|
+ return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {dueCol} AS due_at, {statusCol} AS status FROM {table} WHERE {dueCol} IS NOT NULL AND {dueCol} < {graceClause}{stateClause}{softDeleteClause}";
|
|
|
}
|
|
|
|
|
|
if (mechanism == "VALUE_RANGE")
|
|
|
@@ -507,7 +520,8 @@ public class S8ConfigDraftService : ITransient
|
|
|
if (upper.HasValue) preds.Add($"{mvCol} > {upper.Value.ToString(CultureInfo.InvariantCulture)}");
|
|
|
var oorClause = preds.Count > 0 ? " AND (" + string.Join(" OR ", preds) + ")" : string.Empty;
|
|
|
|
|
|
- return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {mvCol} AS measured_value FROM {table} WHERE {mvCol} IS NOT NULL{oorClause}";
|
|
|
+ var softDeleteClause = BuildSoftDeletePredicate(table);
|
|
|
+ return $"SELECT {idCol} AS source_object_id, {codeCol} AS related_object_code, {nameCol} AS related_object_name, {mvCol} AS measured_value FROM {table} WHERE {mvCol} IS NOT NULL{oorClause}{softDeleteClause}";
|
|
|
}
|
|
|
|
|
|
// RATIO 在上游已被拒绝(metric.Enabled=false 触发 400),此处兜底返回数值占位。
|