Files
wace_rps/docs/migration/sales
hjjeong 75f4ca8127 영업관리 구매요청 2메뉴 액션 완성 + SmartSelect 키보드 네비
- sales_request_part DDL 추출(운영 11133)→RPS(11134) 마이그레이션
- 백엔드 6 엔드포인트: 프로젝트 자동채움/M-BOM 품목/저장/품의서생성/SSO
  · 품의서 결재상신 Amaranth SSO (target_type=PROPOSAL, formId=1163)
- 프론트 다이얼로그 2개 (구매요청서작성 / 품의서생성 확인)
  · 프로젝트 선택→주문유형·제품구분·국내외·고객사·유무상 자동 채움
  · 행추가 시 M-BOM 품번 셀렉트→품명/공급업체/단가 자동 셋팅
- 공용 SmartSelect: ↑↓·Enter·Esc·Home·End·PageUp·Down 키보드 네비
- 그리드 delivery_request_date . → - 형식 정규화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:01:26 +09:00
..

영업관리 이식 (wace_plm → vexplor_rps)

작성: 2026-05-07 / 작성자: hjjeong 대상: vexplor_rps (RPS 전용 분기, COMPANY_16 단독 운영) 원본: wace_plm (Java 7 / Spring 3.2.4 / JSP / MyBatis)

0. 정책 (사용자 확정 사항)

  • 이식 방식: JSP → Next.js 리라이트 (백엔드도 Java→Node 재작성, vexplor_rps backend-node 패턴 채택)
  • 스키마 정책: 하이브리드 — 도메인 테이블(contract_mgmt, estimate_mgmt, sales_registration 등)은 wace_plm 원본 스키마를 그대로 가져오고, 거래처/품목 등 마스터는 vexplor_rps 기존 테이블(customer_mng, item_info)에 매핑
  • 관리자 메뉴: 이식 대상 아님 (vexplor 그대로 사용)
  • 이식 대상 메뉴 6개 (초기 4개 + 2026-05-15 확장 2개):
    1. 견적관리 (/contractMgmt/estimateList_new.do)
    2. 주문서관리 (/contractMgmt/orderMgmtList.do)
    3. 판매관리 (/contractMgmt/salesMgmtList.do → SalesNcollect로 위임)
    4. 매출관리 (/revenueMgmt/revenueList.do)
    5. 구매요청서관리 (/salesMng/purchaseRequestRegList.do) — 2026-05-15 추가
    6. 품의서관리(영업) (/salesMng/purchaseRegProposalMngList.do) — 2026-05-15 추가

1. 메뉴 매핑표

# 메뉴명 wace_plm URL wace_plm JSP wace_plm Controller / Service vexplor_rps 신규 위치 (제안) 상세 문서
1 견적관리 /contractMgmt/estimateList_new.do contractMgmt/estimateList_new.jsp (47KB) ContractMgmtController (16292510 line) / ContractMgmtService app/(main)/COMPANY_16/sales/estimate/page.tsx + backend-node/src/{routes,services}/estimateRoutes.ts 01-estimate.md
2 주문서관리 /contractMgmt/orderMgmtList.do contractMgmt/orderMgmtList.jsp (45KB) ContractMgmtController (25043169 line) / ContractMgmtService app/(main)/COMPANY_16/sales/order/page.tsx (재작성) + backend-node/src/{routes,services}/orderMgmtRoutes.ts 02-order.md
3 판매관리 /contractMgmt/salesMgmtList.do (위임) → /salesNcollectMgmt/sales.do salesmgmt/salesMgmt/*.jsp SalesNcollectMgmtController (line 763~) / SalesNcollectMgmtService app/(main)/COMPANY_16/sales/sale/page.tsx + backend-node/src/{routes,services}/saleRoutes.ts 03-sale.md
4 매출관리 /revenueMgmt/revenueList.do salesmgmt/salesMgmt/revenueMgmtList.jsp SalesNcollectMgmtController (line 103, 214) / SalesNcollectMgmtService app/(main)/COMPANY_16/sales/revenue/page.tsx + backend-node/src/{routes,services}/revenueRoutes.ts 04-revenue.md
5 구매요청서관리 /salesMng/purchaseRequestRegList.do salesMng/purchaseRequestRegList.jsp (728줄) SalesMngController (210~258) / salesMng.getSalesRequestMasterGridList (DOC_TYPE_FILTER='PURCHASE_REG') app/(main)/COMPANY_16/purchase-request/request/page.tsx + backend-node/src/{routes,services}/salesPurchaseRequestRoutes.ts 09-purchase-request.md
6 품의서관리 (영업) /salesMng/purchaseRegProposalMngList.do salesMng/purchaseRegProposalMngList.jsp (313줄) SalesMngController (1363~1389) / salesMng.getPurchaseRegProposalMngGridList app/(main)/COMPANY_16/purchase-request/proposal/page.tsx + backend-node/src/{routes,services}/salesPurchaseRequestRoutes.ts 09-purchase-request.md
마스터 매핑 (전 메뉴 공통) 05-master-mapping.md

⚠️ vexplor_rps의 기존 sales/quote/sales/order 페이지는 별도 도메인(quote_mng/quote_detail)으로 만들어져 있음. 이식 후 사용 중지 또는 별도 모듈로 이름 변경 검토 필요. 신규 페이지는 estimate/, order/ 신규 경로로 작성하는 것을 권장.

2. 도메인 테이블 (wace_plm → vexplor_rps 그대로 이식)

이식 대상 테이블. 새 vexplor_rps DB에 CREATE TABLE 그대로 적용 (컬럼명/타입 유지).

우선순위 테이블 용도 dbexport.pgsql line
★★★ contract_mgmt 계약/주문서 헤더 2488
★★★ contract_item 계약/주문서 상세 라인 (DDL: database/contract_item_tables.sql)
★★★ estimate_mgmt 견적 헤더 (구버전) 4340
★★★ estimate_template 견적 템플릿 = 새 견적의 헤더(estimateList_new가 사용) (CREATE 미발견, 운영 DB 추출 필요)
★★★ estimate_template_item 견적 템플릿 라인 = 새 견적의 상세 (CREATE 미발견, 운영 DB 추출 필요)
★★ counselingmgmt 상담관리 — 이식 대상 아님 (사용자 확정) 2989
★★ contract_mgmt_option 주문 옵션 2899
★★ contract_item_serial 주문 라인 시리얼 (DDL: database/contract_item_tables.sql)
★★ sales_registration 판매 등록 (= 판매·매출 집계 원장) (dbexport에서 위치 확인 필요)
attach_file_info 첨부파일 (PDF/이미지) 1387
approval 결재 507
mail_log 메일 발송 로그 (견적 메일링) (필요 시)
pms_pjt_year_goal 연도 목표 (대시보드용) (필요 시)

운영 DB DDL 추출 완료 (2026-05-07)

운영 DB(211.115.91.141:11133/waceplm PG 16.8)에서 누락된 5개 테이블을 추출하여 ddl-extracted/에 정리. 주요 발견:

  • estimate_template / estimate_template_item 발견 → 100_create_estimate_template.sql
  • sales_registration / shipment_log 발견 → 101_create_sales_registration.sql
  • mail_log 발견 → 102_create_mail_log.sql
  • final_data, end_count, transaction_statement_*, tax_invoice_*존재하지 않음
  • 매출관리의 마감/세금계산서/수출신고 컬럼은 모두 shipment_log에 통합되어 있음
  • 운영 데이터 카운트: 견적 5건, 견적라인 7건, 판매 10건, 분할출하 0건, 메일로그 7,805건 → 도메인은 사실상 신규 시스템, 데이터 이주 부담 거의 없음

자세한 내용은 ddl-extracted/README.md.

3. 마스터 매핑 (wace_plm 마스터 → vexplor_rps 마스터로 변환)

wace_plm 테이블 wace_plm 키 컬럼 vexplor_rps 테이블 vexplor_rps 키 변환 규칙
SUPPLY_MNG (공급/고객사 통합) objid (numeric) customer_mng id (integer) 양방향 매핑 테이블 필요 (legacy_supply_objid → customer_mng.id)
CLIENT_MNG (일반 거래처) objid (numeric) customer_mng id 위와 동일 (wace_plm은 customer_objid'C_' 접두사로 두 테이블 구분)
USER_INFO user_id user_info user_id 동일 키 사용 가능 (있다면 그대로)
DEPT_INFO dept_code (vexplor_rps department) (확인 필요) TBD
PART_MGMT / PRODUCT_MGMT objid item_info id 매핑 테이블 필요
ATTACH_FILE_INFO target_objid + doc_type (vexplor_rps 파일 시스템) (확인 필요) TBD

마스터 마이그레이션 절차 (제안)

  1. wace_plm SUPPLY_MNG + CLIENT_MNGcustomer_mng로 INSERT (legacy_objid 컬럼 추가)
  2. wace_plm PART_MGMT (+ PRODUCT_MGMT?) → item_info로 INSERT (legacy_part_objid 컬럼 추가)
  3. 도메인 테이블(contract_mgmt, estimate_mgmt 등) 이식 시 외래 컬럼은 wace_plm objid를 그대로 가져오고, 별도 매핑 테이블(legacy_id_map)을 통해 vexplor_rps 마스터 id로 변환

4. 백엔드 패턴 (vexplor_rps backend-node)

라우트 (예: quoteRoutes.ts 패턴)

import { Router } from "express";
import { authenticateToken } from "../middleware/authMiddleware";
import * as ctrl from "../controllers/<feature>Controller";

const router = Router();
router.use(authenticateToken);

router.get("/list", ctrl.getList);
router.get("/generate-number", ctrl.generateNumber);
router.get("/:id", ctrl.getById);
router.post("/", ctrl.create);
router.put("/:id", ctrl.update);
router.delete("/:id", ctrl.remove);

export default router;

서비스 (예: quoteService.ts 패턴)

  • getPool() (PG raw)
  • companyCode 멀티테넌시: WHERE company_code = $1 (RPS는 COMPANY_16 고정)
  • 소프트삭제: use_yn = 'Y'
  • 트랜잭션: pool.connect()BEGIN/COMMIT/ROLLBACK
  • 자동 채번: generateNumber() (예: EST-YYYYMMDD-001)

컨트롤러

  • 인증: req.user.companyCode, req.user.userId 사용
  • 응답: res.json({ data, totalCount }) 또는 res.json({ success, message })

5. 프론트엔드 패턴 (vexplor_rps Next.js)

"use client";
import { DataGrid, DataGridColumn } from "@/components/common/DataGrid";
import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter";
import { apiClient } from "@/lib/api/client";
import { useAuth } from "@/hooks/useAuth";
// ... shadcn/ui Button, Dialog, Select, Input, Label ...
  • 검색 필터: DynamicSearchFilter (테이블 카테고리/공통코드 자동 바인딩)
  • 그리드: DataGrid (선택, 정렬, 포맷팅)
  • 채번 / 단일 조회 / 저장 / 삭제: apiClient.get/post/put/delete
  • 권한: useCurrent2ndLevelMenuObjid + 관리자에서 권한 매핑

6. 진행 체크리스트 (메뉴별)

각 메뉴 1개 이식 = 다음 9단계.

  • (a) 운영 DB에서 해당 테이블 schema-only dump 추출
  • (b) db/migrations/NNN_create_<feature>_tables.sql 작성
  • (c) wace_plm Controller endpoint 목록 추출 → backend-node/src/routes/<feature>Routes.ts 매핑표 작성
  • (d) backend-node/src/services/<feature>Service.ts 작성 (raw SQL)
  • (e) backend-node/src/controllers/<feature>Controller.ts 작성
  • (f) backend-node/src/server.ts 또는 라우트 등록 위치에 마운트
  • (g) frontend/app/(main)/COMPANY_16/sales/<feature>/page.tsx 작성 (DataGrid + Filter + Modal)
  • (h) 메뉴 트리에 등록 (vexplor_rps 메뉴 관리 화면 또는 메뉴 시드)
  • (i) 권한 매핑 + 수동 테스트

7. 다음 작업

  1. 운영 DB DDL 추출 완료 (2026-05-07)
  2. 01~04 상세 매핑 + 1차 이식 완료 (2026-05-08)
  3. 00-gap.md PR-A/B/C 흐름 + G7~G11 결재상신 완료 (2026-05-11)
  4. 구매요청서관리·품의서관리(영업) 1차 스캐폴드 완료 (2026-05-15, 커밋 7e7c6a0a, 09-purchase-request.md)
  5. 다음: 구매요청서작성 다이얼로그 + 품의서생성 액션 + 영업>품의서 Amaranth 결재상신(target_type='PROPOSAL', formId='1163'). sales_request_part 운영DB DDL 추출 선행.

8. 공통 UX 규칙 (검색 폼 / 영업관리 4개 메뉴 동일 적용)

8.1 버튼 영역

상단 우측 버튼 영역에 다음 순서로 배치 — 모든 메뉴 공통:

  1. 조회 (variant="outline" + <Search> 아이콘)
  2. 메뉴 고유 액션 버튼들 (등록/수정/삭제/확정 등)
  3. 초기화 (variant="ghost") — searchForm state를 모든 키 빈 값으로 reset
<Button size="sm" variant="ghost"
        onClick={() => setSearchForm({ /* 모든 키 "" */ })}>
  초기화
</Button>

8.2 date input

  • <Input type="date"> 사용 시 별도 처리 불필요. 다음은 Input 컴포넌트 + globals.css에 자동 반영:
    • 빈 값일 때 'YYYY/MM/DD' 자리표시 텍스트 숨김 (data-empty="true" 자동)
    • 캘린더 아이콘 숨김 (::-webkit-calendar-picker-indicator { display: none })
    • input 영역 어디 클릭해도 picker 자동 표시 (showPicker())
  • 위 동작은 frontend/components/ui/input.tsx + frontend/app/globals.css에서 일괄 처리.

8.3 검색 폼 그리드

  • grid grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-x-2 gap-y-1.5 p-2 border rounded-md bg-muted/30
  • 라벨: text-[11px] mb-0.5 block text-muted-foreground
  • 입력: h-8 text-xs (date는 px-1 flex-1 min-w-0 추가)

8.4 wace JSP 주석 함정

검색 폼 추출 시 JSP 끝부분 <!-- 주석처리된 검색필터 - 필요시 활성화 --> 블록은 이식 대상 아님. 활성/비활성 분리 표로 문서화. 자세한 내용은 메모리 feedback_wace_jsp_columns.