feat(procurements): 입고완료 이후 수정 잠금 + 공급업체 SearchableSelect
Deploy momo-erp / deploy (push) Successful in 2m54s
Deploy momo-erp / deploy (push) Successful in 2m54s
- 매입 발주서 editable 재조정: OPEN/REQUESTED 만 수정 가능. RECEIVED/ PARTIAL/PAID/CANCELLED 는 수정 불가. lines/save API 가드도 동일. - 공급업체 select 를 SearchableSelect 로 교체 (typeahead): · 매입 발주서 관리 페이지의 발주서 폼 (page.tsx) · 매입 발주 신규 작성 페이지 (new/page.tsx) 운영 DB 의 매입 발주/입고/관련 stock_moves 데이터는 직접 모두 삭제했음 (사용자 명시 요청). UI 에 깨끗한 상태로 보임.
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Trash2, Plus } from "lucide-react";
|
||||
import Swal from "sweetalert2";
|
||||
import { SearchableSelect } from "@/components/ui/searchable-select";
|
||||
|
||||
interface Vendor { OBJID: string; VENDOR_NAME: string }
|
||||
interface Item { OBJID: string; ITEM_CODE: string; ITEM_NAME: string; COST_PRICE: number }
|
||||
@@ -58,10 +59,14 @@ export default function NewProcPage() {
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-600">공급업체 *</label>
|
||||
<select value={vendorObjid} onChange={(e) => setVendorObjid(e.target.value)} className="w-full h-10 px-3 rounded-lg border border-slate-200 mt-1">
|
||||
<option value="">선택</option>
|
||||
{vendors.map((v) => <option key={v.OBJID} value={v.OBJID}>{v.VENDOR_NAME}</option>)}
|
||||
</select>
|
||||
<div className="mt-1">
|
||||
<SearchableSelect
|
||||
value={vendorObjid}
|
||||
onChange={setVendorObjid}
|
||||
options={vendors.map((v) => ({ value: v.OBJID, label: v.VENDOR_NAME }))}
|
||||
placeholder="공급업체 검색/선택"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-600">발주일</label>
|
||||
|
||||
@@ -352,8 +352,9 @@ function ProcurementForm({ detail, vendors, onSetVendor, onSetMemo, onSetTerm, o
|
||||
onUpdateLine: (line: { objid?: string; itemObjid?: string; qty: number; costPrice: number }) => void;
|
||||
onDeleteLine: (objid: string) => void;
|
||||
}) {
|
||||
// 입금완료(PAID)/취소(CANCELLED) 전까지 수정 허용 — 발주요청/입고완료/부분입고 도 수량 수정 가능
|
||||
const editable = !["PAID", "CANCELLED"].includes(detail.proc.STATUS);
|
||||
// OPEN(작성중) / REQUESTED(발주요청) 만 수정 가능.
|
||||
// RECEIVED(입고완료) / PARTIAL(부분입고) / PAID(입금완료) / CANCELLED 는 수정 불가.
|
||||
const editable = ["OPEN", "REQUESTED"].includes(detail.proc.STATUS);
|
||||
const formRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleCapture = async () => {
|
||||
@@ -419,12 +420,14 @@ function ProcurementForm({ detail, vendors, onSetVendor, onSetMemo, onSetTerm, o
|
||||
<th className="border border-slate-400 bg-slate-100 px-2 py-1 text-center">공급업체</th>
|
||||
<td className="border border-slate-400 px-3 py-1">
|
||||
{editable ? (
|
||||
<select value={detail.proc.VENDOR_OBJID ?? ""}
|
||||
onChange={(e) => onSetVendor(e.target.value)}
|
||||
className="h-7 px-2 rounded border border-slate-300 text-[11px] bg-white">
|
||||
<option value="">-- 공급업체 선택 --</option>
|
||||
{vendors.map((v) => <option key={v.OBJID} value={v.OBJID}>{v.VENDOR_NAME}</option>)}
|
||||
</select>
|
||||
<div className="max-w-[280px]">
|
||||
<SearchableSelect
|
||||
value={detail.proc.VENDOR_OBJID ?? ""}
|
||||
onChange={onSetVendor}
|
||||
options={vendors.map((v) => ({ value: v.OBJID, label: v.VENDOR_NAME }))}
|
||||
placeholder="공급업체 검색/선택"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<span className="font-semibold">{detail.proc.VENDOR_NAME ?? "-"}</span>
|
||||
)}
|
||||
|
||||
@@ -34,10 +34,10 @@ export async function POST(req: NextRequest) {
|
||||
return NextResponse.json({ success: false, message: "발주서를 찾을 수 없습니다." }, { status: 404 });
|
||||
}
|
||||
const status = procRes.rows[0].status;
|
||||
// 입금완료(PAID)/취소(CANCELLED) 외 모든 상태에서 수정 허용
|
||||
if (status === "PAID" || status === "CANCELLED") {
|
||||
// OPEN/REQUESTED 만 허용. 입고완료/부분입고/입금완료/취소는 차단.
|
||||
if (status !== "OPEN" && status !== "REQUESTED") {
|
||||
await client.query("ROLLBACK");
|
||||
return NextResponse.json({ success: false, message: "입금완료/취소 상태는 수정할 수 없습니다." }, { status: 400 });
|
||||
return NextResponse.json({ success: false, message: "입고완료 이후 상태는 수정할 수 없습니다." }, { status: 400 });
|
||||
}
|
||||
|
||||
for (const ln of lines) {
|
||||
|
||||
Reference in New Issue
Block a user