fix(orders): 거래명세표 공급자 정보 발주 시점 snapshot 처리
Deploy momo-erp / deploy (push) Successful in 3m37s

기존: 거래명세표 발급 때마다 user_info.statement_branch + branches table
을 실시간 조회 → 사용자의 기준 명세표를 바꾸거나, branches 의 계좌/
전화/이메일을 수정하면 과거 이미 찍힌 명세표까지 함께 바뀌어버림.

수정: 출고요청(REQUESTED) 시점에 supplier 8개 컬럼을 momo_orders 행에
박아두고, 이후 detail/statement/approve 는 이 snapshot 을 사용.

- 마이그레이션 030: momo_orders 에 supplier_branch / supplier_name /
  supplier_ceo / supplier_bank_account / supplier_phone / supplier_email
  / supplier_biz_no / supplier_address 컬럼 추가 (idempotent IF NOT EXISTS)
- save: 발주 INSERT 시 getSupplierByBranch(user.statement_branch) 호출 결과
  를 그대로 박음
- detail/statement/approve: snapshot 컬럼이 있으면 그것을 사용, 없으면
  옛 발주용 폴백으로 user_info.statement_branch → branches table 조회
This commit is contained in:
chpark
2026-05-13 16:39:40 +09:00
parent 2fffc42575
commit 0bfe85dc69
5 changed files with 89 additions and 10 deletions
@@ -0,0 +1,16 @@
-- 발주별 공급자(거래명세표) snapshot 컬럼 추가
-- 사용자(user_info.statement_branch) 의 기준 명세표를 바꾸면, 또는 명세표 자체(계좌/전화 등)를
-- 바꾸면, 과거에 이미 찍힌 거래명세표까지 함께 바뀌어버리는 버그 fix.
-- 발주 시점의 공급자 정보를 momo_orders 행에 그대로 박아둔다.
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_branch VARCHAR(20);
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_name VARCHAR(100);
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_ceo VARCHAR(50);
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_bank_account VARCHAR(200);
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_phone VARCHAR(50);
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_email VARCHAR(200);
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_biz_no VARCHAR(50);
ALTER TABLE momo_orders ADD COLUMN IF NOT EXISTS supplier_address VARCHAR(500);
-- 기존 발주 (NULL) 은 detail/statement API 에서 user_info.statement_branch 폴백으로 처리.
-- 신규 발주만 snapshot 박힘.
+12
View File
@@ -119,6 +119,9 @@ export async function POST(req: NextRequest) {
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.supplier_branch, O.supplier_name, O.supplier_ceo,
O.supplier_bank_account, O.supplier_phone, O.supplier_email,
O.supplier_biz_no, O.supplier_address,
O.total_supply, O.total_vat, O.total_amount,
O.total_taxfree, O.total_taxable
FROM momo_orders O
@@ -143,6 +146,15 @@ export async function POST(req: NextRequest) {
phone: order.phone as string | undefined,
},
supplier: await (async () => {
// snapshot 우선 (출고요청 시점), 없으면 사용자 기준 명세표 폴백
if (order.supplier_bank_account) {
return {
companyName: String(order.supplier_name ?? "모모유통"),
bankAccount: String(order.supplier_bank_account),
phone: String(order.supplier_phone ?? ""),
email: String(order.supplier_email ?? ""),
};
}
const b = await getSupplierByBranch(order.statement_branch as string | undefined);
return { companyName: b.NAME, bankAccount: b.BANK_ACCOUNT, phone: b.PHONE, email: b.EMAIL };
})(),
+25 -4
View File
@@ -28,7 +28,15 @@ export async function POST(req: NextRequest) {
O.invoice_no AS "INVOICE_NO",
TO_CHAR(O.invoice_date,'YYYY-MM-DD') AS "INVOICE_DATE",
O.paid_amount AS "PAID_AMOUNT",
TO_CHAR(O.approve_date,'YYYY-MM-DD HH24:MI') AS "APPROVE_DATE"
TO_CHAR(O.approve_date,'YYYY-MM-DD HH24:MI') AS "APPROVE_DATE",
O.supplier_branch AS "SUPPLIER_BRANCH",
O.supplier_name AS "SUPPLIER_NAME",
O.supplier_ceo AS "SUPPLIER_CEO",
O.supplier_bank_account AS "SUPPLIER_BANK_ACCOUNT",
O.supplier_phone AS "SUPPLIER_PHONE",
O.supplier_email AS "SUPPLIER_EMAIL",
O.supplier_biz_no AS "SUPPLIER_BIZ_NO",
O.supplier_address AS "SUPPLIER_ADDRESS"
FROM momo_orders O
LEFT JOIN user_info U ON U.user_id = O.customer_objid
WHERE O.objid = $1 AND COALESCE(O.is_del,'N') != 'Y'`,
@@ -88,9 +96,22 @@ export async function POST(req: NextRequest) {
[objid]
);
// 공급자(모모유통) 정보 — 거래처(사용자)의 statement_branch 에 따라 DB 분기
const branch = (order as { STATEMENT_BRANCH?: string }).STATEMENT_BRANCH ?? "HQ";
const supplier = await getSupplierByBranch(branch);
// 공급자(모모유통) 정보:
// - 출고요청 시점에 momo_orders.supplier_* 컬럼에 snapshot 박힘 → 그것을 사용
// - 옛 발주(snapshot 없음) 는 user_info.statement_branch + branches table 폴백
const o = order as Record<string, unknown>;
const supplier = o.SUPPLIER_BANK_ACCOUNT
? {
CODE: String(o.SUPPLIER_BRANCH ?? "HQ"),
NAME: String(o.SUPPLIER_NAME ?? "모모유통"),
CEO: String(o.SUPPLIER_CEO ?? ""),
BANK_ACCOUNT: String(o.SUPPLIER_BANK_ACCOUNT ?? ""),
PHONE: String(o.SUPPLIER_PHONE ?? ""),
EMAIL: String(o.SUPPLIER_EMAIL ?? ""),
BIZ_NO: String(o.SUPPLIER_BIZ_NO ?? ""),
ADDRESS: String(o.SUPPLIER_ADDRESS ?? ""),
}
: await getSupplierByBranch(String(o.STATEMENT_BRANCH ?? "HQ"));
return NextResponse.json({ success: true, order, items, supplier });
}
+19 -6
View File
@@ -5,6 +5,7 @@ import { pool, queryOne } from "@/lib/db";
import { createObjectId } from "@/lib/utils";
import { requireMomoUser } from "@/lib/momo-guard";
import { calcLine, sumTotals } from "@/lib/momo-pricing";
import { getSupplierByBranch } from "@/lib/momo-branches";
interface InputItemLine {
itemObjid: string;
@@ -64,11 +65,18 @@ export async function POST(req: NextRequest) {
try {
const customerRow = await pool.query(
`SELECT COALESCE(unlimited_qty, 'N') AS unlimited_qty, COALESCE(view_hidden, 'N') AS view_hidden FROM user_info WHERE user_id = $1`,
`SELECT COALESCE(unlimited_qty, 'N') AS unlimited_qty,
COALESCE(view_hidden, 'N') AS view_hidden,
COALESCE(statement_branch, 'HQ') AS statement_branch
FROM user_info WHERE user_id = $1`,
[customerObjid]
);
const unlimitedQty = customerRow.rows[0]?.unlimited_qty === "Y";
const viewHidden = customerRow.rows[0]?.view_hidden === "Y";
const unlimitedQty = customerRow.rows[0]?.unlimited_qty === "Y";
const viewHidden = customerRow.rows[0]?.view_hidden === "Y";
const customerBranch = customerRow.rows[0]?.statement_branch ?? "HQ";
// 출고요청 시점의 공급자(거래명세표) 정보를 snapshot — 이후 기준 명세표/사용자
// 설정을 바꿔도 이미 찍힌 명세표는 그대로 유지됨.
const supplierSnap = await getSupplierByBranch(customerBranch);
const itemIds = lines.map((l) => l.itemObjid);
const placeholders = itemIds.map((_, i) => `$${i + 1}`).join(",");
@@ -185,13 +193,18 @@ export async function POST(req: NextRequest) {
objid, order_no, customer_objid, order_date, status,
total_supply, total_vat, total_amount, total_taxfree, total_taxable,
total_delivery, total_charter,
memo, regdate, regid
) VALUES ($1,$2,$3,CURRENT_DATE,'REQUESTED',$4,$5,$6,$7,$8,$9,$10,$11,NOW(),$12)`,
memo, regdate, regid,
supplier_branch, supplier_name, supplier_ceo, supplier_bank_account,
supplier_phone, supplier_email, supplier_biz_no, supplier_address
) VALUES ($1,$2,$3,CURRENT_DATE,'REQUESTED',$4,$5,$6,$7,$8,$9,$10,$11,NOW(),$12,
$13,$14,$15,$16,$17,$18,$19,$20)`,
[orderObjid, orderNo, customerObjid,
totals.supply, totals.vat, totals.total, totals.taxFree, totals.taxable,
totalDelivery, totalCharter,
memo ?? null,
customerObjid]
customerObjid,
supplierSnap.CODE, supplierSnap.NAME, supplierSnap.CEO, supplierSnap.BANK_ACCOUNT,
supplierSnap.PHONE, supplierSnap.EMAIL, supplierSnap.BIZ_NO, supplierSnap.ADDRESS]
);
for (const ln of enriched) {
await client.query(
@@ -20,6 +20,14 @@ export async function GET(req: NextRequest, ctx: { params: Promise<{ id: string
U.address AS address,
U.email AS email,
U.statement_branch AS statement_branch,
O.supplier_branch AS supplier_branch,
O.supplier_name AS supplier_name,
O.supplier_ceo AS supplier_ceo,
O.supplier_bank_account AS supplier_bank_account,
O.supplier_phone AS supplier_phone,
O.supplier_email AS supplier_email,
O.supplier_biz_no AS supplier_biz_no,
O.supplier_address AS supplier_address,
O.total_supply, O.total_vat, O.total_amount,
O.total_taxfree, O.total_taxable,
COALESCE(O.paid_amount, 0) AS paid_amount
@@ -58,6 +66,15 @@ export async function GET(req: NextRequest, ctx: { params: Promise<{ id: string
phone: order.phone as string | undefined,
},
supplier: await (async () => {
// snapshot (출고요청 시점) 우선, 없으면 사용자 기준 명세표 폴백
if (order.supplier_bank_account) {
return {
companyName: String(order.supplier_name ?? "모모유통"),
bankAccount: String(order.supplier_bank_account),
phone: String(order.supplier_phone ?? ""),
email: String(order.supplier_email ?? ""),
};
}
const b = await getSupplierByBranch(order.statement_branch as string | undefined);
return { companyName: b.NAME, bankAccount: b.BANK_ACCOUNT, phone: b.PHONE, email: b.EMAIL };
})(),