diff --git a/src/app/(main)/m/admin/orders/page.tsx b/src/app/(main)/m/admin/orders/page.tsx index 0054856..08f0fc2 100644 --- a/src/app/(main)/m/admin/orders/page.tsx +++ b/src/app/(main)/m/admin/orders/page.tsx @@ -687,9 +687,9 @@ function StatementPreview({ const statementRef = useRef(null); const lowStock = items.filter((it) => it.KIND === "ITEM" && Number(it.STOCK_QTY) < Number(it.QTY)); - // 입금전 단계만 수정 가능 — REQUESTED(출고요청) / APPROVED(출고완료). - // 계산서발행(INVOICED) / 입금완료(PAID) / 취소(CANCELED) 는 수정 불가. - const editable = order.STATUS === "REQUESTED" || order.STATUS === "APPROVED"; + // admin(출고관리) 은 입금완료(PAID) 까지 품목/택배/용차 추가 가능. + // 계산서발행(INVOICED) / 취소(CANCELLED) 는 수정 불가. + const editable = order.STATUS === "REQUESTED" || order.STATUS === "APPROVED" || order.STATUS === "PAID"; // 거래명세표를 이미지로 캡처 → 공유 또는 다운로드 const handleCapture = async () => { diff --git a/src/app/api/m/orders/items/add/route.ts b/src/app/api/m/orders/items/add/route.ts index 374456a..84d14b7 100644 --- a/src/app/api/m/orders/items/add/route.ts +++ b/src/app/api/m/orders/items/add/route.ts @@ -57,9 +57,18 @@ export async function POST(req: NextRequest) { await client.query("ROLLBACK"); return NextResponse.json({ success: false, message: "권한이 없습니다." }, { status: 403 }); } - if (order.status !== "REQUESTED" && order.status !== "APPROVED") { - await client.query("ROLLBACK"); - return NextResponse.json({ success: false, message: "입금완료 이후 발주는 품목 추가 불가." }, { status: 400 }); + // admin: 입금완료(PAID) 까지 품목 추가 허용. USER: 출고완료(APPROVED) 까지만. + // 계산서발행(INVOICED) / 취소(CANCELLED) 이후는 누구도 추가 불가. + if (isAdmin) { + if (!["REQUESTED", "APPROVED", "PAID"].includes(order.status)) { + await client.query("ROLLBACK"); + return NextResponse.json({ success: false, message: "계산서발행 이후 발주는 품목 추가 불가." }, { status: 400 }); + } + } else { + if (order.status !== "REQUESTED" && order.status !== "APPROVED") { + await client.query("ROLLBACK"); + return NextResponse.json({ success: false, message: "입금완료 이후 발주는 품목 추가 불가." }, { status: 400 }); + } } // 편집 락 체크 const myId = String(r.user.objid || r.user.userId); diff --git a/src/app/api/m/orders/items/update/route.ts b/src/app/api/m/orders/items/update/route.ts index 19ed11a..8d833b4 100644 --- a/src/app/api/m/orders/items/update/route.ts +++ b/src/app/api/m/orders/items/update/route.ts @@ -72,12 +72,12 @@ export async function POST(req: NextRequest) { message: `${name} 담당자가 수정 중입니다. 잠시 후 다시 시도하세요.`, }, { status: 409 }); } - // USER: REQUESTED 만. ADMIN: 입금 전 단계만 = REQUESTED/APPROVED. - // INVOICED(계산서발행)/PAID(입금완료)/CANCELED 는 수정 불가. + // ADMIN: REQUESTED/APPROVED/PAID 까지 수정 허용. (INVOICED, CANCELLED 는 잠금) + // USER: REQUESTED/APPROVED 까지 (입금완료 후 본인은 변경 불가). if (isAdmin) { - if (order.status !== "REQUESTED" && order.status !== "APPROVED") { + if (!["REQUESTED", "APPROVED", "PAID"].includes(order.status)) { await client.query("ROLLBACK"); - return NextResponse.json({ success: false, message: "계산서발행 또는 입금완료 이후 발주는 수정할 수 없습니다." }, { status: 400 }); + return NextResponse.json({ success: false, message: "계산서발행 이후 발주는 수정할 수 없습니다." }, { status: 400 }); } } else { // USER: 본인 발주의 REQUESTED + APPROVED (입금 완료 전) 모두 수량 수정 가능 @@ -148,9 +148,9 @@ export async function POST(req: NextRequest) { const isFree = cur.is_tax_free === "Y"; const calc = calcLine({ unitPrice: Number(cur.unit_price), qty: newQty, isTaxFree: isFree }); - // 출고완료(APPROVED) 상태에서 수량 변경 시 재고 ± 동기화 + stock_moves 이력 + // 출고완료(APPROVED) / 입금완료(PAID) 상태에서 수량 변경 시 재고 ± 동기화 + stock_moves 이력 // ITEM 종류만 (택배/용차는 재고 미차감이라 skip — 위 cur.kind 검사로 ITEM 확정됨) - if (order.status === "APPROVED") { + if (order.status === "APPROVED" || order.status === "PAID") { const oldQty = Number(cur.qty); const diff = newQty - oldQty; // +면 추가 차감, -면 복원 if (diff !== 0) {