using Admin.NET.Plugin.AiDOP.Infrastructure.S8;
using Admin.NET.Plugin.AiDOP.Service.S8.Rules.DataAccess;
using Admin.NET.Plugin.AiDOP.Service.S8.Rules.DataAccess.Providers;
namespace Admin.NET.Plugin.AiDOP.Service.S8.Rules.Definitions;
///
/// S8 正式规则定义的集中登记处(当前仅 Rule 01)。
///
/// 集中一处而非每规则一个文件,理由与 相同:
/// 重复 rule_code 在数组里人工一眼可查;新增规则只加一个元素,不必再改 Startup.cs。
///
public sealed class S8PurchaseDeliveryRuleDefinitions : IS8RuleDefinitionSource
{
/// Rule 01 编码。全链身份,任何地方引用必须逐字用本常量,不写字面量。
public const string PurchaseDeliveryDateDelayCode = "RULE_S4_PURCHASE_DELIVERY_DATE_DELAY";
/// Rule 01 建单使用的异常类型。
public const string PurchaseDeliveryExceptionTypeCode = "PURCHASE_DELIVERY_ABNORMAL";
/// Rule 01 源对象类型。**参与 dedup_key**。
public const string PurchaseOrderLineObjectType = "PURCHASE_ORDER_LINE";
public IEnumerable GetDefinitions() => new[]
{
new S8RuleDefinition
{
RuleCode = PurchaseDeliveryDateDelayCode,
DisplayName = "采购交期延误",
Description =
"采购订单行已过约定到期日仍未完成交付时提报异常。" +
"到期日取交付计划需求日期,缺失时回落采购订单到期日;" +
"已完成 / 已关闭 / 已取消的订单行不再判为延误。",
DatasetCode = S8BusinessDatasetDefinitions.PurchaseDeliveryCode,
RuleType = S8TimeoutRuleEvaluator.RuleTypeCode,
RuleMechanism = "DATE",
SourceObjectType = PurchaseOrderLineObjectType,
SceneCode = S8ModuleCode.S4,
StageCode = S8ModuleCode.S4,
OrderFlowCode = "MATERIAL_PURCHASE",
ExceptionTypeCode = PurchaseDeliveryExceptionTypeCode,
// 面向业务管理员的只读说明。刻意不写 dwd_supplier_delivery / COALESCE / 列名 ——
// 配置页展示的是"这条规则按什么判",不是"它怎么实现的"。
JudgementSummary =
"到期日取交付计划的需求日期;该日期缺失时回落为采购订单的到期日。"
+ "订单行状态为已完成 / 已关闭 / 已取消时不再判为延误。",
DedupIdentitySummary = "采购订单号 + 订单行号",
// ────────────────────────────────────────────────────────────────
// 判定语义。四个列名都是 canonical 名 —— Provider 直接以这些名字产出行
// (见 S8PurchaseDeliveryDataProvider 的 SELECT 别名契约)。
//
// due_at 的血缘已完成取证:Provider 的 COALESCE(need_date, due_date)
// 与数据中台自身的 DELAYED 判据
// COALESCE(交付计划 need_date, 采购订单 need_date, 采购订单 due_date) < now
// 展开后逐字等价(S3MdpSyncTransformService 的 dwd_supplier_delivery INSERT)。
// 实测佐证:UAT 租户最新快照 36 行,evaluator 命中 28 条,
// 与中台自行标记的 DELAYED 28 条完全一致。
//
// ⚠️ UNPROVEN_CONTRACT_SEMANTICS:以上只证明 S8 与中台口径一致,
// 并未证明 need_date 等同于与供应商约定的承诺交期。该问题需追至源系统
// PurOrdDetail.NeedDate 并由业务确认,在此之前 due_at 不得被当作交付合同依据。
// ────────────────────────────────────────────────────────────────
Timeout = new S8TimeoutSemantics
{
DueAtColumn = S8CanonicalColumns.DueAt,
StatusColumn = S8CanonicalColumns.Status,
// 去重身份 = po_no + '#' + po_line,由 Provider 拼好后放在 source_object_id 列。
// 真库证据:dwd_supplier_delivery 全表 39854 行 / 4 租户 / 97 个快照,
// (tenant_id, stat_date, po_no, po_line) 重复组为 0。
SourceObjectIdColumn = S8CanonicalColumns.SourceObjectId,
RelatedObjectCodeColumn = S8CanonicalColumns.RelatedObjectCode,
// status 域 = COMPLETED / DELAYED / OPEN / CLOSED / CANCELLED / PARTIAL
// (三个写入方合并取证:S3MdpSyncTransformService / DeliveryScheduleService /
// ProcessOutsourceOrderService)。
// 下列三个视为已完成;DELAYED / OPEN / PARTIAL 均可命中。
CompletedStates = new[] { "COMPLETED", "CLOSED", "CANCELLED" }
},
Parameters = new S8RuleParameterPolicy
{
PollIntervalSecondsDefault = 300,
TriggerCountRequiredDefault = 1,
// 交期类异常抖动主要来自快照切换,连续两次未命中才判恢复。
RecoverCountRequiredDefault = 2,
GraceMinutesDefault = 0,
SeverityDefault = S8SeverityCode.Serious,
AllowsDepartmentDefaults = true,
// S8-RULE-READINESS-1:本规则的数据集 dwd_supplier_delivery **没有部门列**,
// 命中行带不出 occurrence / responsible,建单时部门只能来自这两个运行参数。
// 不配就是「启用成功、调度成功、异常一条建不出来」——各层都报成功的静默失败。
// 故声明为启用前置条件,由 S8RuleReadinessGate 在三条执行入口统一拦截。
RequiresDepartmentDefaultsForEnable = true
}
}
};
}