Implement BOM base quantity retrieval functionality
- Added a new endpoint `/work-instruction/bom-base-qty` to retrieve base quantities for items based on their codes. - Introduced the `getBomBaseQtyMap` function in the `workInstructionController` to handle the logic for fetching base quantities. - Updated the frontend to call the new API and integrate base quantity mapping into the work instruction registration process. - Enhanced the work instruction page to calculate batch counts and split quantities based on the retrieved base quantities. (TASK:ERP-020)
This commit is contained in:
@@ -314,7 +314,7 @@ export async function save(req: AuthenticatedRequest, res: Response) {
|
||||
if (!firstRouting && itemRouting) firstRouting = itemRouting;
|
||||
totalQty += Number(item.qty || 0);
|
||||
await client.query(
|
||||
`INSERT INTO work_instruction_detail (id,company_code,work_instruction_no,work_instruction_id,item_number,qty,remark,source_table,source_id,part_code,routing_version_id,start_date,end_date,equipment_ids,work_teams,workers,created_date,writer) VALUES (gen_random_uuid()::text,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,NOW(),$16)`,
|
||||
`INSERT INTO work_instruction_detail (id,company_code,work_instruction_no,work_instruction_id,item_number,qty,remark,source_table,source_id,part_code,routing_version_id,start_date,end_date,equipment_ids,work_teams,workers,created_date,writer) VALUES (gen_random_uuid()::text,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,clock_timestamp(),$16)`,
|
||||
[
|
||||
companyCode,
|
||||
wiNo,
|
||||
@@ -993,3 +993,40 @@ export async function resetWorkStandard(req: AuthenticatedRequest, res: Response
|
||||
return res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// ─── BOM 기준수(0레벨 base_qty) 일괄 조회 ───
|
||||
// itemCodes(item_info.item_number 기준) 배열을 받아 { [itemCode]: base_qty | null } 맵 반환
|
||||
export async function getBomBaseQtyMap(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
const companyCode = req.user!.companyCode;
|
||||
const itemCodes: string[] = Array.isArray(req.body?.itemCodes) ? req.body.itemCodes.filter(Boolean) : [];
|
||||
if (itemCodes.length === 0) return res.json({ success: true, data: {} });
|
||||
|
||||
const pool = getPool();
|
||||
// bom.item_code 우선 매칭, 없으면 item_info.id 경유 매칭
|
||||
const result = await pool.query(
|
||||
`SELECT i.item_number AS item_code, b.base_qty
|
||||
FROM bom b
|
||||
LEFT JOIN item_info i ON i.id = b.item_id AND i.company_code = b.company_code
|
||||
WHERE b.company_code = $1
|
||||
AND (b.item_code = ANY($2::text[]) OR i.item_number = ANY($2::text[]))`,
|
||||
[companyCode, itemCodes]
|
||||
);
|
||||
|
||||
const map: Record<string, number | null> = {};
|
||||
for (const code of itemCodes) map[code] = null;
|
||||
for (const row of result.rows) {
|
||||
const code = row.item_code;
|
||||
const base = parseFloat(row.base_qty || "");
|
||||
if (!code) continue;
|
||||
if (Number.isFinite(base) && base > 0) {
|
||||
// 동일 품목 다건 BOM 시 첫 유효값 유지
|
||||
if (map[code] == null) map[code] = base;
|
||||
}
|
||||
}
|
||||
return res.json({ success: true, data: map });
|
||||
} catch (error: any) {
|
||||
logger.error("BOM 기준수 일괄 조회 실패", { error: error.message });
|
||||
return res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ router.get("/employees", ctrl.getEmployeeList);
|
||||
// 벌크 라우팅 조회 (품목별 공정 일괄 조회)
|
||||
router.post("/routing-versions-bulk", ctrl.getRoutingVersionsBulk);
|
||||
|
||||
// BOM 기준수 일괄 조회 (작업지시 등록 모달 기준수/배치수 산출용)
|
||||
router.post("/bom-base-qty", ctrl.getBomBaseQtyMap);
|
||||
|
||||
// 라우팅 & 공정작업기준
|
||||
router.get("/:wiNo/routing-versions/:itemCode", ctrl.getRoutingVersions);
|
||||
router.put("/:wiNo/routing", ctrl.updateRouting);
|
||||
|
||||
Reference in New Issue
Block a user