namespace Admin.NET.Plugin.AiDOP.DataPlatform; /// /// 中立层 KPI 必填列。某通道的投影 SQL 必须写出这些列,写不出的列登记在 。 /// public static class NeutralRequiredColumns { public sealed record RequiredColumn(string Name, string? SemanticCode); public static IReadOnlyList For(string? stdObject) => string.Equals(stdObject, "INV_TRANS", StringComparison.OrdinalIgnoreCase) ? [ new("location", "INV_LOCATION"), new("lot_serial", "INV_LOT"), new("create_user", "INV_CREATE_USER"), new("end_balance", "INV_END_BALANCE"), new("dimension1", null), new("eff_date", null), // S5_L1_001 物料上线周期、S7_L1_001 订单发货周期都以 approved_time 为唯一时间基准: // 该列整列为空时两个 KPI 只会算出 NO_DATA,且不会报错,故必须当必填列守住。 new("approved_time", null), new("doc_qty", "DOC_QTY_CLOSE"), new("line_closed_flag", "DOC_QTY_CLOSE") ] : []; public static readonly string[] InvTrans = [ "location", "lot_serial", "create_user", "end_balance", "dimension1", "eff_date", "approved_time", "doc_qty", "line_closed_flag" ]; public sealed record Projection(string Channel, string RelativePath, string Marker, string[] Present, string[] Missing); public static readonly Projection[] Channels = [ new("T8", Path.Combine("DataPlatform", "T8BaseInboundMdpSyncService.NeutralProjection.cs"), "ProjectInvTransSql", ["doc_qty", "eff_date", "approved_time", "dimension1", "line_closed_flag", "location", "lot_serial", "create_user", "end_balance"], []), new("PUSH", Path.Combine("DataPlatform", "T8BaseInboundMdpSyncService.NeutralProjection.cs"), "BuildProjectApiInvTransSql", ["location", "lot_serial", "create_user", "end_balance", "doc_qty", "line_closed_flag", "dimension1", "eff_date", "approved_time"], []), new("PULL", Path.Combine("DataPlatform", "T8BaseInboundMdpSyncService.NeutralProjection.cs"), "BuildProjectApiInvTransSql", ["location", "lot_serial", "create_user", "end_balance", "doc_qty", "line_closed_flag", "dimension1", "eff_date", "approved_time"], []), new("165", Path.Combine("MaterialWarehouse", "InventoryMdpSyncService.cs"), "MaterializeInvTransStdAsync", ["location", "lot_serial", "create_user", "end_balance", "doc_qty", "dimension1", "eff_date", "approved_time"], ["line_closed_flag"]), // 165 的销售发运走 ASN 明细单独一段投影(任务 A-3),是 mdp_std_inv_trans 的第二个写入口。 // 它漏掉 approved_time 时 S7 三个指标会一起静默变成 NO_DATA,故必须单列为一个通道守住。 new("165_ASN", Path.Combine("DataPlatform", "Wms", "ShipTransNeutralProjection.cs"), // 标记只写表名:带上 INSERT INTO 会被「中立层写入必须调用来源闸门」的守卫当成写入点。 "mdp_std_inv_trans", ["location", "lot_serial", "create_user", "dimension1", "eff_date", "approved_time", "doc_qty"], ["end_balance", "line_closed_flag"]), // NATIVE 不写 mdp_std_inv_trans(自有数据只进工单、BOM、员工、销售订单行), // 故不参与库存流水必填列的覆盖断言,这里只记它自己的写入方标记。 new("NATIVE", Path.Combine("DataPlatform", "NativeNeutralProjectionService.cs"), "AIDOP_NATIVE", ["written_by"], []) ]; }