From 1f9b017617b4b1ff79ba729c0125b45647efbc36 Mon Sep 17 00:00:00 2001 From: chpark Date: Sat, 2 May 2026 00:26:20 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat(momo=20v0.4):=20=EB=B0=9C=EC=A3=BC?= =?UTF-8?q?=EC=84=9C=20=ED=83=9D=EB=B0=B0/=EC=9A=A9=EC=B0=A8=20=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=20+=20=ED=83=9D=EB=B0=B0=EC=A0=84=EC=9A=A9=20?= =?UTF-8?q?=ED=92=88=EB=AA=A9=20=EC=9E=90=EB=8F=99=20=EB=9D=BC=EC=9D=B8=20?= =?UTF-8?q?+=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20=EB=B0=98=EC=9D=91=ED=98=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [DB 010] - momo_items.requires_delivery (택배 전용 플래그) - momo_order_items.kind (ITEM/DELIVERY/CHARTER) + extra_label - momo_orders.total_delivery / total_charter [발주] - /api/m/orders/save: 택배/용차 라인 처리, 택배전용 품목이 있으면 택배 라인 필수 검증 - /api/m/orders/detail: kind/extra_label/택배비/용차비 응답 - /m/orders/new 재설계: · 택배/용차 추가 버튼 (한 줄씩 생성, 담당자명+금액 수기 입력) · 택배전용 품목 카트에 담기면 자동으로 택배 라인 1줄 추가, 제거 시 차단 · 카트 수량 직접 입력 가능 (재고/한도 자동 클램프) · 모바일 반응형 (2열 그리드, 터치 친화 패딩, sticky 카트바 압축) [품목] - 관리자 등록/수정 폼: 택배 전용 라디오 추가 - 그리드 배지에 택배 표시 - /api/m/items/list: REQUIRES_DELIVERY 응답 - /api/m/items/save: requiresDelivery 필드 처리 Co-Authored-By: Claude Opus 4.7 (1M context) --- db/migrations/010_delivery_charter.sql | 33 +++ src/app/(main)/m/admin/items/page.tsx | 27 +- src/app/(main)/m/orders/new/page.tsx | 342 ++++++++++++++++++------- src/app/api/m/items/list/route.ts | 1 + src/app/api/m/items/save/route.ts | 14 +- src/app/api/m/orders/detail/route.ts | 4 + src/app/api/m/orders/save/route.ts | 90 ++++++- 7 files changed, 400 insertions(+), 111 deletions(-) create mode 100644 db/migrations/010_delivery_charter.sql diff --git a/db/migrations/010_delivery_charter.sql b/db/migrations/010_delivery_charter.sql new file mode 100644 index 0000000..bd59110 --- /dev/null +++ b/db/migrations/010_delivery_charter.sql @@ -0,0 +1,33 @@ +-- 010_delivery_charter.sql +-- v0.4 (2026-04-27) +-- 발주서에 택배비/용차비 라인 + 택배 전용 품목 자동 라인 지원 + +BEGIN; + +-- 1. momo_items: 택배 전용 플래그 +ALTER TABLE momo_items + ADD COLUMN IF NOT EXISTS requires_delivery CHAR(1) NOT NULL DEFAULT 'N'; +COMMENT ON COLUMN momo_items.requires_delivery + IS '택배 전용 품목 (Y) — 카트에 담기면 택배 라인이 자동으로 추가됨'; + +-- 2. momo_order_items: 라인 종류 + 라벨 +-- kind: 'ITEM'(품목) / 'DELIVERY'(택배비) / 'CHARTER'(용차비) +ALTER TABLE momo_order_items + ADD COLUMN IF NOT EXISTS kind VARCHAR(16) NOT NULL DEFAULT 'ITEM', + ADD COLUMN IF NOT EXISTS extra_label VARCHAR(100); +COMMENT ON COLUMN momo_order_items.kind + IS 'ITEM=품목 / DELIVERY=택배비 / CHARTER=용차비'; +COMMENT ON COLUMN momo_order_items.extra_label + IS '택배비/용차비 라인의 담당자명 또는 부가 메모'; + +-- 기존 가맹 데이터는 ITEM 으로 간주 +UPDATE momo_order_items SET kind = 'ITEM' WHERE kind IS NULL; + +-- 3. momo_orders: 택배비/용차비 합계 (집계 편의용) +ALTER TABLE momo_orders + ADD COLUMN IF NOT EXISTS total_delivery NUMERIC(15,2) DEFAULT 0, + ADD COLUMN IF NOT EXISTS total_charter NUMERIC(15,2) DEFAULT 0; +COMMENT ON COLUMN momo_orders.total_delivery IS '택배비 라인 합계'; +COMMENT ON COLUMN momo_orders.total_charter IS '용차비 라인 합계'; + +COMMIT; diff --git a/src/app/(main)/m/admin/items/page.tsx b/src/app/(main)/m/admin/items/page.tsx index 7e192dd..4a9c0da 100644 --- a/src/app/(main)/m/admin/items/page.tsx +++ b/src/app/(main)/m/admin/items/page.tsx @@ -21,6 +21,7 @@ interface Item { ATTRIBUTES: Record | null; MAX_ORDER_QTY: number | null; IS_HIDDEN: string; + REQUIRES_DELIVERY: string; } interface Maker { OBJID: string; MAKER_NAME: string } @@ -80,7 +81,7 @@ export default function AdminItemsPage() { }; const openNew = () => { - setEditing({ ITEM_NAME: "", UNIT: "EA", IS_TAX_FREE: "N", STATUS: "ACTIVE", IS_HIDDEN: "N", MAX_ORDER_QTY: null }); + setEditing({ ITEM_NAME: "", UNIT: "EA", IS_TAX_FREE: "N", STATUS: "ACTIVE", IS_HIDDEN: "N", MAX_ORDER_QTY: null, REQUIRES_DELIVERY: "N" }); setAttrs({}); }; @@ -103,6 +104,7 @@ export default function AdminItemsPage() { attributes: Object.keys(attrs).length > 0 ? attrs : null, maxOrderQty: editing.MAX_ORDER_QTY ?? null, isHidden: editing.IS_HIDDEN === "Y" ? "Y" : "N", + requiresDelivery: editing.REQUIRES_DELIVERY === "Y" ? "Y" : "N", }; const res = await fetch("/api/m/items/save", { method: "POST", @@ -260,6 +262,9 @@ export default function AdminItemsPage() { {it.MAX_ORDER_QTY != null && Number(it.MAX_ORDER_QTY) > 0 && ( ≤{it.MAX_ORDER_QTY} )} + {it.REQUIRES_DELIVERY === "Y" && ( + 택배 + )}