diff --git a/src/app/(main)/m/admin/inbounds/page.tsx b/src/app/(main)/m/admin/inbounds/page.tsx index 74c999b..1c05985 100644 --- a/src/app/(main)/m/admin/inbounds/page.tsx +++ b/src/app/(main)/m/admin/inbounds/page.tsx @@ -42,6 +42,23 @@ export default function InboundsPage() { // 라인별 입력 (창고/입고수량/불량수량) const [inputs, setInputs] = useState>({}); + // 입고 체크리스트 + const [checklist, setChecklist] = useState({ + qtyMatch: false, // 1) 발주수량/입고수량 일치 + cartonMatch: false, // 2) 1카톤 N개 일치 + cartonSize: "", // 카톤 단위 + expiryDate: "", // 3) 소비기한 + completedBy: "", // 4) 물류팀 입고 최종완료자 + remark: "", // 5) 특이건 메모 + }); + // 물류팀 4명 — 임직원(user_type='A') 중 momo4763/momo7529 외 2명까지 + const LOGISTICS = [ + { id: "momo4763", name: "이효철 (물류총괄)" }, + { id: "momo7529", name: "유우형 (물류팀장)" }, + { id: "momo9431", name: "강상익 (김포지사 총괄)" }, + { id: "momo5315", name: "배연진 (경영팀장)" }, + ]; + const load = useCallback(async () => { const body: Record = {}; // 입고 화면은 REQUESTED + PARTIAL 만 보이게 @@ -150,6 +167,15 @@ export default function InboundsPage() { }); if (!ok.isConfirmed) return; + // 체크리스트 텍스트화 — memo 에 저장 (스키마 변경 없이) + const checklistMemo = [ + `[수량 일치] ${checklist.qtyMatch ? "Y ✓" : "N"}`, + `[카톤 일치] ${checklist.cartonMatch ? `Y ✓ (1카톤 ${checklist.cartonSize || "?"}개)` : "N"}`, + `[소비기한] ${checklist.expiryDate || "-"}`, + `[입고완료자] ${checklist.completedBy || "-"}`, + `[특이사항] ${checklist.remark || "-"}`, + ].join("\n"); + setBusy(true); let successCnt = 0, failCnt = 0; const errors: string[] = []; @@ -161,6 +187,7 @@ export default function InboundsPage() { procObjid: detail.proc.OBJID, whObjid, lines: whLines, + memo: checklistMemo, }), }); const j = await res.json(); @@ -281,6 +308,9 @@ export default function InboundsPage() { warehouses={warehouses} inputs={inputs} onUpdate={updateInput} + checklist={checklist} + onChecklistChange={(patch) => setChecklist((p) => ({ ...p, ...patch }))} + logistics={LOGISTICS} /> )} @@ -290,11 +320,18 @@ export default function InboundsPage() { ); } -function InboundForm({ detail, warehouses, inputs, onUpdate }: { +interface Checklist { + qtyMatch: boolean; cartonMatch: boolean; cartonSize: string; + expiryDate: string; completedBy: string; remark: string; +} +function InboundForm({ detail, warehouses, inputs, onUpdate, checklist, onChecklistChange, logistics }: { detail: { proc: ProcDetail; items: ProcLine[] }; warehouses: Warehouse[]; inputs: Record; onUpdate: (lineObjid: string, patch: Partial<{ whObjid: string; qtyNormal: number; qtyDefect: number }>) => void; + checklist: Checklist; + onChecklistChange: (patch: Partial) => void; + logistics: { id: string; name: string }[]; }) { const editable = detail.proc.STATUS === "PAID" || detail.proc.STATUS === "PARTIAL"; return ( @@ -386,10 +423,65 @@ function InboundForm({ detail, warehouses, inputs, onUpdate }: { {editable && ( + <>
※ 정상 입고 + 불량은 남은 수량 이하로만 입력 가능합니다. 0으로 두면 그 라인은 입고하지 않습니다.
※ 일부 라인만 입고하면 발주서가 입고중으로 표시되고, 나중에 다시 들어와 마저 입고할 수 있어요.
+ + {/* 입고 체크리스트 — memo 컬럼에 함께 저장 */} +
+
📋 입고 체크리스트
+ + + +
+ + onChecklistChange({ cartonSize: e.target.value })} + placeholder="개수" + className="w-20 h-7 px-2 border border-slate-300 rounded text-[11px] text-right tabular-nums" /> + 개 일치하나요? +
+ +
+ 3) 소비기한 + onChecklistChange({ expiryDate: e.target.value })} + className="h-7 px-2 border border-slate-300 rounded text-[11px]" /> +
+ +
+ 4) 물류창고 입고 최종완료자 + +
+ +
+
5) 특이사항
+