From d1d823d5caa31de38dc128d28628df1589b3b902 Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Mon, 6 Apr 2026 14:07:11 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=9E=AC=EC=9E=91=EC=97=85=20=EC=B9=B4?= =?UTF-8?q?=EB=93=9C=20=EC=A0=91=EC=88=98=20=E2=80=94=20=EC=9E=90=EC=B2=B4?= =?UTF-8?q?=20input=5Fqty=20=EA=B8=B0=EB=B0=98=20=EC=A0=91=EC=88=98=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=20(=EC=95=9E=EA=B3=B5=EC=A0=95=20=EB=AC=B4?= =?UTF-8?q?=EA=B4=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/popProductionController.ts | 117 ++++++++++++------ 1 file changed, 77 insertions(+), 40 deletions(-) diff --git a/backend-node/src/controllers/popProductionController.ts b/backend-node/src/controllers/popProductionController.ts index f471b124..b26490d5 100644 --- a/backend-node/src/controllers/popProductionController.ts +++ b/backend-node/src/controllers/popProductionController.ts @@ -1629,33 +1629,51 @@ export const getAvailableQty = async (req: AuthenticatedRequest, res: Response) const instrQty = parseInt(instruction_qty, 10) || 0; const seqNum = parseInt(seq_no, 10); - // 같은 공정(wo_id + seq_no)의 모든 분할 행 접수량 합산 - const totalAccepted = await pool.query( - `SELECT COALESCE(SUM(input_qty::int), 0) as total_input - FROM work_order_process - WHERE wo_id = $1 AND seq_no = $2 AND company_code = $3 - AND parent_process_id IS NOT NULL`, - [wo_id, seq_no, companyCode] + // 재작업 카드 여부 확인 + const reworkCheck = await pool.query( + `SELECT is_rework, input_qty FROM work_order_process WHERE id = $1`, + [work_order_process_id] ); - const myInputQty = parseInt(totalAccepted.rows[0].total_input, 10) || 0; + const isRework = reworkCheck.rows[0]?.is_rework === "Y"; - // 앞공정 양품+특채 합산 (SPLIT만 — master 이중 집계 방지) - let prevGoodQty = instrQty; - if (seqNum > 1) { - const prevSeq = String(seqNum - 1); - const prevProcess = await pool.query( - `SELECT COALESCE(SUM(good_qty::int), 0) + COALESCE(SUM(concession_qty::int), 0) as total_good + let myInputQty: number; + let prevGoodQty: number; + let availableQty: number; + + if (isRework) { + // 재작업 카드: 자체 input_qty가 접수 가능 수량 + const reworkInput = parseInt(reworkCheck.rows[0]?.input_qty, 10) || 0; + myInputQty = 0; + prevGoodQty = reworkInput; + availableQty = reworkInput; + } else { + // 일반 카드: 앞공정 양품 - 기접수합계 (재작업 카드 제외) + const totalAccepted = await pool.query( + `SELECT COALESCE(SUM(input_qty::int), 0) as total_input FROM work_order_process WHERE wo_id = $1 AND seq_no = $2 AND company_code = $3 - AND parent_process_id IS NOT NULL`, - [wo_id, prevSeq, companyCode] + AND parent_process_id IS NOT NULL + AND (is_rework IS NULL OR is_rework != 'Y')`, + [wo_id, seq_no, companyCode] ); - if (prevProcess.rowCount > 0) { - prevGoodQty = parseInt(prevProcess.rows[0].total_good, 10) || 0; - } - } + myInputQty = parseInt(totalAccepted.rows[0].total_input, 10) || 0; - const availableQty = Math.max(0, prevGoodQty - myInputQty); + prevGoodQty = instrQty; + if (seqNum > 1) { + const prevSeq = String(seqNum - 1); + const prevProcess = await pool.query( + `SELECT COALESCE(SUM(good_qty::int), 0) + COALESCE(SUM(concession_qty::int), 0) as total_good + FROM work_order_process + WHERE wo_id = $1 AND seq_no = $2 AND company_code = $3 + AND parent_process_id IS NOT NULL`, + [wo_id, prevSeq, companyCode] + ); + if (prevProcess.rowCount > 0) { + prevGoodQty = parseInt(prevProcess.rows[0].total_good, 10) || 0; + } + } + availableQty = Math.max(0, prevGoodQty - myInputQty); + } logger.info("[pop/production] available-qty 조회", { work_order_process_id, @@ -1751,33 +1769,52 @@ export const acceptProcess = async (req: AuthenticatedRequest, res: Response) => const instrQty = parseInt(row.instruction_qty, 10) || 0; const seqNum = parseInt(row.seq_no, 10); - // 같은 공정의 모든 분할 행 접수량 합산 (트랜잭션 내부 — 정확한 값) - const totalAccepted = await client.query( - `SELECT COALESCE(SUM(input_qty::int), 0) as total_input - FROM work_order_process - WHERE wo_id = $1 AND seq_no = $2 AND company_code = $3 - AND parent_process_id IS NOT NULL`, - [row.wo_id, row.seq_no, companyCode] + // 재작업 카드 여부 확인 + const isReworkCard = await client.query( + `SELECT is_rework, input_qty FROM work_order_process WHERE id = $1`, + [work_order_process_id] ); - const currentTotalInput = parseInt(totalAccepted.rows[0].total_input, 10) || 0; + const isRework = isReworkCard.rows[0]?.is_rework === "Y"; + const reworkInputQty = parseInt(isReworkCard.rows[0]?.input_qty, 10) || 0; - // 앞공정 양품+특채 합산 - let prevGoodQty = instrQty; - if (seqNum > 1) { - const prevSeq = String(seqNum - 1); - const prevProcess = await client.query( - `SELECT COALESCE(SUM(good_qty::int), 0) + COALESCE(SUM(concession_qty::int), 0) as total_good + let prevGoodQty: number; + let currentTotalInput: number; + let availableQty: number; + + if (isRework) { + // 재작업 카드: 자체 input_qty가 접수 가능 수량 (앞공정과 무관) + prevGoodQty = reworkInputQty; + currentTotalInput = 0; // 재작업 카드는 자체가 마스터, 분할 행 없음 + availableQty = reworkInputQty; + } else { + // 일반 카드: 앞공정 양품 - 기접수합계 + const totalAccepted = await client.query( + `SELECT COALESCE(SUM(input_qty::int), 0) as total_input FROM work_order_process WHERE wo_id = $1 AND seq_no = $2 AND company_code = $3 - AND parent_process_id IS NOT NULL`, - [row.wo_id, prevSeq, companyCode] + AND parent_process_id IS NOT NULL + AND (is_rework IS NULL OR is_rework != 'Y')`, + [row.wo_id, row.seq_no, companyCode] ); - if (prevProcess.rowCount > 0) { - prevGoodQty = parseInt(prevProcess.rows[0].total_good, 10) || 0; + currentTotalInput = parseInt(totalAccepted.rows[0].total_input, 10) || 0; + + prevGoodQty = instrQty; + if (seqNum > 1) { + const prevSeq = String(seqNum - 1); + const prevProcess = await client.query( + `SELECT COALESCE(SUM(good_qty::int), 0) + COALESCE(SUM(concession_qty::int), 0) as total_good + FROM work_order_process + WHERE wo_id = $1 AND seq_no = $2 AND company_code = $3 + AND parent_process_id IS NOT NULL`, + [row.wo_id, prevSeq, companyCode] + ); + if (prevProcess.rowCount > 0) { + prevGoodQty = parseInt(prevProcess.rows[0].total_good, 10) || 0; + } } + availableQty = prevGoodQty - currentTotalInput; } - const availableQty = prevGoodQty - currentTotalInput; if (qty > availableQty) { await client.query("ROLLBACK"); client.release();