using Xunit; namespace Admin.NET.Plugin.AiDOP.Tests.SmartOps; public class MissingKpiPipelineContractTests { [Fact] public void S3MaterialTurnover_UsesTenantScopedInboundAndIssueFacts() { var source = ReadSource("Supply", "S3MdpSyncTransformService.cs"); Assert.Contains("MetricCode = \"S3_L1_004\"", source); Assert.Contains("h.tenant_id=@TenantId", source); Assert.Contains("h.lbs IN ('采购入库','生产领料')", source); Assert.Contains("NULLIF(SUM(issue_qty), 0)", source); Assert.Contains("GlobalRunGate.WaitAsync", source); Assert.Contains("GlobalRunGate.Release", source); } [Fact] public void S9QualityReturnRate_UsesS7BusinessTransactionsAndPpmScale() { var source = ReadSource("FinishedWarehouse", "S7MdpSyncTransformService.cs"); Assert.Contains("result.MergeSub(\"S9_L1_001\"", source); Assert.Contains("h.lbs IN ('销售退货','销售出库')", source); Assert.Contains("* 1_000_000m", source); Assert.Contains("option, \"S9\")", source); } [Fact] public void GenericDashboard_UsesLatestValuePerMetric() { var source = ReadSource("Controllers", "AidopKanbanController.Generic.cs"); Assert.Contains("v2.metric_code=v.metric_code", source); Assert.DoesNotContain("is_deleted=0 AND biz_date=@d", source); } [Fact] public void S5StageKpis_UseReceiptAndIqcFacts() { var source = ReadSource("MaterialWarehouse", "S5MdpSyncTransformService.cs"); Assert.Contains("result.MergeSub(\"S5_L2_001\"", source); Assert.Contains("result.MergeSub(\"S5_L2_003\"", source); Assert.Contains("source_table='PurOrdRctMaster'", source); Assert.Contains("FINSPESTARTDATE", source); Assert.Contains("ado_s9_kpi_value_l2_day", source); Assert.DoesNotContain("COPY_PARENT_VALUE", source); } [Fact] public void S6WorkOrderCycle_GroupsByWorkOrderNotOrder() { var source = ReadSource("Manufacturing", "S6MdpSyncTransformService.cs"); Assert.Contains("result.MergeSub(\"S6_L2_001\"", source); Assert.Contains("group by rwnoid", source); Assert.Contains("NO_COMPLETED_WORK_ORDER", source); Assert.Contains("L2ValueTable", source); } [Fact] public void S8Snapshot_UsesExceptionTableAndKeepsNullTimeliness() { var source = ReadSource("Service/S8", "S8KpiSnapshotService.cs"); Assert.Contains("FROM ado_s8_exception", source); Assert.Contains("S8_L1_001", source); Assert.Contains("S8_L1_002", source); Assert.Contains("avgHours > 0 ? avgHours : null", source); Assert.DoesNotContain("metric_value=0", source); } private static string ReadSource(string folder, string fileName) { var dir = new DirectoryInfo(AppContext.BaseDirectory); while (dir != null) { var candidate = Path.Combine( dir.FullName, "server", "Plugins", "Admin.NET.Plugin.AiDOP", folder, fileName); if (File.Exists(candidate)) return File.ReadAllText(candidate); dir = dir.Parent; } throw new FileNotFoundException(fileName); } }