From 6ad57356a054dd6ca9529ae98db0f6adc424bb9b Mon Sep 17 00:00:00 2001 From: chpark Date: Wed, 13 May 2026 15:29:02 +0900 Subject: [PATCH] =?UTF-8?q?feat(statement-branch):=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=EB=B3=84=20=EA=B1=B0=EB=9E=98=EB=AA=85=EC=84=B8?= =?UTF-8?q?=EC=84=9C=20=EA=B3=B5=EA=B8=89=EC=9E=90=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EB=B6=84=EA=B8=B0=20(=EB=B3=B8=EC=82=AC/=EA=B9=80=ED=8F=AC)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 마이그레이션 027: - user_info 에 statement_branch VARCHAR(10) DEFAULT 'HQ' 컬럼 추가 - 기존 사용자 일괄 'HQ' 로 채움 라이브러리: - src/lib/momo-branches.ts 신설 — HQ / KIMPO 두 branch 의 공급자 정보 정의 · HQ: 기업은행 434-115361-01-016 (이상용) / 010-6369-8443 / momo8443@daum.net · KIMPO: 농협 351-1383-7634-13 (모모유통) / 010-5789-9431 / momokimpo@nate.com - getSupplierByBranch(branch) helper 거래명세표 supplier 분기 (3개 API): - /api/m/orders/detail: order.STATEMENT_BRANCH 따라 supplier 객체 결정 - /api/m/orders/statement/[id]: xlsx 다운로드도 동일 - /api/m/orders/approve: 메일 발송 stmt 도 동일 사용자 수정 폼: - /api/admin/users/detail: statement_branch 반환 (default 'HQ') - /api/admin/users/save: statement_branch 받아 UPDATE - /admin-panel/user-form: "기준 거래명세서" select 추가 (본사/김포) 흐름: 거래처 사용자의 기준을 김포로 설정 → 그 사용자의 발주에 대한 거래명세표 supplier 가 김포 정보로 표시 Co-Authored-By: Claude Opus 4.7 (1M context) --- db/migrations/027_user_statement_branch.sql | 7 ++++ src/app/admin-panel/user-form/page.tsx | 11 ++++++ src/app/api/admin/users/detail/route.ts | 1 + src/app/api/admin/users/save/route.ts | 6 ++- src/app/api/m/orders/approve/route.ts | 12 +++--- src/app/api/m/orders/detail/route.ts | 15 +++----- src/app/api/m/orders/statement/[id]/route.ts | 12 +++--- src/lib/momo-branches.ts | 39 ++++++++++++++++++++ 8 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 db/migrations/027_user_statement_branch.sql create mode 100644 src/lib/momo-branches.ts diff --git a/db/migrations/027_user_statement_branch.sql b/db/migrations/027_user_statement_branch.sql new file mode 100644 index 0000000..587592d --- /dev/null +++ b/db/migrations/027_user_statement_branch.sql @@ -0,0 +1,7 @@ +-- 사용자별 거래명세서 기준 지점 (본사 / 김포) +-- 거래명세표 발급 시 공급자(supplier) 정보를 두 가지로 분기하기 위함 +ALTER TABLE user_info + ADD COLUMN IF NOT EXISTS statement_branch VARCHAR(10) DEFAULT 'HQ'; + +-- 기존 사용자는 모두 본사로 default +UPDATE user_info SET statement_branch = 'HQ' WHERE statement_branch IS NULL; diff --git a/src/app/admin-panel/user-form/page.tsx b/src/app/admin-panel/user-form/page.tsx index 2b7a266..466dd45 100644 --- a/src/app/admin-panel/user-form/page.tsx +++ b/src/app/admin-panel/user-form/page.tsx @@ -111,6 +111,17 @@ function UserForm() { ))} +
+ + +
diff --git a/src/app/api/admin/users/detail/route.ts b/src/app/api/admin/users/detail/route.ts index c1f29b0..23693ed 100644 --- a/src/app/api/admin/users/detail/route.ts +++ b/src/app/api/admin/users/detail/route.ts @@ -17,6 +17,7 @@ export async function POST(request: NextRequest) { COALESCE(unlimited_qty, 'N') AS "unlimited_qty", COALESCE(view_hidden, 'N') AS "view_hidden", default_wh_objid::text AS "default_wh_objid", + COALESCE(statement_branch, 'HQ') AS "statement_branch", TO_CHAR(regdate, 'YYYY-MM-DD') AS "regdate" FROM user_info WHERE user_id = $1`, [body.userId || ""] diff --git a/src/app/api/admin/users/save/route.ts b/src/app/api/admin/users/save/route.ts index 781ac6e..8a15816 100644 --- a/src/app/api/admin/users/save/route.ts +++ b/src/app/api/admin/users/save/route.ts @@ -33,6 +33,7 @@ export async function POST(request: NextRequest) { const viewHidden = body.view_hidden === "Y" ? "Y" : "N"; // 빈 문자열 / undefined → NULL 처리 const defaultWh = body.default_wh_objid && String(body.default_wh_objid).trim() !== "" ? body.default_wh_objid : null; + const stmtBranch = body.statement_branch === "KIMPO" ? "KIMPO" : "HQ"; await client.query( `UPDATE user_info SET user_name=$1, sabun=$2, dept_code=$3, dept_name=$4, @@ -40,14 +41,15 @@ export async function POST(request: NextRequest) { address=COALESCE($11, address), ceo_name=COALESCE($12, ceo_name), biz_no=COALESCE($13, biz_no), unlimited_qty=$14, view_hidden=$15, - default_wh_objid=$16 + default_wh_objid=$16, + statement_branch=$17 WHERE user_id=$10`, [body.user_name || "", body.sabun || "", body.dept_code || "", body.dept_name || "", body.position_name || "", body.email || "", body.cell_phone || "", body.user_type || "", body.tel || "", body.user_id || "", body.address ?? null, body.ceo_name ?? null, body.biz_no ?? null, - unlimited, viewHidden, defaultWh] + unlimited, viewHidden, defaultWh, stmtBranch] ); } return NextResponse.json({ success: true, message: isNew ? "등록되었습니다." : "수정되었습니다." }); diff --git a/src/app/api/m/orders/approve/route.ts b/src/app/api/m/orders/approve/route.ts index 2429066..cbe9285 100644 --- a/src/app/api/m/orders/approve/route.ts +++ b/src/app/api/m/orders/approve/route.ts @@ -5,6 +5,7 @@ import { createObjectId } from "@/lib/utils"; import { requireMomoAdmin } from "@/lib/momo-guard"; import { buildStatementHtml, buildStatementXlsx } from "@/lib/excel-statement"; import { sendMail } from "@/lib/mailer"; +import { getSupplierByBranch } from "@/lib/momo-branches"; export async function POST(req: NextRequest) { const g = await requireMomoAdmin(); @@ -114,6 +115,7 @@ export async function POST(req: NextRequest) { `SELECT O.objid, O.order_no, TO_CHAR(O.order_date,'YYYY-MM-DD') AS order_date, U.user_name AS company_name, U.email, U.ceo_name, U.biz_no, U.cell_phone AS phone, U.address, + U.statement_branch, O.total_supply, O.total_vat, O.total_amount, O.total_taxfree, O.total_taxable FROM momo_orders O @@ -137,12 +139,10 @@ export async function POST(req: NextRequest) { bizNo: order.biz_no as string | undefined, phone: order.phone as string | undefined, }, - supplier: { - companyName: "모모유통", - bankAccount: process.env.MOMO_BANK_ACCOUNT ?? "기업은행 ____", - phone: process.env.MOMO_PHONE ?? "010-6624-5315", - email: process.env.SMTP_FROM ?? "momo8443@daum.net", - }, + supplier: (() => { + const b = getSupplierByBranch(order.statement_branch as string | undefined); + return { companyName: b.NAME, bankAccount: b.BANK_ACCOUNT, phone: b.PHONE, email: b.EMAIL }; + })(), items: items.map((it) => ({ seq: Number(it.seq), itemName: String(it.item_name_snap), diff --git a/src/app/api/m/orders/detail/route.ts b/src/app/api/m/orders/detail/route.ts index 596a60a..4c98d3e 100644 --- a/src/app/api/m/orders/detail/route.ts +++ b/src/app/api/m/orders/detail/route.ts @@ -1,6 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { queryOne, queryRows } from "@/lib/db"; import { requireMomoUser } from "@/lib/momo-guard"; +import { getSupplierByBranch } from "@/lib/momo-branches"; export async function POST(req: NextRequest) { const r = await requireMomoUser(); @@ -17,6 +18,7 @@ export async function POST(req: NextRequest) { U.user_name AS "COMPANY_NAME", U.email AS "EMAIL", U.ceo_name AS "CEO_NAME", U.biz_no AS "BIZ_NO", U.cell_phone AS "PHONE", U.address AS "ADDRESS", + U.statement_branch AS "STATEMENT_BRANCH", O.status AS "STATUS", O.memo AS "MEMO", O.total_supply AS "TOTAL_SUPPLY", O.total_vat AS "TOTAL_VAT", O.total_amount AS "TOTAL_AMOUNT", @@ -75,16 +77,9 @@ export async function POST(req: NextRequest) { [objid] ); - // 공급자(모모유통) 정보 — 환경변수 또는 기본값 - const supplier = { - NAME: process.env.MOMO_COMPANY_NAME || "모모유통", - CEO: process.env.MOMO_COMPANY_CEO || "이상용", - BIZ_NO: process.env.MOMO_COMPANY_BIZNO || "", - BANK_ACCOUNT: process.env.MOMO_BANK_ACCOUNT || "기업은행 434-115361-01-016 (이상용)", - PHONE: process.env.MOMO_PHONE || "010-6369-8443", - EMAIL: process.env.MOMO_EMAIL || "momo8443@daum.net", - ADDRESS: process.env.MOMO_COMPANY_ADDR || "", - }; + // 공급자(모모유통) 정보 — 거래처(사용자)의 statement_branch (HQ / KIMPO) 에 따라 분기 + const branch = (order as { STATEMENT_BRANCH?: string }).STATEMENT_BRANCH ?? "HQ"; + const supplier = getSupplierByBranch(branch); return NextResponse.json({ success: true, order, items, supplier }); } diff --git a/src/app/api/m/orders/statement/[id]/route.ts b/src/app/api/m/orders/statement/[id]/route.ts index 28dd80d..438ce04 100644 --- a/src/app/api/m/orders/statement/[id]/route.ts +++ b/src/app/api/m/orders/statement/[id]/route.ts @@ -3,6 +3,7 @@ import { NextRequest, NextResponse } from "next/server"; import { queryOne, queryRows } from "@/lib/db"; import { requireMomoUser } from "@/lib/momo-guard"; import { buildStatementXlsx } from "@/lib/excel-statement"; +import { getSupplierByBranch } from "@/lib/momo-branches"; export async function GET(req: NextRequest, ctx: { params: Promise<{ id: string }> }) { const r = await requireMomoUser(); @@ -18,6 +19,7 @@ export async function GET(req: NextRequest, ctx: { params: Promise<{ id: string U.cell_phone AS phone, U.address AS address, U.email AS email, + U.statement_branch AS statement_branch, O.total_supply, O.total_vat, O.total_amount, O.total_taxfree, O.total_taxable, COALESCE(O.paid_amount, 0) AS paid_amount @@ -55,12 +57,10 @@ export async function GET(req: NextRequest, ctx: { params: Promise<{ id: string bizNo: order.biz_no as string | undefined, phone: order.phone as string | undefined, }, - supplier: { - companyName: "모모유통", - bankAccount: process.env.MOMO_BANK_ACCOUNT ?? "기업은행 ____", - phone: process.env.MOMO_PHONE ?? "010-6624-5315", - email: process.env.SMTP_FROM ?? "momo8443@daum.net", - }, + supplier: (() => { + const b = getSupplierByBranch(order.statement_branch as string | undefined); + return { companyName: b.NAME, bankAccount: b.BANK_ACCOUNT, phone: b.PHONE, email: b.EMAIL }; + })(), items: items.map((it, idx) => { const isExtra = it.kind === "DELIVERY" || it.kind === "CHARTER"; return { diff --git a/src/lib/momo-branches.ts b/src/lib/momo-branches.ts new file mode 100644 index 0000000..583f6d4 --- /dev/null +++ b/src/lib/momo-branches.ts @@ -0,0 +1,39 @@ +// 모모유통 공급자(supplier) 정보 — 거래명세표/계산서 발행 시 사용자별로 분기 +// 사용자(user_info.statement_branch) 가 'HQ' / 'KIMPO' 중 어느 값이냐에 따라 적용 +export type StatementBranch = "HQ" | "KIMPO"; + +export interface BranchSupplier { + NAME: string; + CEO: string; + BANK_ACCOUNT: string; + PHONE: string; + EMAIL: string; + BIZ_NO: string; + ADDRESS: string; +} + +export const SUPPLIER_BRANCHES: Record = { + HQ: { + NAME: "모모유통", + CEO: "이상용", + BANK_ACCOUNT: "기업은행 434-115361-01-016 (이상용)", + PHONE: "010-6369-8443", + EMAIL: "momo8443@daum.net", + BIZ_NO: "", + ADDRESS: "", + }, + KIMPO: { + NAME: "모모유통", + CEO: "이상용", + BANK_ACCOUNT: "농협 351-1383-7634-13 (모모유통)", + PHONE: "010-5789-9431", + EMAIL: "momokimpo@nate.com", + BIZ_NO: "", + ADDRESS: "", + }, +}; + +export function getSupplierByBranch(branch?: string | null): BranchSupplier { + const key = (branch === "KIMPO" ? "KIMPO" : "HQ") as StatementBranch; + return SUPPLIER_BRANCHES[key]; +}