refactor: Optimize order summary query and implement pagination in production plan management
- Consolidated the order summary query to integrate detailed, stock, and planning information into a single CTE for improved performance and clarity. - Removed redundant checks for lead time in item_info, simplifying the query structure. - Introduced pagination functionality in the production plan management page, allowing users to navigate through order items more efficiently. - Enhanced the user interface to reflect the paginated data, improving overall usability and data handling across multiple company implementations.
This commit is contained in:
@@ -35,46 +35,15 @@ export async function getOrderSummary(
|
||||
|
||||
const whereClause = conditions.join(" AND ");
|
||||
|
||||
// item_info에 lead_time 컬럼이 존재하는지 확인
|
||||
const leadTimeColCheck = await pool.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'item_info' AND column_name = 'lead_time'
|
||||
) AS has_lead_time
|
||||
`);
|
||||
const hasLeadTime = leadTimeColCheck.rows[0]?.has_lead_time === true;
|
||||
|
||||
const itemLeadTimeCte = hasLeadTime
|
||||
? `item_lead_time AS (
|
||||
SELECT DISTINCT ON (item_number)
|
||||
item_number,
|
||||
id AS item_id,
|
||||
COALESCE(lead_time::int, 0) AS lead_time
|
||||
FROM item_info
|
||||
WHERE company_code = $1
|
||||
ORDER BY item_number, created_date DESC
|
||||
),`
|
||||
: `item_lead_time AS (
|
||||
SELECT DISTINCT ON (item_number)
|
||||
item_number,
|
||||
id AS item_id,
|
||||
0 AS lead_time
|
||||
FROM item_info
|
||||
WHERE company_code = $1
|
||||
ORDER BY item_number, created_date DESC
|
||||
),`;
|
||||
|
||||
// 단일 쿼리로 요약 + 상세 + 재고 + 계획 통합 조회
|
||||
const query = `
|
||||
WITH all_orders AS (
|
||||
-- 레거시: sales_order_mng에 part_code가 직접 있는 경우
|
||||
SELECT
|
||||
so.part_code,
|
||||
so.part_name,
|
||||
so.company_code,
|
||||
so.id::text, so.order_no, so.part_code, so.part_name, so.company_code,
|
||||
COALESCE(so.order_qty::numeric, 0) AS order_qty,
|
||||
COALESCE(so.ship_qty::numeric, 0) AS ship_qty,
|
||||
COALESCE(so.balance_qty::numeric, 0) AS balance_qty,
|
||||
so.due_date
|
||||
so.due_date, so.status, so.partner_id, so.manager_name
|
||||
FROM sales_order_mng so
|
||||
WHERE ${whereClause}
|
||||
AND so.part_code IS NOT NULL AND so.part_code != ''
|
||||
@@ -85,52 +54,47 @@ export async function getOrderSummary(
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- 마스터-디테일: sales_order_detail에 품목이 있는 경우
|
||||
SELECT
|
||||
sd.part_code,
|
||||
sd.part_name,
|
||||
sd.company_code,
|
||||
sd.id::text, sd.order_no, sd.part_code, sd.part_name, sd.company_code,
|
||||
COALESCE(sd.qty::numeric, 0) AS order_qty,
|
||||
COALESCE(sd.ship_qty::numeric, 0) AS ship_qty,
|
||||
COALESCE(sd.balance_qty::numeric, sd.qty::numeric - COALESCE(sd.ship_qty::numeric, 0), 0) AS balance_qty,
|
||||
sd.due_date::date
|
||||
sd.due_date::date, so.status, so.partner_id, so.manager_name
|
||||
FROM sales_order_detail sd
|
||||
INNER JOIN sales_order_mng so ON sd.order_no = so.order_no AND sd.company_code = so.company_code
|
||||
WHERE sd.company_code = $1
|
||||
AND sd.part_code IS NOT NULL AND sd.part_code != ''
|
||||
),
|
||||
distinct_item AS (
|
||||
SELECT DISTINCT ON (item_number, company_code)
|
||||
item_number, item_name, company_code
|
||||
item_info_dedup AS (
|
||||
SELECT DISTINCT ON (item_number)
|
||||
item_number, item_name, id AS item_id,
|
||||
COALESCE(lead_time::int, 0) AS lead_time
|
||||
FROM item_info
|
||||
ORDER BY item_number, company_code, created_date DESC
|
||||
WHERE company_code = $1
|
||||
ORDER BY item_number, created_date DESC
|
||||
),
|
||||
order_summary AS (
|
||||
SELECT
|
||||
ao.part_code AS item_code,
|
||||
COALESCE(NULLIF(ao.part_name, ''), ii.item_name, ao.part_code) AS item_name,
|
||||
COALESCE(NULLIF(MAX(ao.part_name), ''), MAX(ii.item_name), ao.part_code) AS item_name,
|
||||
SUM(ao.order_qty) AS total_order_qty,
|
||||
SUM(ao.ship_qty) AS total_ship_qty,
|
||||
SUM(ao.balance_qty) AS total_balance_qty,
|
||||
COUNT(*) AS order_count,
|
||||
MIN(ao.due_date) AS earliest_due_date
|
||||
FROM all_orders ao
|
||||
LEFT JOIN distinct_item ii ON ao.part_code = ii.item_number AND ao.company_code = ii.company_code
|
||||
GROUP BY ao.part_code, COALESCE(NULLIF(ao.part_name, ''), ii.item_name, ao.part_code)
|
||||
LEFT JOIN item_info_dedup ii ON ao.part_code = ii.item_number
|
||||
GROUP BY ao.part_code
|
||||
),
|
||||
${itemLeadTimeCte}
|
||||
stock_info AS (
|
||||
SELECT
|
||||
item_code,
|
||||
SELECT item_code,
|
||||
SUM(COALESCE(current_qty::numeric, 0)) AS current_stock,
|
||||
MAX(COALESCE(safety_qty::numeric, 0)) AS safety_stock
|
||||
FROM inventory_stock
|
||||
WHERE company_code = $1
|
||||
FROM inventory_stock WHERE company_code = $1
|
||||
GROUP BY item_code
|
||||
),
|
||||
plan_info AS (
|
||||
SELECT
|
||||
item_code,
|
||||
SELECT item_code,
|
||||
SUM(CASE WHEN status = 'planned' THEN COALESCE(plan_qty, 0) ELSE 0 END) AS existing_plan_qty,
|
||||
SUM(CASE WHEN status = 'in_progress' THEN COALESCE(plan_qty, 0) ELSE 0 END) AS in_progress_qty
|
||||
FROM production_plan_mng
|
||||
@@ -140,13 +104,9 @@ export async function getOrderSummary(
|
||||
GROUP BY item_code
|
||||
)
|
||||
SELECT
|
||||
os.item_code,
|
||||
os.item_name,
|
||||
os.total_order_qty,
|
||||
os.total_ship_qty,
|
||||
os.total_balance_qty,
|
||||
os.order_count,
|
||||
os.earliest_due_date,
|
||||
os.item_code, os.item_name,
|
||||
os.total_order_qty, os.total_ship_qty, os.total_balance_qty,
|
||||
os.order_count, os.earliest_due_date,
|
||||
COALESCE(si.current_stock, 0) AS current_stock,
|
||||
COALESCE(si.safety_stock, 0) AS safety_stock,
|
||||
COALESCE(pi.existing_plan_qty, 0) AS existing_plan_qty,
|
||||
@@ -160,15 +120,14 @@ export async function getOrderSummary(
|
||||
FROM order_summary os
|
||||
LEFT JOIN stock_info si ON os.item_code = si.item_code
|
||||
LEFT JOIN plan_info pi ON os.item_code = pi.item_code
|
||||
LEFT JOIN item_lead_time ilt ON (os.item_code = ilt.item_number OR os.item_code = ilt.item_id)
|
||||
LEFT JOIN item_info_dedup ilt ON os.item_code = ilt.item_number
|
||||
${options?.excludePlanned ? "WHERE COALESCE(pi.existing_plan_qty, 0) = 0" : ""}
|
||||
ORDER BY os.item_code;
|
||||
`;
|
||||
|
||||
const result = await pool.query(query, params);
|
||||
|
||||
// 그룹별 상세 수주 데이터도 함께 조회 (레거시 + 디테일 UNION)
|
||||
const detailWhere = conditions.map(c => c.replace(/so\./g, "")).join(" AND ");
|
||||
// 상세 데이터: all_orders CTE와 동일 로직 (쿼리 재사용 위해 별도 실행)
|
||||
const detailQuery = `
|
||||
SELECT id::text, order_no, part_code, part_name,
|
||||
COALESCE(order_qty::numeric, 0) AS order_qty,
|
||||
@@ -176,15 +135,13 @@ export async function getOrderSummary(
|
||||
COALESCE(balance_qty::numeric, 0) AS balance_qty,
|
||||
due_date, status, partner_id, manager_name
|
||||
FROM sales_order_mng
|
||||
WHERE ${detailWhere}
|
||||
WHERE ${conditions.map(c => c.replace(/so\./g, "")).join(" AND ")}
|
||||
AND part_code IS NOT NULL AND part_code != ''
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sales_order_detail sd
|
||||
WHERE sd.order_no = sales_order_mng.order_no AND sd.company_code = sales_order_mng.company_code
|
||||
)
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT sd.id::text, sd.order_no, sd.part_code, sd.part_name,
|
||||
COALESCE(sd.qty::numeric, 0) AS order_qty,
|
||||
COALESCE(sd.ship_qty::numeric, 0) AS ship_qty,
|
||||
@@ -194,7 +151,6 @@ export async function getOrderSummary(
|
||||
INNER JOIN sales_order_mng so ON sd.order_no = so.order_no AND sd.company_code = so.company_code
|
||||
WHERE sd.company_code = $1
|
||||
AND sd.part_code IS NOT NULL AND sd.part_code != ''
|
||||
|
||||
ORDER BY part_code, due_date;
|
||||
`;
|
||||
const detailResult = await pool.query(detailQuery, params);
|
||||
|
||||
Reference in New Issue
Block a user