PR-B G2: 주문관리 수주입력 = 직접등록 통합폼 (is_direct_order='Y' + order_date + approval_required)
wace 패턴(estimateAndOrderRegistFormPopup + saveEstimateAndOrderInfo) 이식. 운영 데이터 90건 중 74건이 is_direct_order='Y' — 주문 신규 등록의 기본 흐름. 변경: - 백엔드 OrderBody: order_date / approval_required / is_direct_order 신규 (contract_date 폐지, 운영 컬럼명 일치) - create()/update() INSERT·UPDATE에 위 3개 컬럼 추가. is_direct_order 기본값 'Y' - 프론트 OrderBody 타입 동기화. openCreate 시 order_date=today + is_direct_order='Y' 자동 - 폼 다이얼로그 "발주일" 입력을 order_date 바인딩 (잘못 contract_date 바인딩 정정) 자동 검증 (BEGIN/ROLLBACK): - is_direct_order='Y' INSERT, order_date 저장, ORDER_* 라인 컬럼 정상 - 견적관리 그리드 노출 차단(IS_DIRECT_ORDER!='Y' 필터), 주문관리 그리드 노출 확인 docs/migration/sales/05-direct-order-verify.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,7 @@ export interface OrderItem {
|
||||
}
|
||||
|
||||
export interface OrderBody {
|
||||
// contract_mgmt 헤더
|
||||
// contract_mgmt 헤더 (wace estimateAndOrderRegistFormPopup 직접등록 통합폼 — G2)
|
||||
objid?: string; // 신규면 자동 생성
|
||||
contract_no?: string;
|
||||
category_cd?: string;
|
||||
@@ -57,15 +57,17 @@ export interface OrderBody {
|
||||
paid_type?: string;
|
||||
contract_currency?: string;
|
||||
exchange_rate?: string;
|
||||
receipt_date?: string;
|
||||
contract_date?: string; // 발주일
|
||||
receipt_date?: string; // 접수일 *
|
||||
order_date?: string; // 발주일 * (wace G2 필수)
|
||||
req_del_date?: string; // 요청납기
|
||||
po_no?: string; // 발주번호
|
||||
contract_result?: string; // 수주상태 (예: WAITING/CONFIRMED/CANCELLED)
|
||||
contract_result?: string; // 수주상태
|
||||
approval_required?: string; // 결재여부 'Y'|'N'
|
||||
pm_user_id?: string;
|
||||
customer_request?: string;
|
||||
shipping_method?: string;
|
||||
incoterms?: string;
|
||||
is_direct_order?: string; // 'Y'면 직접등록 (견적관리 노출 X, 주문관리만 노출)
|
||||
// 라인
|
||||
items: OrderItem[];
|
||||
}
|
||||
@@ -435,25 +437,29 @@ export async function create(userId: string, body: OrderBody) {
|
||||
return s + (isNaN(v) ? 0 : v);
|
||||
}, 0);
|
||||
|
||||
// wace G2 패턴: 주문관리 등록은 직접등록 통합폼 — is_direct_order='Y' (견적관리에 노출 X)
|
||||
const isDirectOrder = body.is_direct_order || "Y";
|
||||
|
||||
await client.query(
|
||||
`INSERT INTO contract_mgmt (
|
||||
objid, contract_no, category_cd, customer_objid, product, area_cd, paid_type,
|
||||
contract_currency, exchange_rate, receipt_date, contract_date, req_del_date,
|
||||
po_no, contract_result, pm_user_id, customer_request, shipping_method, incoterms,
|
||||
contract_currency, exchange_rate, receipt_date, order_date, req_del_date,
|
||||
po_no, contract_result, approval_required, pm_user_id, customer_request,
|
||||
shipping_method, incoterms, is_direct_order,
|
||||
order_supply_price, order_vat, order_total_amount,
|
||||
writer, regdate
|
||||
) VALUES (
|
||||
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,
|
||||
$19,$20,$21,$22,NOW()
|
||||
$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,
|
||||
$21,$22,$23,$24,NOW()
|
||||
)`,
|
||||
[
|
||||
objid, contractNo, body.category_cd || null, body.customer_objid || null,
|
||||
body.product || null, body.area_cd || null, body.paid_type || null,
|
||||
body.contract_currency || null, body.exchange_rate || null,
|
||||
body.receipt_date || null, body.contract_date || null, body.req_del_date || null,
|
||||
body.po_no || null, body.contract_result || null,
|
||||
body.receipt_date || null, body.order_date || null, body.req_del_date || null,
|
||||
body.po_no || null, body.contract_result || null, body.approval_required || "N",
|
||||
body.pm_user_id || null, body.customer_request || null,
|
||||
body.shipping_method || null, body.incoterms || null,
|
||||
body.shipping_method || null, body.incoterms || null, isDirectOrder,
|
||||
String(sum("order_supply_price")), String(sum("order_vat")), String(sum("order_total_amount")),
|
||||
userId,
|
||||
],
|
||||
@@ -484,18 +490,18 @@ export async function update(userId: string, objid: string, body: OrderBody) {
|
||||
await client.query(
|
||||
`UPDATE contract_mgmt SET
|
||||
category_cd=$2, customer_objid=$3, product=$4, area_cd=$5, paid_type=$6,
|
||||
contract_currency=$7, exchange_rate=$8, receipt_date=$9, contract_date=$10,
|
||||
req_del_date=$11, po_no=$12, contract_result=$13, pm_user_id=$14,
|
||||
customer_request=$15, shipping_method=$16, incoterms=$17,
|
||||
order_supply_price=$18, order_vat=$19, order_total_amount=$20,
|
||||
chg_user_id=$21
|
||||
contract_currency=$7, exchange_rate=$8, receipt_date=$9, order_date=$10,
|
||||
req_del_date=$11, po_no=$12, contract_result=$13, approval_required=$14, pm_user_id=$15,
|
||||
customer_request=$16, shipping_method=$17, incoterms=$18,
|
||||
order_supply_price=$19, order_vat=$20, order_total_amount=$21,
|
||||
chg_user_id=$22
|
||||
WHERE objid=$1`,
|
||||
[
|
||||
objid, body.category_cd || null, body.customer_objid || null,
|
||||
body.product || null, body.area_cd || null, body.paid_type || null,
|
||||
body.contract_currency || null, body.exchange_rate || null,
|
||||
body.receipt_date || null, body.contract_date || null, body.req_del_date || null,
|
||||
body.po_no || null, body.contract_result || null,
|
||||
body.receipt_date || null, body.order_date || null, body.req_del_date || null,
|
||||
body.po_no || null, body.contract_result || null, body.approval_required || "N",
|
||||
body.pm_user_id || null, body.customer_request || null,
|
||||
body.shipping_method || null, body.incoterms || null,
|
||||
String(sum("order_supply_price")), String(sum("order_vat")), String(sum("order_total_amount")),
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# 05. PR-B G2 — 주문관리 직접등록 통합폼 (`is_direct_order='Y'`)
|
||||
|
||||
> 작성: 2026-05-11
|
||||
> 원본: `wace_plm/WebContent/WEB-INF/view/contractMgmt/estimateAndOrderRegistFormPopup.jsp` + `ContractMgmtService.saveEstimateAndOrderInfo` (라인 2664~)
|
||||
> 대상: `app/(main)/COMPANY_16/sales/order/page.tsx` "수주입력" 다이얼로그 + `POST /api/sales/order-mgmt`
|
||||
|
||||
## 1. wace 패턴
|
||||
|
||||
견적 없이 주문을 바로 등록하는 통합폼. 핵심 차이:
|
||||
- `contract_mgmt.is_direct_order = 'Y'` 강제 (견적관리 그리드 노출 X — 견적관리 SQL이 `IS_DIRECT_ORDER != 'Y'` 필터)
|
||||
- 주문관리 그리드엔 노출
|
||||
- 헤더에 발주일(`order_date`) / 발주번호(`po_no`) 추가
|
||||
- 라인에 `ORDER_*` 컬럼 (수주수량/단가/공급가액/부가세/총액) 입력
|
||||
- 라인의 `quantity = order_quantity` 미러링 (wace 통합폼은 견적수량 별도 입력 X)
|
||||
|
||||
## 2. 운영 데이터 검증
|
||||
|
||||
```
|
||||
contract_mgmt 90건 중 is_direct_order='Y' = 74건 (82%)
|
||||
```
|
||||
|
||||
→ 운영 주문은 절대다수가 직접등록 통합폼으로 작성. G2가 주문 신규 등록의 기본 흐름.
|
||||
|
||||
## 3. RPS 변경
|
||||
|
||||
### 백엔드 [salesOrderMgmtService.ts]
|
||||
- `OrderBody` 타입: `order_date` / `approval_required` / `is_direct_order` 추가, `contract_date` 폐지 (운영 컬럼은 `order_date`)
|
||||
- `create()`: INSERT에 `is_direct_order` (default 'Y') / `order_date` / `approval_required` 추가
|
||||
- `update()`: 동일 컬럼 UPDATE
|
||||
- `upsertItems`: 기존 `ORDER_*` 처리 그대로 (이미 G2 호환)
|
||||
|
||||
### 프론트 [order/page.tsx] + [salesOrderMgmt.ts]
|
||||
- `OrderBody`: `order_date`/`approval_required`/`is_direct_order` 보강, `contract_date` 폐지
|
||||
- `openCreate()`: `order_date = today` + `is_direct_order = 'Y'` 기본값
|
||||
- `openEdit()`: `order_date`/`approval_required`/`is_direct_order` detail에서 복원
|
||||
- 폼 다이얼로그: "발주일" 입력을 `order_date` 바인딩 (이전 `contract_date` 잘못 바인딩 정정)
|
||||
|
||||
## 4. 자동 검증 결과 (BEGIN/ROLLBACK)
|
||||
|
||||
| 항목 | 결과 |
|
||||
|---|---|
|
||||
| `is_direct_order='Y'` INSERT | ✅ |
|
||||
| `order_date` 컬럼에 저장 | ✅ (`2026-05-11`) |
|
||||
| `ORDER_*` 라인 컬럼 (qty/unit_price/total_amount) | ✅ |
|
||||
| 견적관리 노출 차단 (필터 `is_direct_order != 'Y'`) | ✅ (0 rows) |
|
||||
| 주문관리 노출 | ✅ (1 row) |
|
||||
|
||||
## 5. 결론
|
||||
|
||||
기존 RPS `create/update`가 거의 G2 호환이라 신규 endpoint 없이 컬럼 보강(is_direct_order/order_date/approval_required)으로 처리. 분리 endpoint 불필요.
|
||||
|
||||
다음 단계: G5 견적작성 PDF 또는 G4 결재 모듈.
|
||||
@@ -192,7 +192,8 @@ export default function SalesOrderPage() {
|
||||
contract_no: contractNo,
|
||||
contract_currency: "KRW",
|
||||
paid_type: "paid",
|
||||
contract_date: new Date().toISOString().slice(0, 10),
|
||||
order_date: new Date().toISOString().slice(0, 10),
|
||||
is_direct_order: "Y",
|
||||
items: [{ ...EMPTY_ITEM }],
|
||||
});
|
||||
setDialogOpen(true);
|
||||
@@ -214,7 +215,9 @@ export default function SalesOrderPage() {
|
||||
contract_currency: detail.contract_currency ?? "KRW",
|
||||
exchange_rate: detail.exchange_rate ?? "",
|
||||
receipt_date: detail.receipt_date ?? "",
|
||||
contract_date: detail.contract_date ?? "",
|
||||
order_date: detail.order_date ?? "",
|
||||
approval_required: detail.approval_required ?? "N",
|
||||
is_direct_order: detail.is_direct_order ?? "Y",
|
||||
req_del_date: detail.req_del_date ?? "",
|
||||
po_no: detail.po_no ?? "",
|
||||
contract_result: detail.contract_result ?? "",
|
||||
@@ -501,8 +504,8 @@ export default function SalesOrderPage() {
|
||||
placeholder="저장 시 자동 부여됩니다" /></div>
|
||||
<div><Label className="text-xs">발주번호</Label>
|
||||
<Input value={form.po_no ?? ""} onChange={(e) => setForm({ ...form, po_no: e.target.value })} /></div>
|
||||
<div><Label className="text-xs">발주일</Label>
|
||||
<Input type="date" value={form.contract_date ?? ""} onChange={(e) => setForm({ ...form, contract_date: e.target.value })} /></div>
|
||||
<div><Label className="text-xs">발주일 <span className="text-rose-600">*</span></Label>
|
||||
<Input type="date" value={form.order_date ?? ""} onChange={(e) => setForm({ ...form, order_date: e.target.value })} /></div>
|
||||
<div><Label className="text-xs">요청납기</Label>
|
||||
<Input type="date" value={form.req_del_date ?? ""} onChange={(e) => setForm({ ...form, req_del_date: e.target.value })} /></div>
|
||||
<div><Label className="text-xs">고객사</Label>
|
||||
|
||||
@@ -88,10 +88,12 @@ export interface OrderBody {
|
||||
contract_currency?: string;
|
||||
exchange_rate?: string;
|
||||
receipt_date?: string;
|
||||
contract_date?: string;
|
||||
order_date?: string; // 발주일 (wace G2 필수)
|
||||
req_del_date?: string;
|
||||
po_no?: string;
|
||||
contract_result?: string;
|
||||
approval_required?: string; // 결재여부 'Y'|'N'
|
||||
is_direct_order?: string; // 'Y' 기본 (G2 직접등록)
|
||||
pm_user_id?: string;
|
||||
customer_request?: string;
|
||||
shipping_method?: string;
|
||||
|
||||
Reference in New Issue
Block a user