namespace Admin.NET.Plugin.AiDOP.Production;
///
/// 工单工序执行进度口径(唯一真相):工单执行进度看板与工序进度明细共用,避免两处各写一套算法。
///
/// 流程件语义:产品需逐序加工,全部工序走完一遍才算完成,因此「完成件数」取末道工序完成量,
/// 而非各工序 QtyComplete 累加(165 报工会把当前工序之前的一段工序一并推进,累加值无业务意义)。
///
///
internal static class WorkOrderExecutionProgressSql
{
/// 当前工序:优先正在生产(Status='W')的一序;否则取已有完成量的最靠后一序。
public static string CurrentOp(string routingMatch) => $"""
SELECT r.OP AS Op, r.Descr AS Descr, IFNULL(r.QtyComplete, 0) AS QtyComplete
FROM WorkOrdRouting r
WHERE {routingMatch}
AND IFNULL(r.IsActive, 1) = 1
AND (UPPER(IFNULL(r.Status, '')) = 'W' OR IFNULL(r.QtyComplete, 0) > 0)
ORDER BY (UPPER(IFNULL(r.Status, '')) = 'W') DESC, (r.OP + 0) DESC
LIMIT 1
""";
/// 末道工序:工艺路线最大 OP,作为「整单工艺走完」的判定序。
public static string LastOp(string routingMatch) => $"""
SELECT r.OP AS Op, r.Descr AS Descr, IFNULL(r.QtyComplete, 0) AS QtyComplete
FROM WorkOrdRouting r
WHERE {routingMatch}
AND IFNULL(r.IsActive, 1) = 1
ORDER BY (r.OP + 0) DESC
LIMIT 1
""";
/// 全工序完成量求和:仅作技术对账,不代表流程件进度。
public static string OpSum(string routingMatch) => $"""
SELECT SUM(IFNULL(r.QtyComplete, 0)) AS QtyOpComplete
FROM WorkOrdRouting r
WHERE {routingMatch}
AND IFNULL(r.IsActive, 1) = 1
""";
/// 统一的进度列表达式,供看板行与明细汇总共用。
public static string Columns(string master, string cur, string last, string sum) => $"""
{cur}.Op AS CurrentOp,
{cur}.Descr AS CurrentOpName,
IFNULL({cur}.QtyComplete, 0) AS CurrentOpQty,
{last}.Op AS LastOp,
{last}.Descr AS LastOpName,
IFNULL({last}.QtyComplete, 0) AS LastOpQty,
GREATEST(IFNULL({cur}.QtyComplete, 0) - IFNULL({last}.QtyComplete, 0), 0) AS QtyWip,
IFNULL({sum}.QtyOpComplete, 0) AS QtyOpComplete,
CASE
WHEN IFNULL({master}.QtyOrded, 0) = 0 THEN 0
ELSE ROUND(100.0 * IFNULL({last}.QtyComplete, 0) / {master}.QtyOrded, 4)
END AS ProgressExec
""";
/// 三个 LATERAL 关联,别名固定为 curOp / lastOp / opAgg。
public static string Laterals(string routingMatch) => $"""
LEFT JOIN LATERAL (
{CurrentOp(routingMatch)}
) AS curOp ON TRUE
LEFT JOIN LATERAL (
{LastOp(routingMatch)}
) AS lastOp ON TRUE
LEFT JOIN LATERAL (
{OpSum(routingMatch)}
) AS opAgg ON TRUE
""";
}