|
|
@@ -432,7 +432,9 @@ public class S8OrderFlowService : ITransient
|
|
|
return await BuildBaselineAggregateAsync(tenantId, factoryId, scope);
|
|
|
|
|
|
if (string.Equals(scope, ScopeCurrentFiltered, StringComparison.OrdinalIgnoreCase))
|
|
|
- return await BuildCurrentAggregateAsync(tenantId, factoryId, scope, query.OrderCodes);
|
|
|
+ // S8-STEP5B-P2-FILTER-SUBSET-CERT-1:与 4 个 pivot 端点统一走 CSV 拆分,
|
|
|
+ // 不再依赖默认集合绑定(多订单会被绑成单元素、过滤静默失效)。
|
|
|
+ return await BuildCurrentAggregateAsync(tenantId, factoryId, scope, ParseOrderCodesCsv(query.OrderCodes));
|
|
|
|
|
|
return EmptyAggregate(scope);
|
|
|
}
|
|
|
@@ -515,9 +517,16 @@ public class S8OrderFlowService : ITransient
|
|
|
.Distinct()
|
|
|
.ToList();
|
|
|
|
|
|
+ // S8-STEP5B-ORDER-CHAIN-CLOSURE-1(B):移除 source_object_type == "SALES_ORDER" 过滤,
|
|
|
+ // 与 ORDER_EXEC F-1 同源修复。本方法的统计口径由 BuildObjectStat 定义为
|
|
|
+ // 「命中候选异常类型的**去重 RelatedObjectCode** 数」——即「有多少张销售订单存在该类异常」,
|
|
|
+ // 关联键就是 related_object_code;source_object_type 描述的是**触发对象类型**
|
|
|
+ // (SHIPMENT / PURCHASE_ORDER / WORK_ORDER / NULL …),与订单归属正交。
|
|
|
+ // 实测:命中候选类型的 3 条 Golden 异常(GEX-020-FAW / -PEND / -SHIP)无一为 SALES_ORDER,
|
|
|
+ // 原过滤令末端协同面板恒为「影响订单 0 单 / 主要风险 --」。
|
|
|
+ // 作用域安全性不变:tenant / factory / orderCodes 三重边界保留。
|
|
|
var rows = await _exceptionRep.AsQueryable()
|
|
|
.Where(e => e.TenantId == tenantId && e.FactoryId == factoryId && !e.IsDeleted)
|
|
|
- .Where(e => e.SourceObjectType == ExceptionSourceObjectType)
|
|
|
.Where(e => e.ExceptionTypeCode != null && allTypes.Contains(e.ExceptionTypeCode!))
|
|
|
.WhereIF(orderCodes != null && orderCodes.Count > 0,
|
|
|
e => e.RelatedObjectCode != null && orderCodes!.Contains(e.RelatedObjectCode!))
|
|
|
@@ -595,13 +604,21 @@ public class S8OrderFlowService : ITransient
|
|
|
var total = rows.Count;
|
|
|
|
|
|
dto.KpiAvgDays = AvgOrZero(plannedList);
|
|
|
- dto.ActualAvgDays = AvgOrZero(actualList);
|
|
|
+ // S8-STEP5B-ORDER-CHAIN-CLOSURE-1:与 BASELINE_PPT snapshot 的存储精度对齐(1 位小数)。
|
|
|
+ // 必须显式 AwayFromZero:Math.Round 默认银行家舍入(ToEven)会把 BODY_PRODUCTION 的 5.25 舍成 5.2,
|
|
|
+ // 而 snapshot 存的是 5.3,两个 scope 又会不一致。
|
|
|
+ dto.ActualAvgDays = Math.Round(AvgOrZero(actualList), 1, MidpointRounding.AwayFromZero);
|
|
|
dto.Green = green;
|
|
|
dto.Yellow = yellow;
|
|
|
dto.Red = red;
|
|
|
dto.Pending = pending;
|
|
|
- // 整数百分比;total 不含 0 因为上面已 short-circuit。 percent 因子 100 是公式系数,非业务真值。
|
|
|
- dto.OnTimeRate = total > 0 ? (int)Math.Round(green * 100.0 / total) : 0;
|
|
|
+ // S8-STEP5B-ORDER-CHAIN-CLOSURE-1:按期达成率**排除 pending**(尚未到达的阶段既非按期也非延期,
|
|
|
+ // 计入分母会系统性低估)。原实现用 green/total(含 pending),与 BASELINE_PPT snapshot 的
|
|
|
+ // green/(total-pending) 口径不一致——实测 BODY_PRODUCTION 100 vs 80、FINAL_ASSEMBLY 100 vs 60。
|
|
|
+ // 本项目既有约定同样排除未完成项:ORDER_FLOW_CYCLE_RATIO 只统计 actual_days 非空的阶段,
|
|
|
+ // ORDER_DELIVERY_RATE 只统计已完工订单。故此处对齐 snapshot 与既有约定,而非改写 snapshot 数据。
|
|
|
+ var settled = total - pending;
|
|
|
+ dto.OnTimeRate = settled > 0 ? (int)Math.Round(green * 100.0 / settled) : 0;
|
|
|
return dto;
|
|
|
}
|
|
|
|