feat(orders/approve): 출고 시 재고 부족 검사 제거 — 음수 재고 허용
Deploy momo-erp / deploy (push) Successful in 3m54s
Deploy momo-erp / deploy (push) Successful in 3m54s
요구: 거래처 default 창고에 재고가 모자라도 그대로 차감해서 출고 진행.
일자별 발주/재고 + 창고별 재고 현황에서 음수(-) 로 표시되면 관리자가
다른 창고에서 부족 창고로 수동 재고 이동 처리하는 운영 정책.
변경:
- "재고 부족: 현재고 N, 요청 M" 차단 + ROLLBACK 제거 → 그대로 차감
- 재고 row 자체가 없던 품목은 새 row(qty=-N) INSERT
- itemsRes SQL 에 kind='ITEM' AND item_objid IS NOT NULL 가드 추가
(택배/용차/환불 라인이 잘못 차감되는 잠재 버그도 같이 차단)
- stock_moves OUT 이력은 동일하게 음수 qty 로 기록
음수 재고 발생 시 운영 흐름:
1) 다른 창고에 같은 품목 재고 확인
2) 관리자 패널 → 재고 이동 (오프라인 물리 이동 + 시스템 등록)
3) 부족 창고 재고가 0 이상으로 복구
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,8 +33,11 @@ export async function POST(req: NextRequest) {
|
|||||||
return NextResponse.json({ success: false, message: `현재 상태(${order.status})에서는 승인할 수 없습니다.` }, { status: 400 });
|
return NextResponse.json({ success: false, message: `현재 상태(${order.status})에서는 승인할 수 없습니다.` }, { status: 400 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ITEM 종류만 — 택배/용차/환불 라인은 재고 차감 대상이 아님
|
||||||
const itemsRes = await client.query(
|
const itemsRes = await client.query(
|
||||||
`SELECT objid, item_objid, qty FROM momo_order_items WHERE order_objid = $1 ORDER BY seq`,
|
`SELECT objid, item_objid, qty FROM momo_order_items
|
||||||
|
WHERE order_objid = $1 AND COALESCE(kind,'ITEM') = 'ITEM' AND item_objid IS NOT NULL
|
||||||
|
ORDER BY seq`,
|
||||||
[objid]
|
[objid]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -65,29 +68,31 @@ export async function POST(req: NextRequest) {
|
|||||||
whObjid = whRes.rows[0].objid;
|
whObjid = whRes.rows[0].objid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 부족해도 차감 — 음수 재고 허용. 일자별 발주/재고 + 창고별 재고 현황에 음수로
|
||||||
|
// 표시되면 관리자가 다른 창고에서 부족 창고로 수동 이동 처리.
|
||||||
for (const ln of itemsRes.rows) {
|
for (const ln of itemsRes.rows) {
|
||||||
|
// 택배/용차 라인은 재고 차감 대상이 아님 — item_objid 없거나 kind 가 ITEM 이 아닌 row 는 skip.
|
||||||
|
// (approve 시 itemsRes 가 kind 필터링 없이 가져오므로 여기서 한 번 더 가드)
|
||||||
|
if (!ln.item_objid) continue;
|
||||||
|
|
||||||
const stk = await client.query(
|
const stk = await client.query(
|
||||||
`SELECT qty FROM momo_stocks WHERE wh_objid = $1 AND item_objid = $2 FOR UPDATE`,
|
`SELECT qty FROM momo_stocks WHERE wh_objid = $1 AND item_objid = $2 FOR UPDATE`,
|
||||||
[whObjid, ln.item_objid]
|
[whObjid, ln.item_objid]
|
||||||
);
|
);
|
||||||
const currentQty = stk.rowCount === 0 ? 0 : Number(stk.rows[0].qty);
|
if (stk.rowCount === 0) {
|
||||||
if (currentQty < Number(ln.qty)) {
|
// 재고 row 자체가 없는 품목 — 0 에서 -N 으로 새 row 생성
|
||||||
await client.query("ROLLBACK");
|
await client.query(
|
||||||
return NextResponse.json(
|
`INSERT INTO momo_stocks (objid, wh_objid, item_objid, qty, regdate)
|
||||||
{ success: false, message: `재고 부족: 품목 ${ln.item_objid} (현재고 ${currentQty}, 요청 ${ln.qty})` },
|
VALUES ($1, $2, $3, $4, NOW())`,
|
||||||
{ status: 400 }
|
[createObjectId(), whObjid, ln.item_objid, -Number(ln.qty)]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await client.query(
|
||||||
|
`UPDATE momo_stocks SET qty = qty - $1, update_date = NOW()
|
||||||
|
WHERE wh_objid = $2 AND item_objid = $3`,
|
||||||
|
[ln.qty, whObjid, ln.item_objid]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (stk.rowCount === 0) {
|
|
||||||
// 안전장치: 재고 row가 없으면 만들지 않고 에러 처리
|
|
||||||
await client.query("ROLLBACK");
|
|
||||||
return NextResponse.json({ success: false, message: "재고 정보가 없습니다." }, { status: 400 });
|
|
||||||
}
|
|
||||||
await client.query(
|
|
||||||
`UPDATE momo_stocks SET qty = qty - $1, update_date = NOW()
|
|
||||||
WHERE wh_objid = $2 AND item_objid = $3`,
|
|
||||||
[ln.qty, whObjid, ln.item_objid]
|
|
||||||
);
|
|
||||||
await client.query(
|
await client.query(
|
||||||
`INSERT INTO momo_stock_moves (objid, wh_objid, item_objid, move_type, qty, ref_type, ref_objid, regdate, regid)
|
`INSERT INTO momo_stock_moves (objid, wh_objid, item_objid, move_type, qty, ref_type, ref_objid, regdate, regid)
|
||||||
VALUES ($1, $2, $3, 'OUT', $4, 'ORDER', $5, NOW(), $6)`,
|
VALUES ($1, $2, $3, 'OUT', $4, 'ORDER', $5, NOW(), $6)`,
|
||||||
|
|||||||
Reference in New Issue
Block a user