| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- using Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
- namespace Admin.NET.Plugin.AiDOP.SeedData;
- /// <summary>
- /// S8-ORDER-CHAIN-BODY-PRODUCTION-ORDER-LEVEL-SEED-FIX-1:本体生产「工序明细」/「损失因素」/「操作员表现」三表 seed。
- ///
- /// ──────────────────────────────────────────────────────────────────────
- /// S8-...-FIX-1S(阶段 2 失败修正):本项目实际 SEED 数据落地路径是 UpdateScripts SQL
- /// 的 DELETE+INSERT(与 procurement 1.0.148.sql 模式一致),不是 SqlSugar IncreSeed
- /// 自动写入。阶段 2 实测启动后三表创建成功但 IncreSeed 0 行写入。
- /// 处理:移除 IncreSeed attribute,保留本算法 SOT 作为 SQL 生成依据与未来 IMPORT/AGG
- /// 接入的算法 owner;本批次 221 行 SEED 数据由 WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql
- /// 的 INSERT 语句落地。
- /// ──────────────────────────────────────────────────────────────────────
- ///
- /// baseline 行(order_id=NULL)来自 MANUFACTURING_DETAIL_FIXTURE 逐字段对齐:
- /// - process:(P10/P20/P30/P40/TOTAL) × (pi, actual, plan_qty, rate, status)
- /// - loss factor:(MATERIAL/EQUIPMENT/QUALITY/EFFICIENCY/SUBTOTAL) × (count, ratio_pct, loss_hours)
- /// - operator:(张/李/王) × (avg_hours, status)
- ///
- /// 订单级行(order_id≠NULL,scenario=ORDER_LEVEL):
- /// 对每个 BODY_PRODUCTION stage.status != "pending" 的订单(16 单),按 A=stage.actualDays 与 baseline 比例派生:
- /// ratio = A / 6.8
- /// process 行:
- /// baseline_actuals = [2.4, 0.8, 3.0, 0.6]
- /// actual[0..2] = round(baseline_actuals[i] * A / 6.8, 3)
- /// actual[3] = A - sum(actual[0..2]) // 守恒尾差修正
- /// plan_qty[i] = round(baseline_plan[i] * ratio)
- /// achievement_rate[i] = baseline_rate[i] (per-process 固定属性)
- /// achievement_status[i] = ≥0.95 green / ≥0.80 yellow / 否则 red (由 rate 派生)
- /// cycle_status[i] = ≤pi green / ≤pi*1.2 yellow / 否则 red (由 actual vs pi 派生)
- /// TOTAL 行:pi=6, actual=A, plan_qty=NULL,
- /// rate=0.9000 / status="yellow" 锚定 fixture (S8-...-FIX-1R),
- /// 不再做 plan_qty 加权计算,与 baseline TOTAL 一致;
- /// cycle_status 仍由 actual vs 6 派生。SEED 过渡口径,IMPORT/AGG 接入后替换。
- /// loss factor 行:
- /// count[i] = round(baseline_count[i] * ratio)
- /// ratio_pct[i] = baseline_ratio_pct[i] // 结构保留
- /// loss_hours[i] = round(baseline_loss_hours[i] * ratio, 2)
- /// SUBTOTAL: count=round(30*ratio), ratio_pct=100, loss_hours=round(7.5*ratio,2) // fixture-pinned 比例缩放
- /// operator 行:
- /// avg_hours[i] = round(baseline_hours[i] * ratio, 2)
- /// status[i] = baseline_status[i] // 每操作员固定 status
- ///
- /// 真实数据源(IMPORT / AGG)接入后,service 优先采用 IMPORT/AGG,同 (order_code, process/factor/operator) SEED 行仅兜底。
- /// </summary>
- // S8-...-FIX-1S:[IncreSeed] 已移除(项目实际不通过 SqlSugar IncreSeed 自动写入)。
- // 数据落地见 UpdateScripts/WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql 的 INSERT。
- public class S8OrderFlowManufacturingProcessSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowManufacturingProcess>
- {
- public IEnumerable<AdoS8OrderFlowManufacturingProcess> HasData()
- => S8OrderFlowManufacturingDataset.BuildProcessBaselineRows()
- .Concat(S8OrderFlowManufacturingDataset.BuildProcessOrderLevelRows());
- }
- // S8-...-FIX-1S:[IncreSeed] 已移除(项目实际不通过 SqlSugar IncreSeed 自动写入)。
- // 数据落地见 UpdateScripts/WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql 的 INSERT。
- public class S8OrderFlowManufacturingLossFactorSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowManufacturingLossFactor>
- {
- public IEnumerable<AdoS8OrderFlowManufacturingLossFactor> HasData()
- => S8OrderFlowManufacturingDataset.BuildLossFactorBaselineRows()
- .Concat(S8OrderFlowManufacturingDataset.BuildLossFactorOrderLevelRows());
- }
- // S8-...-FIX-1S:[IncreSeed] 已移除(项目实际不通过 SqlSugar IncreSeed 自动写入)。
- // 数据落地见 UpdateScripts/WIP-S8-BODY-PRODUCTION-ORDER-LEVEL-SEED.sql 的 INSERT。
- public class S8OrderFlowManufacturingOperatorSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowManufacturingOperator>
- {
- public IEnumerable<AdoS8OrderFlowManufacturingOperator> HasData()
- => S8OrderFlowManufacturingDataset.BuildOperatorBaselineRows()
- .Concat(S8OrderFlowManufacturingDataset.BuildOperatorOrderLevelRows());
- }
- internal static class S8OrderFlowManufacturingDataset
- {
- // ─────────────── ID base ranges(与 procurement-pivot 同号段策略) ───────────────
- internal const long ProcessBaselineIdBase = 1329909160000L;
- internal const long ProcessOrderLevelIdBase = 1329909170000L;
- internal const long LossFactorBaselineIdBase = 1329909180000L;
- internal const long LossFactorOrderLevelIdBase = 1329909190000L;
- internal const long OperatorBaselineIdBase = 1329909200000L;
- internal const long OperatorOrderLevelIdBase = 1329909210000L;
- internal const string ScenarioBaseline = "BASELINE_PPT";
- internal const string ScenarioOrderLevel = "ORDER_LEVEL";
- // BODY_PRODUCTION 在 5 阶段流水中固定为索引 3(order_review→product_design→material_procurement→body_production→final_assembly_shipping)。
- private const int BodyProductionStageIndex = 3;
- // ─────────────── baseline 真值(与 MANUFACTURING_DETAIL_FIXTURE 逐字段对齐) ───────────────
- private sealed record ProcessBaseline(
- int SortNo, string Code, string Name,
- decimal Pi, decimal Actual,
- int? PlanQty, decimal? Rate, string AchStatus);
- /// <summary>fixture 工序基线:(sort, code, name, pi, actual, plan, rate, ach_status)。</summary>
- private static readonly ProcessBaseline[] ProcessBaselines =
- {
- new(1, "P10", "10工序", 1.0m, 2.4m, 45, 0.5500m, "red"),
- new(2, "P20", "20工序", 1.0m, 0.8m, 3, 0.9700m, "yellow"),
- new(3, "P30", "30工序", 2.5m, 3.0m, 15, 0.8500m, "green"),
- new(4, "P40", "40工序", 1.5m, 0.6m, 2, 0.9800m, "red"),
- // TOTAL:pi=6, actual=6.8, plan_qty=NULL, rate=0.90 (fixture-pinned), achievement_status=yellow(来自 fixture 表格颜色)。
- new(5, "TOTAL", "合计", 6.0m, 6.8m, null, 0.9000m, "yellow"),
- };
- private sealed record LossFactorBaseline(
- int SortNo, string Code, string Name,
- int? Count, decimal? RatioPct, decimal? LossHours);
- /// <summary>fixture 损失因素基线:(sort, code, name, count, ratio_pct, loss_hours)。</summary>
- /// <remarks>SUBTOTAL loss_hours=7.50 来自 fixture,不等于 4 因素之和 26.15;保留 fixture 锚定。</remarks>
- private static readonly LossFactorBaseline[] LossFactorBaselines =
- {
- new(1, "MATERIAL", "材料影响", 9, 30.00m, 9.00m),
- new(2, "EQUIPMENT", "设备影响", 6, 20.00m, 4.50m),
- new(3, "QUALITY", "质量影响", 3, 10.00m, 3.40m),
- new(4, "EFFICIENCY", "作业效率损失", 12, 40.00m, 9.25m),
- new(5, "SUBTOTAL", "损失小计", 30, 100.00m, 7.50m),
- };
- private sealed record OperatorBaseline(int SortNo, string Code, string Name, decimal Hours, string Status);
- /// <summary>fixture 操作员基线:(sort, code, name, avg_hours, status)。</summary>
- private static readonly OperatorBaseline[] OperatorBaselines =
- {
- new(1, "OP_ZHANG", "张师傅", 20.00m, "red"),
- new(2, "OP_LI", "李师傅", 10.00m, "yellow"),
- new(3, "OP_WANG", "王师傅", 8.00m, "green"),
- };
- /// <summary>baseline TOTAL.actual_days(6.8)作为订单级 ratio = A/6.8 的归一化分母。</summary>
- private const decimal BaselineTotalActualDays = 6.8m;
- private const decimal BaselineTotalPiDays = 6.0m;
- // ────────────────────────────────────────────────────────────
- // Process 行
- // ────────────────────────────────────────────────────────────
- public static IEnumerable<AdoS8OrderFlowManufacturingProcess> BuildProcessBaselineRows()
- {
- long seq = 0;
- foreach (var b in ProcessBaselines)
- {
- yield return new AdoS8OrderFlowManufacturingProcess
- {
- Id = ProcessBaselineIdBase + (++seq),
- OrderId = null,
- OrderCode = null,
- ProcessCode = b.Code,
- ProcessName = b.Name,
- PiDays = b.Pi,
- ActualDays = b.Actual,
- CycleStatus = ClassifyCycleStatus(b.Actual, b.Pi),
- PlanQty = b.PlanQty,
- AchievementRate = b.Rate,
- AchievementStatus = b.AchStatus,
- SortNo = b.SortNo,
- ScenarioCode = ScenarioBaseline,
- DataSource = "SEED",
- TenantId = 1,
- FactoryId = 1,
- CreatedAt = S8OrderFlowDataset.CreatedAt,
- UpdatedAt = null,
- IsDeleted = false,
- };
- }
- }
- public static IEnumerable<AdoS8OrderFlowManufacturingProcess> BuildProcessOrderLevelRows()
- {
- long seq = 0;
- foreach (var spec in S8OrderFlowDataset.Specs)
- {
- var lifecycle = S8OrderFlowStageDataset.BuildLifecycleValues(spec);
- var stage = lifecycle[BodyProductionStageIndex];
- if (stage.status == "pending") continue;
- var A = stage.actualDays;
- var ratio = A / BaselineTotalActualDays;
- var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
- // 4 个工序 actual:前 3 个直接缩放,第 4 个尾差修正以满足 sum == A。
- var actuals = new decimal[4];
- decimal sumFirstThree = 0m;
- for (var i = 0; i < 3; i++)
- {
- actuals[i] = decimal.Round(ProcessBaselines[i].Actual * ratio, 3);
- sumFirstThree += actuals[i];
- }
- actuals[3] = decimal.Round(A - sumFirstThree, 3);
- // 4 工序 plan_qty(TOTAL 行不计入;取 baseline.PlanQty 非 null 即可,TOTAL 是第 5 行)
- var planQtys = new int[4];
- for (var i = 0; i < 4; i++)
- {
- var basePlan = ProcessBaselines[i].PlanQty ?? 0;
- planQtys[i] = (int)decimal.Round(basePlan * ratio, MidpointRounding.AwayFromZero);
- }
- // 4 工序行
- for (var i = 0; i < 4; i++)
- {
- var baseRow = ProcessBaselines[i];
- var rate = baseRow.Rate!.Value;
- yield return new AdoS8OrderFlowManufacturingProcess
- {
- Id = ProcessOrderLevelIdBase + (++seq),
- OrderId = orderId,
- OrderCode = spec.OrderCode,
- ProcessCode = baseRow.Code,
- ProcessName = baseRow.Name,
- PiDays = baseRow.Pi,
- ActualDays = actuals[i],
- CycleStatus = ClassifyCycleStatus(actuals[i], baseRow.Pi),
- PlanQty = planQtys[i],
- AchievementRate = rate,
- AchievementStatus = ClassifyAchievementStatus(rate),
- SortNo = baseRow.SortNo,
- ScenarioCode = ScenarioOrderLevel,
- DataSource = "SEED",
- TenantId = 1,
- FactoryId = 1,
- CreatedAt = S8OrderFlowDataset.CreatedAt,
- UpdatedAt = null,
- IsDeleted = false,
- };
- }
- // TOTAL 行:plan_qty=NULL。
- // S8-...-FIX-1R:achievement_rate / achievement_status 锚定 fixture(ProcessBaselines[4],
- // 即 0.9000 / yellow),不再用 4 工序 plan_qty 加权计算,与 baseline TOTAL 保持一致。
- // SEED 过渡口径;真实 IMPORT/AGG 接入后由真实生产达成数据替换。
- var fixtureTotalRate = ProcessBaselines[4].Rate!.Value; // 0.9000m
- var fixtureTotalStatus = ProcessBaselines[4].AchStatus; // "yellow"
- yield return new AdoS8OrderFlowManufacturingProcess
- {
- Id = ProcessOrderLevelIdBase + (++seq),
- OrderId = orderId,
- OrderCode = spec.OrderCode,
- ProcessCode = ProcessBaselines[4].Code,
- ProcessName = ProcessBaselines[4].Name,
- PiDays = BaselineTotalPiDays,
- ActualDays = decimal.Round(A, 3),
- CycleStatus = ClassifyCycleStatus(A, BaselineTotalPiDays),
- PlanQty = null,
- AchievementRate = fixtureTotalRate,
- AchievementStatus = fixtureTotalStatus,
- SortNo = ProcessBaselines[4].SortNo,
- ScenarioCode = ScenarioOrderLevel,
- DataSource = "SEED",
- TenantId = 1,
- FactoryId = 1,
- CreatedAt = S8OrderFlowDataset.CreatedAt,
- UpdatedAt = null,
- IsDeleted = false,
- };
- }
- }
- // ────────────────────────────────────────────────────────────
- // Loss factor 行
- // ────────────────────────────────────────────────────────────
- public static IEnumerable<AdoS8OrderFlowManufacturingLossFactor> BuildLossFactorBaselineRows()
- {
- long seq = 0;
- foreach (var b in LossFactorBaselines)
- {
- yield return new AdoS8OrderFlowManufacturingLossFactor
- {
- Id = LossFactorBaselineIdBase + (++seq),
- OrderId = null,
- OrderCode = null,
- FactorCode = b.Code,
- FactorName = b.Name,
- CountValue = b.Count,
- RatioPct = b.RatioPct,
- LossHours = b.LossHours,
- SortNo = b.SortNo,
- ScenarioCode = ScenarioBaseline,
- DataSource = "SEED",
- TenantId = 1,
- FactoryId = 1,
- CreatedAt = S8OrderFlowDataset.CreatedAt,
- UpdatedAt = null,
- IsDeleted = false,
- };
- }
- }
- public static IEnumerable<AdoS8OrderFlowManufacturingLossFactor> BuildLossFactorOrderLevelRows()
- {
- long seq = 0;
- foreach (var spec in S8OrderFlowDataset.Specs)
- {
- var lifecycle = S8OrderFlowStageDataset.BuildLifecycleValues(spec);
- var stage = lifecycle[BodyProductionStageIndex];
- if (stage.status == "pending") continue;
- var A = stage.actualDays;
- var ratio = A / BaselineTotalActualDays;
- var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
- foreach (var b in LossFactorBaselines)
- {
- int? count = b.Count.HasValue
- ? (int)decimal.Round(b.Count.Value * ratio, MidpointRounding.AwayFromZero)
- : null;
- decimal? hours = b.LossHours.HasValue
- ? decimal.Round(b.LossHours.Value * ratio, 2)
- : null;
- yield return new AdoS8OrderFlowManufacturingLossFactor
- {
- Id = LossFactorOrderLevelIdBase + (++seq),
- OrderId = orderId,
- OrderCode = spec.OrderCode,
- FactorCode = b.Code,
- FactorName = b.Name,
- CountValue = count,
- RatioPct = b.RatioPct, // 结构保留:baseline ratio_pct 原值复制
- LossHours = hours,
- SortNo = b.SortNo,
- ScenarioCode = ScenarioOrderLevel,
- DataSource = "SEED",
- TenantId = 1,
- FactoryId = 1,
- CreatedAt = S8OrderFlowDataset.CreatedAt,
- UpdatedAt = null,
- IsDeleted = false,
- };
- }
- }
- }
- // ────────────────────────────────────────────────────────────
- // Operator 行
- // ────────────────────────────────────────────────────────────
- public static IEnumerable<AdoS8OrderFlowManufacturingOperator> BuildOperatorBaselineRows()
- {
- long seq = 0;
- foreach (var b in OperatorBaselines)
- {
- yield return new AdoS8OrderFlowManufacturingOperator
- {
- Id = OperatorBaselineIdBase + (++seq),
- OrderId = null,
- OrderCode = null,
- OperatorCode = b.Code,
- OperatorName = b.Name,
- AvgHours = b.Hours,
- Status = b.Status,
- SortNo = b.SortNo,
- ScenarioCode = ScenarioBaseline,
- DataSource = "SEED",
- TenantId = 1,
- FactoryId = 1,
- CreatedAt = S8OrderFlowDataset.CreatedAt,
- UpdatedAt = null,
- IsDeleted = false,
- };
- }
- }
- public static IEnumerable<AdoS8OrderFlowManufacturingOperator> BuildOperatorOrderLevelRows()
- {
- long seq = 0;
- foreach (var spec in S8OrderFlowDataset.Specs)
- {
- var lifecycle = S8OrderFlowStageDataset.BuildLifecycleValues(spec);
- var stage = lifecycle[BodyProductionStageIndex];
- if (stage.status == "pending") continue;
- var A = stage.actualDays;
- var ratio = A / BaselineTotalActualDays;
- var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
- foreach (var b in OperatorBaselines)
- {
- var hours = decimal.Round(b.Hours * ratio, 2);
- yield return new AdoS8OrderFlowManufacturingOperator
- {
- Id = OperatorOrderLevelIdBase + (++seq),
- OrderId = orderId,
- OrderCode = spec.OrderCode,
- OperatorCode = b.Code,
- OperatorName = b.Name,
- AvgHours = hours,
- Status = b.Status, // 结构保留:每操作员固定 status
- SortNo = b.SortNo,
- ScenarioCode = ScenarioOrderLevel,
- DataSource = "SEED",
- TenantId = 1,
- FactoryId = 1,
- CreatedAt = S8OrderFlowDataset.CreatedAt,
- UpdatedAt = null,
- IsDeleted = false,
- };
- }
- }
- }
- // ────────────────────────────────────────────────────────────
- // status classifiers(seed-time 一次性,运行期不再重判)
- // ────────────────────────────────────────────────────────────
- /// <summary>cycle_status:actual ≤ pi → green;≤ pi*1.2 → yellow;否则 red。</summary>
- private static string ClassifyCycleStatus(decimal actual, decimal pi)
- {
- if (actual <= pi) return "green";
- if (actual <= pi * 1.2m) return "yellow";
- return "red";
- }
- /// <summary>achievement_status:rate ≥ 0.95 green / ≥ 0.80 yellow / 否则 red。</summary>
- private static string ClassifyAchievementStatus(decimal rate)
- {
- if (rate >= 0.95m) return "green";
- if (rate >= 0.80m) return "yellow";
- return "red";
- }
- }
|