Pārlūkot izejas kodu

feat(s8): t2b seed order flow substeps and units

YY968XX 1 mēnesi atpakaļ
vecāks
revīzija
b3068ba183

+ 115 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/SeedData/S8OrderFlowSubstepSeedData.cs

@@ -0,0 +1,115 @@
+using Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
+
+namespace Admin.NET.Plugin.AiDOP.SeedData;
+
+/// <summary>
+/// ORDER-FLOW-S8-INTEGRATED-DOMAIN-RESET-1 t2b:ORDER_REVIEW_PLAN_CALC 阶段 L2 子节点种子。
+/// 20 单 × 5 子节点 = 100 行;SO-2026-001 按 PPT 第 2 页真值;其余 19 单按 (orderIdx, substepIdx)
+/// 派生 multiplier,确定性、可重入,无随机数 / DateTime.Now。
+/// </summary>
+[IncreSeed]
+public class S8OrderFlowSubstepSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowSubstep>
+{
+    public IEnumerable<AdoS8OrderFlowSubstep> HasData() => S8OrderFlowSubstepDataset.BuildSubsteps();
+}
+
+internal static class S8OrderFlowSubstepDataset
+{
+    internal const long SubstepIdBase = 1329909120000L;
+    internal const string FlowCode = "ORDER_REVIEW_PLAN_CALC";
+
+    /// <summary>L2 五子节点固定顺序与 PI 基线工时。</summary>
+    internal static readonly (string Code, string Name, decimal PiHours)[] L2Def =
+    {
+        ("OPINION_REVIEW",   "意见评审",  8m),
+        ("OPINION_FEEDBACK", "意见反馈", 12m),
+        ("SECOND_REVIEW",    "二次评审",  8m),
+        ("LEADER_REVIEW",    "领导意见", 10m),
+        ("CONTRACT_SEAL",    "合同盖章",  2m),
+    };
+
+    /// <summary>SO-2026-001 PPT 第 2 页 L2 真值:actual_hours / status,与 L2Def 同序。</summary>
+    private static readonly (decimal Actual, string Status)[] Ppt001L2 =
+    {
+        (14.4m, "red"),
+        (14.2m, "yellow"),
+        ( 7.0m, "green"),
+        (12.0m, "yellow"),
+        ( 2.0m, "green"),
+    };
+
+    /// <summary>
+    /// 19 个非 PPT 单的 L2 派生 multiplier 桶。
+    /// bucketIdx = (idx - 2 + substepIdx) mod 5,对应 5 种 (multiplier, status) 组合。
+    /// status 满足:multiplier ≤ 1.00 = green;1.00 &lt; multiplier ≤ 1.25 = yellow;&gt; 1.25 = red。
+    /// </summary>
+    private static readonly (decimal Mult, string Status)[] L2Buckets =
+    {
+        (0.90m, "green"),
+        (1.10m, "yellow"),
+        (1.40m, "red"),
+        (1.00m, "green"),
+        (1.20m, "yellow"),
+    };
+
+    public static IEnumerable<AdoS8OrderFlowSubstep> BuildSubsteps()
+    {
+        long seq = 0;
+        foreach (var spec in S8OrderFlowDataset.Specs)
+        {
+            var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
+            var isPpt = spec.OrderCode == "SO-2026-001";
+            var scenario = isPpt ? "PPT" : "DEMO";
+
+            for (var i = 0; i < L2Def.Length; i++)
+            {
+                var (code, name, piHours) = L2Def[i];
+                decimal actual;
+                string status;
+
+                if (isPpt)
+                {
+                    actual = Ppt001L2[i].Actual;
+                    status = Ppt001L2[i].Status;
+                }
+                else
+                {
+                    var bucketIdx = ((spec.Idx - 2) + i) % L2Buckets.Length;
+                    var bucket = L2Buckets[bucketIdx];
+                    actual = decimal.Round(piHours * bucket.Mult, 1);
+                    status = bucket.Status;
+                }
+
+                yield return new AdoS8OrderFlowSubstep
+                {
+                    Id = SubstepIdBase + (++seq),
+                    OrderId = orderId,
+                    OrderCode = spec.OrderCode,
+                    OrderFlowCode = FlowCode,
+                    SubstepCode = code,
+                    SubstepName = name,
+                    PiHours = piHours,
+                    ActualHours = actual,
+                    Status = status,
+                    SortNo = i + 1,
+                    ScenarioCode = scenario,
+                    DataSource = "SEED",
+                    TenantId = 1,
+                    FactoryId = 1,
+                    CreatedAt = S8OrderFlowDataset.CreatedAt,
+                    UpdatedAt = null,
+                    IsDeleted = false,
+                };
+            }
+        }
+    }
+
+    /// <summary>OPINION_REVIEW 在 100 行 substep 中的全局 substep_id(供 unit seed 反查 FK)。</summary>
+    public static long OpinionReviewSubstepId(int orderIdx)
+    {
+        // 每单 5 个 substep,OPINION_REVIEW 是第 1 个(sort_no=1)。
+        // seq 顺序:(idx=1 的 5 个) → (idx=2 的 5 个) → ...
+        // 第 idx 单的 OPINION_REVIEW seq = (idx - 1) * 5 + 1。
+        return SubstepIdBase + (orderIdx - 1) * 5L + 1L;
+    }
+}

+ 107 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/SeedData/S8OrderFlowSubstepUnitSeedData.cs

@@ -0,0 +1,107 @@
+using Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
+
+namespace Admin.NET.Plugin.AiDOP.SeedData;
+
+/// <summary>
+/// ORDER-FLOW-S8-INTEGRATED-DOMAIN-RESET-1 t2b:OPINION_REVIEW 子节点下 L3 责任单元种子。
+/// 20 单 × 4 责任单元 = 80 行,全部挂在 substep_code = OPINION_REVIEW;SO-2026-001 按 PPT 第 2 页真值,
+/// 其余 19 单按 (orderIdx, unitIdx) 派生 multiplier,确定性、可重入。
+/// </summary>
+[IncreSeed]
+public class S8OrderFlowSubstepUnitSeedData : ISqlSugarEntitySeedData<AdoS8OrderFlowSubstepUnit>
+{
+    public IEnumerable<AdoS8OrderFlowSubstepUnit> HasData() => S8OrderFlowSubstepUnitDataset.BuildUnits();
+}
+
+internal static class S8OrderFlowSubstepUnitDataset
+{
+    internal const long UnitIdBase = 1329909130000L;
+    internal const string FlowCode = "ORDER_REVIEW_PLAN_CALC";
+    internal const string SubstepCode = "OPINION_REVIEW";
+
+    /// <summary>L3 四方责任单元固定顺序与 PI 基线工时。</summary>
+    internal static readonly (string Code, string Name, decimal PiHours)[] L3Def =
+    {
+        ("LEGAL",        "法律事务部",  2m),
+        ("TECH_PRESALE", "技术售前组",  3m),
+        ("GENERAL_PLAN", "综合主计划",  1m),
+        ("LAB",          "试验站",      2m),
+    };
+
+    /// <summary>SO-2026-001 PPT 第 2 页 L3 真值:actual_hours / status,与 L3Def 同序。</summary>
+    private static readonly (decimal Actual, string Status)[] Ppt001L3 =
+    {
+        (2.0m, "green"),
+        (9.2m, "red"),
+        (1.2m, "yellow"),
+        (2.0m, "green"),
+    };
+
+    /// <summary>
+    /// 19 个非 PPT 单的 L3 派生 multiplier 桶。
+    /// bucketIdx = (idx - 2 + unitIdx) mod 4,对应 4 种 (multiplier, status) 组合。
+    /// status 满足:multiplier ≤ 1.00 = green;1.00 &lt; multiplier ≤ 1.25 = yellow;&gt; 1.25 = red。
+    /// </summary>
+    private static readonly (decimal Mult, string Status)[] L3Buckets =
+    {
+        (0.95m, "green"),
+        (1.15m, "yellow"),
+        (1.35m, "red"),
+        (1.05m, "yellow"),
+    };
+
+    public static IEnumerable<AdoS8OrderFlowSubstepUnit> BuildUnits()
+    {
+        long seq = 0;
+        foreach (var spec in S8OrderFlowDataset.Specs)
+        {
+            var orderId = S8OrderFlowDataset.OrderIdBase + spec.Idx;
+            var substepId = S8OrderFlowSubstepDataset.OpinionReviewSubstepId(spec.Idx);
+            var isPpt = spec.OrderCode == "SO-2026-001";
+            var scenario = isPpt ? "PPT" : "DEMO";
+
+            for (var i = 0; i < L3Def.Length; i++)
+            {
+                var (code, name, piHours) = L3Def[i];
+                decimal actual;
+                string status;
+
+                if (isPpt)
+                {
+                    actual = Ppt001L3[i].Actual;
+                    status = Ppt001L3[i].Status;
+                }
+                else
+                {
+                    var bucketIdx = ((spec.Idx - 2) + i) % L3Buckets.Length;
+                    var bucket = L3Buckets[bucketIdx];
+                    actual = decimal.Round(piHours * bucket.Mult, 1);
+                    status = bucket.Status;
+                }
+
+                yield return new AdoS8OrderFlowSubstepUnit
+                {
+                    Id = UnitIdBase + (++seq),
+                    SubstepId = substepId,
+                    OrderId = orderId,
+                    OrderCode = spec.OrderCode,
+                    OrderFlowCode = FlowCode,
+                    SubstepCode = SubstepCode,
+                    UnitCode = code,
+                    UnitName = name,
+                    PiHours = piHours,
+                    ActualHours = actual,
+                    Status = status,
+                    SortNo = i + 1,
+                    ScenarioCode = scenario,
+                    DataSource = "SEED",
+                    TenantId = 1,
+                    FactoryId = 1,
+                    CreatedAt = S8OrderFlowDataset.CreatedAt,
+                    UpdatedAt = null,
+                    IsDeleted = false,
+                };
+            }
+        }
+    }
+}