// ============================================================
// 생산관리 > 생산계획&실적관리 + 생산계획&실적관리(장비) — wace productionplanning.xml 1:1.
//
// 매퍼 매핑:
//   prodPlanResultMgmtGridList       → listGeneral()  (productionplanning.xml:4550)
//   prodPlanResultMgmtEquipGridList  → listEquip()    (productionplanning.xml:4887)
//
// 두 메뉴는 동일 베이스(PROJECT_MGMT + CONTRACT_MGMT + CONTRACT_ITEM + PRODUCTION_PLAN +
// PRODUCTION_RESULT 합산) 위에서 PRODUCT 코드(0000928=장비) 기준으로 갈라진다.
// ============================================================

import { getPool } from "../database/db";

// ─── 필터 ────────────────────────────────────────────────────

export interface ProdPlanResultFilter {
  search_project_nos?: string;       // "OBJID,OBJID,..." (multiple select)
  search_product_code?: string;
  search_category_code?: string;
  search_production_type?: string;
  search_customer_objid?: string;
  search_req_del_date_from?: string;
  search_req_del_date_to?: string;
  search_part_no?: string;
  search_part_name?: string;
  search_serial_no?: string;
  search_writer?: string;
  search_regdate_from?: string;
  search_regdate_to?: string;
  page?: number;
  page_size?: number;
}

function paginate(filter: { page?: number; page_size?: number }) {
  const page = Math.max(1, Number(filter.page) || 1);
  const pageSize = Math.min(500, Math.max(1, Number(filter.page_size) || 50));
  return { limit: pageSize, offset: (page - 1) * pageSize, page, pageSize };
}

// ─── 공통 WHERE 빌더 (매퍼 <if> 1:1) ──────────────────────────
//
// 매퍼: 4684~4741 / 4985~5022. 두 메뉴 동일.
// (Equip 은 search_writer / search_regdate 없지만, 빌더는 동일 — 안 쓰면 됨.)

function buildWhere(filter: ProdPlanResultFilter, startIdx: number, includeSerial: boolean) {
  const params: any[] = [];
  const conds: string[] = [];
  let idx = startIdx;

  if (filter.search_project_nos) {
    const ids = filter.search_project_nos.split(",").map((s) => s.trim()).filter(Boolean);
    if (ids.length > 0) {
      const placeholders = ids.map(() => `$${idx++}`).join(", ");
      conds.push(`T.OBJID::VARCHAR IN (${placeholders})`);
      params.push(...ids);
    }
  }
  if (filter.search_product_code) {
    conds.push(`T.PRODUCT = $${idx++}`);
    params.push(filter.search_product_code);
  }
  if (filter.search_category_code) {
    conds.push(`T.CATEGORY_CODE = $${idx++}`);
    params.push(filter.search_category_code);
  }
  if (filter.search_production_type) {
    conds.push(`T.PRODUCTION_TYPE = $${idx++}`);
    params.push(filter.search_production_type);
  }
  if (filter.search_customer_objid) {
    conds.push(
      `(T.CUSTOMER_OBJID = $${idx} OR T.CUSTOMER_OBJID = REPLACE($${idx}, 'C_', '') OR REPLACE(T.CUSTOMER_OBJID, 'C_', '') = REPLACE($${idx}, 'C_', ''))`
    );
    params.push(filter.search_customer_objid);
    idx++;
  }
  if (filter.search_req_del_date_from) {
    conds.push(`T.REQ_DEL_DATE >= $${idx++}`);
    params.push(filter.search_req_del_date_from);
  }
  if (filter.search_req_del_date_to) {
    conds.push(`T.REQ_DEL_DATE <= $${idx++}`);
    params.push(filter.search_req_del_date_to);
  }
  if (filter.search_part_no) {
    conds.push(`UPPER(T.PART_NO) LIKE '%' || UPPER($${idx++}) || '%'`);
    params.push(filter.search_part_no);
  }
  if (filter.search_part_name) {
    conds.push(`UPPER(T.PART_NAME) LIKE '%' || UPPER($${idx++}) || '%'`);
    params.push(filter.search_part_name);
  }
  if (filter.search_serial_no) {
    // 일반: SERIAL_NO_LIST 전체 매칭 / 장비: SERIAL_NO 단일 (둘 다 동일 컬럼 alias 로 처리)
    const col = includeSerial ? "T.SERIAL_NO_LIST" : "T.SERIAL_NO";
    conds.push(`UPPER(${col}) LIKE '%' || UPPER($${idx++}) || '%'`);
    params.push(filter.search_serial_no);
  }
  if (filter.search_writer) {
    conds.push(`T.WRITER = $${idx++}`);
    params.push(filter.search_writer);
  }
  if (filter.search_regdate_from) {
    conds.push(`T.REGDATE >= TO_DATE($${idx++}, 'YYYY-MM-DD')`);
    params.push(filter.search_regdate_from);
  }
  if (filter.search_regdate_to) {
    conds.push(`T.REGDATE <= TO_DATE($${idx++}, 'YYYY-MM-DD')`);
    params.push(filter.search_regdate_to);
  }

  return { sql: conds.length ? "AND " + conds.join(" AND ") : "", params };
}

// ─── 메뉴 1: 생산계획&실적관리 (일반) ─────────────────────────
//
// 매퍼 prodPlanResultMgmtGridList (4550~4743) 1:1.
// UNION ALL 두 갈래:
//   1) PROJECT_MGMT 기반 — PM.PRODUCT != '0000928' (장비 제외)
//   2) PRODUCTION_PLAN 단독 — PROJECT_OBJID 비어있는 독립 계획

const SQL_GENERAL_INNER = `
  SELECT * FROM (
    -- 1) 프로젝트 기반
    SELECT
      PM.OBJID::VARCHAR AS OBJID,
      PM.PROJECT_NO,
      CM.PRODUCT,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1), '') AS PRODUCT_NAME,
      CM.CATEGORY_CD AS CATEGORY_CODE,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1), CM.CATEGORY_CD) AS CATEGORY_CODE_NAME,
      COALESCE(PP.PRODUCTION_TYPE, '') AS PRODUCTION_TYPE,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCTION_TYPE LIMIT 1), '') AS PRODUCTION_TYPE_NAME,
      CM.CUSTOMER_OBJID,
      COALESCE(
        CASE WHEN CM.CUSTOMER_OBJID LIKE 'C_%'
             THEN (SELECT CLIENT_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = CM.CUSTOMER_OBJID LIMIT 1)
             ELSE (SELECT SUPPLY_NAME FROM SUPPLY_MNG WHERE OBJID::VARCHAR = CM.CUSTOMER_OBJID::VARCHAR LIMIT 1) END,
        ''
      ) AS CUSTOMER_NAME,
      COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
      COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
      COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
      COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
      (SELECT CASE
                WHEN COUNT(*) = 0 THEN ''
                WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
                ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건' END
         FROM CONTRACT_ITEM_SERIAL CIS
         WHERE CIS.ITEM_OBJID::VARCHAR = PM.CONTRACT_ITEM_OBJID
           AND UPPER(CIS.STATUS) = 'ACTIVE'
           AND CIS.SERIAL_NO IS NOT NULL AND CIS.SERIAL_NO != '') AS SERIAL_NO,
      (SELECT STRING_AGG(CIS.SERIAL_NO, ', ' ORDER BY CIS.SERIAL_NO)
         FROM CONTRACT_ITEM_SERIAL CIS
         WHERE CIS.ITEM_OBJID::VARCHAR = PM.CONTRACT_ITEM_OBJID
           AND UPPER(CIS.STATUS) = 'ACTIVE'
           AND CIS.SERIAL_NO IS NOT NULL AND CIS.SERIAL_NO != '') AS SERIAL_NO_LIST,
      COALESCE(NULLIF(PM.QUANTITY, '')::numeric, NULLIF(CI.ORDER_QUANTITY, '')::numeric, 0) AS QUANTITY,
      COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
      COALESCE(NULLIF(PM.QUANTITY, '')::numeric, NULLIF(CI.ORDER_QUANTITY, '')::numeric, 0)
        + COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS TOTAL_PROD_QTY,
      COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR
                 WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'ASSEMBLY' AND PR.STATUS = 'active'), 0) AS ASSEMBLY_QTY,
      COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR
                 WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'INSPECTION' AND PR.STATUS = 'active'), 0) AS INSPECTION_QTY,
      COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR
                 WHERE PR.PROJECT_OBJID = PM.OBJID::VARCHAR AND PR.RESULT_TYPE = 'SHIP_WAIT' AND PR.STATUS = 'active'), 0) AS SHIP_WAIT_QTY,
      PP.OBJID::VARCHAR AS PROD_PLAN_OBJID,
      PM.REGDATE AS SORT_DATE,
      PP.WRITER,
      COALESCE(user_name(PP.WRITER), '') AS WRITER_NAME,
      TO_CHAR(PP.REGDATE, 'YYYY-MM-DD') AS REGDATE_TITLE,
      PP.REGDATE
    FROM PROJECT_MGMT PM
      LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
      LEFT OUTER JOIN CONTRACT_ITEM CI ON (
        CASE
          WHEN PM.CONTRACT_ITEM_OBJID IS NOT NULL THEN CI.OBJID::VARCHAR = PM.CONTRACT_ITEM_OBJID
          ELSE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID AND CI.PART_OBJID = PM.PART_OBJID
        END
      ) AND CI.STATUS = 'ACTIVE'
      LEFT OUTER JOIN PRODUCTION_PLAN PP ON PP.PROJECT_OBJID = PM.OBJID::VARCHAR AND PP.STATUS = 'active'
    WHERE PM.PROJECT_NO IS NOT NULL AND PM.PROJECT_NO != ''
      AND (CM.PRODUCT IS NULL OR CM.PRODUCT != '0000928')

    UNION ALL

    -- 2) 프로젝트 없이 등록한 생산계획
    SELECT
      PP.OBJID::VARCHAR AS OBJID,
      '' AS PROJECT_NO,
      PP.PRODUCT_CODE AS PRODUCT,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCT_CODE LIMIT 1), '') AS PRODUCT_NAME,
      PP.CATEGORY_CODE AS CATEGORY_CODE,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.CATEGORY_CODE LIMIT 1), '') AS CATEGORY_CODE_NAME,
      COALESCE(PP.PRODUCTION_TYPE, '') AS PRODUCTION_TYPE,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCTION_TYPE LIMIT 1), '') AS PRODUCTION_TYPE_NAME,
      PP.CUSTOMER_OBJID,
      COALESCE(
        CASE WHEN PP.CUSTOMER_OBJID LIKE 'C_%'
             THEN (SELECT CLIENT_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = PP.CUSTOMER_OBJID LIMIT 1)
             ELSE (SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID::VARCHAR = PP.CUSTOMER_OBJID LIMIT 1) END,
        ''
      ) AS CUSTOMER_NAME,
      PP.REQ_DEL_DATE,
      COALESCE(PP.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
      COALESCE(PP.PART_NO, '') AS PART_NO,
      COALESCE(PP.PART_NAME, '') AS PART_NAME,
      COALESCE(PP.SERIAL_NO, '') AS SERIAL_NO,
      COALESCE(PP.SERIAL_NO, '') AS SERIAL_NO_LIST,
      COALESCE(NULLIF(PP.ORDER_QTY, '')::numeric, 0) AS QUANTITY,
      COALESCE(NULLIF(PP.EXTRA_PROD_QTY, '')::numeric, 0) AS EXTRA_PROD_QTY,
      COALESCE(NULLIF(PP.TOTAL_PROD_QTY, '')::numeric, 0) AS TOTAL_PROD_QTY,
      COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR
                 WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'ASSEMBLY' AND PR.STATUS = 'active'), 0) AS ASSEMBLY_QTY,
      COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR
                 WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'INSPECTION' AND PR.STATUS = 'active'), 0) AS INSPECTION_QTY,
      COALESCE((SELECT SUM(RESULT_QTY) FROM PRODUCTION_RESULT PR
                 WHERE PR.PROJECT_OBJID = PP.OBJID::VARCHAR AND PR.RESULT_TYPE = 'SHIP_WAIT' AND PR.STATUS = 'active'), 0) AS SHIP_WAIT_QTY,
      PP.OBJID::VARCHAR AS PROD_PLAN_OBJID,
      PP.REGDATE AS SORT_DATE,
      PP.WRITER,
      COALESCE(user_name(PP.WRITER), '') AS WRITER_NAME,
      TO_CHAR(PP.REGDATE, 'YYYY-MM-DD') AS REGDATE_TITLE,
      PP.REGDATE
    FROM PRODUCTION_PLAN PP
    WHERE PP.STATUS = 'active'
      AND (PP.PROJECT_OBJID IS NULL OR PP.PROJECT_OBJID = '')
  ) T
  WHERE 1=1
`;

export async function listGeneral(filter: ProdPlanResultFilter) {
  const { limit, offset, page, pageSize } = paginate(filter);
  const where = buildWhere(filter, 1, true);
  const pool = getPool();

  const dataSql = `
    SELECT * FROM (${SQL_GENERAL_INNER} ${where.sql}) X
    ORDER BY X.SORT_DATE DESC NULLS LAST, X.PROJECT_NO DESC
    LIMIT $${where.params.length + 1} OFFSET $${where.params.length + 2}
  `;
  const countSql = `SELECT COUNT(*)::int AS cnt FROM (${SQL_GENERAL_INNER} ${where.sql}) X`;

  const [dataRes, countRes] = await Promise.all([
    pool.query(dataSql, [...where.params, limit, offset]),
    pool.query(countSql, where.params),
  ]);

  return {
    rows: dataRes.rows,
    totalCount: countRes.rows[0]?.cnt ?? 0,
    page,
    pageSize,
  };
}

// ─── 메뉴 2: 생산계획&실적관리(장비) ────────────────────────
//
// 매퍼 prodPlanResultMgmtEquipGridList (4887~5024) 1:1.
// PM.PRODUCT = '0000928' (장비) 만. PMS_WBS_TASK 기반 진척율.
// (운영판 CONTRACT_ITEM 조인 중복 라인은 정리 — 동일 ON 조건이 2번 들어있음)

const SQL_EQUIP_INNER = `
  SELECT * FROM (
    SELECT
      PM.OBJID::VARCHAR AS OBJID,
      PM.PROJECT_NO,
      CM.PRODUCT,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1), '') AS PRODUCT_NAME,
      CM.CATEGORY_CD AS CATEGORY_CODE,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1), CM.CATEGORY_CD) AS CATEGORY_CODE_NAME,
      COALESCE(PP.PRODUCTION_TYPE, '') AS PRODUCTION_TYPE,
      COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = PP.PRODUCTION_TYPE LIMIT 1), '') AS PRODUCTION_TYPE_NAME,
      CM.CUSTOMER_OBJID,
      COALESCE(
        CASE WHEN CM.CUSTOMER_OBJID LIKE 'C_%'
             THEN (SELECT CLIENT_NM FROM CLIENT_MNG AS C WHERE 'C_' || C.OBJID::VARCHAR = CM.CUSTOMER_OBJID LIMIT 1)
             ELSE (SELECT SUPPLY_NAME FROM SUPPLY_MNG WHERE OBJID::VARCHAR = CM.CUSTOMER_OBJID::VARCHAR LIMIT 1) END,
        ''
      ) AS CUSTOMER_NAME,
      COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.REQ_DEL_DATE) AS REQ_DEL_DATE,
      COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
      COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
      COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
      (SELECT CASE
                WHEN COUNT(*) = 0 THEN ''
                WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
                ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건' END
         FROM CONTRACT_ITEM_SERIAL CIS
         WHERE CIS.ITEM_OBJID = CI.OBJID
           AND UPPER(CIS.STATUS) = 'ACTIVE'
           AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
      -- 생산WBS 건수 (WBS_TYPE='PRODUCE')
      (SELECT COUNT(1)::int FROM PMS_WBS_TASK O
        WHERE O.CONTRACT_OBJID = PM.OBJID::VARCHAR
          AND O.WBS_TYPE = 'PRODUCE') AS PROD_WBS_CNT,
      -- 생산진척율: Level1 PROGRESS 평균
      CASE
        WHEN (SELECT COUNT(1) FROM PMS_WBS_TASK O
                WHERE O.CONTRACT_OBJID = PM.OBJID::VARCHAR
                  AND O.WBS_TYPE = 'PRODUCE'
                  AND O.TASK_LEVEL = '1') = 0 THEN 0
        ELSE ROUND(
          (SELECT COALESCE(AVG(CASE WHEN O.PROGRESS IS NOT NULL AND O.PROGRESS != ''
                                    THEN CAST(O.PROGRESS AS numeric) ELSE 0 END), 0)
             FROM PMS_WBS_TASK O
            WHERE O.CONTRACT_OBJID = PM.OBJID::VARCHAR
              AND O.WBS_TYPE = 'PRODUCE'
              AND O.TASK_LEVEL = '1'), 1)
      END AS PROD_PROGRESS_RATE,
      -- 납품WBS 건수 (WBS_TYPE='SHIP')
      (SELECT COUNT(1)::int FROM PMS_WBS_TASK O
        WHERE O.CONTRACT_OBJID = PM.OBJID::VARCHAR
          AND O.WBS_TYPE = 'SHIP') AS DELV_WBS_CNT,
      -- 납품진척율: Level1 PROGRESS 평균
      CASE
        WHEN (SELECT COUNT(1) FROM PMS_WBS_TASK O
                WHERE O.CONTRACT_OBJID = PM.OBJID::VARCHAR
                  AND O.WBS_TYPE = 'SHIP'
                  AND O.TASK_LEVEL = '1') = 0 THEN 0
        ELSE ROUND(
          (SELECT COALESCE(AVG(CASE WHEN O.PROGRESS IS NOT NULL AND O.PROGRESS != ''
                                    THEN CAST(O.PROGRESS AS numeric) ELSE 0 END), 0)
             FROM PMS_WBS_TASK O
            WHERE O.CONTRACT_OBJID = PM.OBJID::VARCHAR
              AND O.WBS_TYPE = 'SHIP'
              AND O.TASK_LEVEL = '1'), 1)
      END AS DELV_PROGRESS_RATE,
      PM.REGDATE AS SORT_DATE
    FROM PROJECT_MGMT PM
      LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
      LEFT OUTER JOIN CONTRACT_ITEM CI ON (
        CASE
          WHEN PM.CONTRACT_ITEM_OBJID IS NOT NULL THEN CI.OBJID::VARCHAR = PM.CONTRACT_ITEM_OBJID
          ELSE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID AND CI.PART_OBJID = PM.PART_OBJID
        END
      ) AND CI.STATUS = 'ACTIVE'
      LEFT OUTER JOIN PRODUCTION_PLAN PP ON PP.PROJECT_OBJID = PM.OBJID::VARCHAR AND PP.STATUS = 'active'
    WHERE PM.PROJECT_NO IS NOT NULL AND PM.PROJECT_NO != ''
      AND CM.PRODUCT = '0000928'
  ) T
  WHERE 1=1
`;

export async function listEquip(filter: ProdPlanResultFilter) {
  const { limit, offset, page, pageSize } = paginate(filter);
  const where = buildWhere(filter, 1, false);
  const pool = getPool();

  const dataSql = `
    SELECT * FROM (${SQL_EQUIP_INNER} ${where.sql}) X
    ORDER BY X.SORT_DATE DESC NULLS LAST, X.PROJECT_NO DESC
    LIMIT $${where.params.length + 1} OFFSET $${where.params.length + 2}
  `;
  const countSql = `SELECT COUNT(*)::int AS cnt FROM (${SQL_EQUIP_INNER} ${where.sql}) X`;

  const [dataRes, countRes] = await Promise.all([
    pool.query(dataSql, [...where.params, limit, offset]),
    pool.query(countSql, where.params),
  ]);

  return {
    rows: dataRes.rows,
    totalCount: countRes.rows[0]?.cnt ?? 0,
    page,
    pageSize,
  };
}

// ─── 검색 옵션 — 프로젝트번호 / 등록자 ──────────────────────
//
// 운영판 페이지 진입 시 모델에 담아주던 code_map.project_no / code_map.writer 대체.

export async function getProjectNoOptions() {
  const pool = getPool();
  const r = await pool.query(`
    SELECT PM.OBJID::VARCHAR AS code, PM.PROJECT_NO AS label
      FROM PROJECT_MGMT PM
     WHERE PM.PROJECT_NO IS NOT NULL AND PM.PROJECT_NO != ''
     ORDER BY PM.REGDATE DESC, PM.PROJECT_NO DESC
     LIMIT 1000
  `);
  return r.rows;
}

export async function getWriterOptions() {
  const pool = getPool();
  // PRODUCTION_PLAN.WRITER 와 PROJECT_MGMT.REGISTER 모두 user_info 의 user_id.
  // 4개 메뉴 중 메뉴1 의 search_writer 만 사용. 활성 등록자만.
  const r = await pool.query(`
    SELECT DISTINCT PP.WRITER AS code,
           COALESCE(user_name(PP.WRITER), PP.WRITER) AS label
      FROM PRODUCTION_PLAN PP
     WHERE PP.WRITER IS NOT NULL AND PP.WRITER != ''
       AND PP.STATUS = 'active'
     ORDER BY label
  `);
  return r.rows;
}
