using Admin.NET.Plugin.AiDOP.Entity.S8.OrderFlow;
namespace Admin.NET.Plugin.AiDOP.SeedData;
///
/// S8-ORDER-CHAIN-PRODUCT-DESIGN-20ORDER-GENERATION-CONSISTENCY-AUDIT-1:
/// S8 订单链路产品设计图号种子,按订单父级 actual_days 守恒生成(不再使用全局聚合口径)。
///
/// 守恒约束(核心业务规则):
/// AVG(drawing.actual_days WHERE order_code = X)
/// = ado_s8_order_flow_stage.actual_days WHERE order_code = X AND order_flow_code = 'PRODUCT_DESIGN'
/// 即 SUM(all drawing.actual_days) = stage.actual_days × drawing_count(简单平均,非台数加权)。
///
/// 守恒模型(按 stage.actual_days × 是否有非标 5 类分类):
/// A) pending(stage.status=pending) → 3 张 STANDARD,actual_days=NULL,status=pending
/// B) green 无非标(stage.actual_days=A=3) → 3 张 STANDARD,actual_days=A=3.00,status=green
/// C) green 有非标(A=3) → 6 张 STANDARD (1.25 green) + 1 张 NON_STANDARD (13.50 red)
/// AVG=(6×1.25 + 13.50)/7 = 21/7 = 3.00;非标显著超期,常规摊平
/// D) red 无非标(A=5) → 5 张 STANDARD,actual_days=A=5.00,status=red
/// E) red 有非标(A=5) → 6 张 STANDARD (4.50 red) + 1 张 NON_STANDARD (8.00 red)
/// AVG=(6×4.50 + 8.00)/7 = 35/7 = 5.00;全部 red 支撑父 red
///
/// 图号编码:常规 D-{OrderCode}-G{NN};非标 D-{OrderCode}-X{NN}。
/// 责任人按全局序号 seq 在 6 桶(李海峰 / 陈思远 / 王明华 / 赵建国 / 刘振宇 / 周启明)循环。
/// 总图号数:106 = A(2×3) + B(5×3) + C(9×7) + D(3×5) + E(1×7) = 6 + 15 + 63 + 15 + 7。
///
[IncreSeed]
public class S8OrderFlowProductDesignDrawingSeedData
: ISqlSugarEntitySeedData
{
public IEnumerable HasData()
=> S8OrderFlowProductDesignDrawingDataset.BuildDrawings();
}
internal static class S8OrderFlowProductDesignDrawingDataset
{
/// 图号 id 基址(与其他 S8 种子号段隔离;本表新设计行数 106,使用 IdBase+1..106)。
internal const long IdBase = 1329909130000L;
internal const string ProductTypeStandard = "STANDARD";
internal const string ProductTypeNonStandard = "NON_STANDARD";
/// PRODUCT_DESIGN 阶段统一 KPI=3 天,常规与非标共用同一阈值。
internal const decimal KpiDays = 3.00m;
/// 常规图号统一 product_quantity=7(设计阶段每张图号承载 7 台)。
internal const int StandardQuantity = 7;
/// 非标图号统一 product_quantity=2(非标少量定制)。
internal const int NonStandardQuantity = 2;
/// 责任人 6 桶;按全局递增序号 seq 循环分配,sort_no 仅订单内序号。
private static readonly string[] Designers =
{
"李海峰",
"陈思远",
"王明华",
"赵建国",
"刘振宇",
"周启明",
};
///
/// 每订单是否含非标产品(与 stage 派生 layout 共同决定 std/nstd 数量)。
/// 11 单含非标(沿用原业务直觉:大客户 / P1 优先级 / completed 订单),9 单无非标。
/// pending 父级订单(016, 017)按守恒约束统一不分配非标(产品设计阶段尚未进入或刚开始)。
///
private static readonly bool[] HasNonStandardByIdx =
{
// SO-2026-001..005
true, true, true, false, false,
// SO-2026-006..010
true, true, true, false, false,
// SO-2026-011..015
false, true, false, false, false,
// SO-2026-016..020
false, false, true, true, true,
};
/// 单订单图号布局:std/nstd 数量 + 各自 actual_days + 各自 status。null actual=pending。
internal readonly record struct OrderLayout(
int StdN,
int NstdN,
decimal? StdActualDays,
decimal? NstdActualDays,
string StdStatus,
string NstdStatus);
///
/// 按 PRODUCT_DESIGN stage 派生订单布局。守恒前提:SUM(actual_days) = stage.actual_days × drawing_count。
/// stage seed 引用:S8OrderFlowStageDataset.BuildLifecycleValues(spec)[1] 即 PRODUCT_DESIGN 阶段。
///
internal static OrderLayout DeriveLayout(S8OrderFlowDataset.OrderSpec spec, int idx)
{
var lifecycle = S8OrderFlowStageDataset.BuildLifecycleValues(spec);
var stage = lifecycle[1]; // 索引 1 = PRODUCT_DESIGN(lifecycle[0]=ORDER_REVIEW_PLAN_CALC)
// 类别 A:pending 父级 → 3 std NULL pending
if (stage.status == "pending")
{
return new OrderLayout(3, 0, null, null, "pending", "pending");
}
var A = stage.actualDays;
var hasNonStandard = HasNonStandardByIdx[idx];
if (A <= KpiDays)
{
// 类别 C:green 有非标 → 6 std 1.25 + 1 nstd 13.50;AVG=(6×1.25 + 13.50)/7=3.00
if (hasNonStandard)
{
return new OrderLayout(6, 1, 1.25m, 13.50m, "green", "red");
}
// 类别 B:green 无非标 → 3 std 各 A green;AVG=A
return new OrderLayout(3, 0, A, null, "green", "green");
}
else
{
// 类别 E:red 有非标 → 6 std 4.50 + 1 nstd 8.00;AVG=(6×4.50 + 8.00)/7=5.00;全 red
if (hasNonStandard)
{
return new OrderLayout(6, 1, 4.50m, 8.00m, "red", "red");
}
// 类别 D:red 无非标 → 5 std 各 A red;AVG=A;多张图号都超期支撑父 red
return new OrderLayout(5, 0, A, null, "red", "red");
}
}
public static IEnumerable BuildDrawings()
{
long seq = 0;
// 图号粒度计划开始 = release_at + 5 天(ORDER_REVIEW KPI=5 天结束后进入 PRODUCT_DESIGN)
var plannedStart = S8OrderFlowDataset.ReleaseBase.AddDays(5);
var plannedEnd = plannedStart.AddDays((double)KpiDays);
for (var i = 0; i < S8OrderFlowDataset.Specs.Length; i++)
{
var orderSpec = S8OrderFlowDataset.Specs[i];
var layout = DeriveLayout(orderSpec, i);
var sortNo = 0;
for (var g = 0; g < layout.StdN; g++)
{
sortNo++;
yield return BuildDrawing(
seq: ++seq,
orderSpec: orderSpec,
sortNo: sortNo,
drawingNo: $"D-{orderSpec.OrderCode}-G{g + 1:D2}",
productType: ProductTypeStandard,
productQuantity: StandardQuantity,
plannedStart: plannedStart,
plannedEnd: plannedEnd,
actualDays: layout.StdActualDays,
status: layout.StdStatus);
}
for (var x = 0; x < layout.NstdN; x++)
{
sortNo++;
yield return BuildDrawing(
seq: ++seq,
orderSpec: orderSpec,
sortNo: sortNo,
drawingNo: $"D-{orderSpec.OrderCode}-X{x + 1:D2}",
productType: ProductTypeNonStandard,
productQuantity: NonStandardQuantity,
plannedStart: plannedStart,
plannedEnd: plannedEnd,
actualDays: layout.NstdActualDays,
status: layout.NstdStatus);
}
}
}
private static AdoS8OrderFlowProductDesignDrawing BuildDrawing(
long seq,
S8OrderFlowDataset.OrderSpec orderSpec,
int sortNo,
string drawingNo,
string productType,
int productQuantity,
DateTime plannedStart,
DateTime plannedEnd,
decimal? actualDays,
string status)
{
// 完成态:actualStart=plannedStart,actualEnd=plannedStart + actualDays
// pending:actualStart=plannedStart 表示已起步但未完工,actualEnd=NULL(与 stage seed pending 路径一致)
DateTime? actualStart = plannedStart;
DateTime? actualEnd = actualDays.HasValue
? plannedStart.AddDays((double)actualDays.Value)
: (DateTime?)null;
// is_achieved:actual_days <= kpi_days;pending 时为 false(entity bool 不可 null)
var isAchieved = actualDays.HasValue && actualDays.Value <= KpiDays;
var responsible = Designers[(seq - 1) % Designers.Length];
return new AdoS8OrderFlowProductDesignDrawing
{
Id = IdBase + seq,
TenantId = 1,
FactoryId = 1,
OrderCode = orderSpec.OrderCode,
DrawingNo = drawingNo,
ProductType = productType,
ProductQuantity = productQuantity,
ResponsiblePerson = responsible,
PlannedStartDate = plannedStart,
PlannedEndDate = plannedEnd,
ActualStartDate = actualStart,
ActualEndDate = actualEnd,
KpiDays = KpiDays,
ActualDays = actualDays,
IsAchieved = isAchieved,
Status = status,
SortNo = sortNo,
IsDeleted = false,
CreateTime = S8OrderFlowDataset.CreatedAt,
UpdateTime = null,
};
}
}