00-gap.md: wace_plm 원본 흐름 vs vexplor_rps 이식본 GAP 매트릭스. 다음 PR 우선순위(A: 수주확정→프로젝트 자동생성, B: 직접등록 통합폼, C: 결재·메일·PDF) 합의 문서. README.md: §7 다음 작업 항목을 완료 처리하고 00-gap.md 우선 합의로 재정렬. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 KiB
영업관리 이식 GAP 분석 (원본 wace_plm 대비)
작성: 2026-05-08 / 작성자: hjjeong 목적: vexplor_rps에 이식된 영업관리 4개 메뉴가 wace_plm 원본 흐름과 어디서 어긋나는지 정리하고, 다음 PR 우선순위를 합의하기 위한 단일 문서. 참고: 01-estimate.md, 02-order.md, feedback_wace_jsp_columns
0. 한 문장 요약
견적/주문 list와 SQL은 잘 이식됐지만 상태 전이 트리거(수주확정 → 프로젝트 자동생성)와 직접등록 통합폼, 결재 자동판정, PDF·SMTP 실작업이 통째로 빠져 있어, 사용자가 영업 흐름을 끝까지 돌릴 수 없는 상태.
0.1 이식 원칙 (모든 GAP 작업 공통)
JSP/Java/매퍼XML 안의 주석 블록(
/* */,<!-- -->,//)은 비활성 옛 로직 보존 영역이다 — 절대 이식 대상이 아니다. 활성 코드만, 한 줄 한 줄 직접 따라가서 그대로 이식한다.
- 운영 화면이 진실의 기준: waceplm.esgrin.com 운영 화면에 실제 보이는 항목/동작이 활성. 코드만 보면 활성/비활성 구분이 흐려짐.
- 컬럼 정의(
var columns = [...]):/* 주석처리된 컬럼 - 필요시 활성화 */블록 이하는 무시. - 검색 폼(
#plmSearchZon):<!-- 주석처리된 검색필터 - 필요시 활성화 -->블록 이하는 무시. - 서비스 메서드: 주석된 옛 SQL/분기 무시. 호출 그래프(controller → service → mapper)를 한 줄씩 따라가서 활성 경로만 추출.
- 매퍼 XML:
<!-- ... -->블록 안의 SQL fragment는 무시.<select id="...">/<insert id="...">단위로 호출되는 것만 사용. - 자세한 함정 사례: 메모리 feedback_wace_jsp_columns (2026-05-08 영업관리 4개 메뉴 검색폼 사고 기록).
1. 원본 견적·주문 흐름 (10단계)
| # | 단계 | wace_plm endpoint | 핵심 테이블 변경 |
|---|---|---|---|
| 1 | 견적 list 조회 | POST /contractMgmt/estimateGridList.do |
contract_mgmt(read, IS_DIRECT_ORDER!='Y' 필터) |
| 2 | 견적요청 등록 | POST /contractMgmt/saveContractMgmtInfo.do |
contract_mgmt + contract_item(N) + contract_item_serial(N) INSERT |
| 3 | 직접등록 통합폼 (견적 없이 주문) | POST /contractMgmt/saveEstimateAndOrderInfo.do |
위와 동일 + IS_DIRECT_ORDER='Y' 강제 세팅 |
| 4 | 견적요청 → 견적작성 | (식별자 contract_objid로 묶임. 명시적 컬럼 복사 없음) |
(없음) |
| 5 | 견적 작성 (일반/장비) | `POST /contractMgmt/saveEstimate.do | saveEstimate2.do` |
| 6 | 결재 사전판정 | POST /contractMgmt/checkApprovalRequired.do |
(read only — 신규수주/가격인하 로직) |
| 6a | 결재불필요 자동처리 | POST /contractMgmt/setApprovalNotRequired.do |
contract_mgmt.APPROVAL_REQUIRED='N' UPDATE |
| 6b | 아마란스 결재상신 | POST /approval/getAmaranthSsoUrl.do |
amaranth_approval INSERT (외부 SSO) |
| 7 | 메일 발송 | POST /contractMgmt/sendEstimateMail.do |
mail_log INSERT + 실제 SMTP MailUtil.sendMailWithAttachFileUTF8 |
| 8 | 주문서 list 조회 | POST /contractMgmt/contractGridList.do |
contract_mgmt(read, 모든 행) — 견적 list와 동일 테이블 |
| 9 | 수주확정 (전이) | POST /contractMgmt/updateOrderStatus.do |
contract_mgmt.CONTRACT_RESULT UPDATE만 (새 INSERT 없음) |
| 10 | 프로젝트 자동생성 (9의 부수효과) | (9의 service 내부에서 호출) | project_mgmt INSERT × N (라인별, Machine은 수량만큼) + project_no 채번 |
견적관리·주문서관리·판매관리·매출관리 4개 list는 모두 같은
contract_mgmt행을 단계별 필터로 보여주는 구조. 단계 전이는CONTRACT_RESULT코드 변경으로 일어남.
2. GAP 매트릭스 (우선순위 순)
🔴 = 사용자 흐름 차단 / 🟠 = 핵심 기능 빠짐 / 🟡 = 보완 필요 / 🟢 = 백로그
| # | 우선 | 항목 | 원본 위치 | 이식본 현재 상태 | 권장 작업 |
|---|---|---|---|---|---|
| G1 | 🔴 | 수주확정 시 프로젝트 자동생성 | ContractMgmtService.updateOrderStatus (라인 2987project.xml (7518 |
salesOrderMgmtService.ts:521 updateStatus는 CONTRACT_RESULT UPDATE만 — 프로젝트 생성 호출 없음 |
updateStatus 트랜잭션 내에서: contract_item 루프 → PRODUCT='0000928'(Machine)이면 quantity만큼 N회, 아니면 1회 → project_no 채번 ({주문유형}-{제품구분}-{YYMMDD}-{순번3자리}) → project_mgmt INSERT |
| G2 | 🔴 | 직접등록 통합폼 (estimateAndOrderRegistFormPopup) |
ContractMgmtService.saveEstimateAndOrderInfo (라인 2664) |
endpoint 자체 부재. 주문관리 화면 "신규" 버튼이 견적 없이 주문 등록하는 흐름 미지원 | POST /api/sales/order/direct 신설 — IS_DIRECT_ORDER='Y' 강제, contract_mgmt UPSERT + contract_item UPSERT + contract_item_serial 다중 INSERT |
| G3 | 🟠 | 견적요청등록 시 contract_item 다중 INSERT | ContractMgmtService.saveContractMgmtInfo (라인 544) |
salesEstimateService.ts는 헤더만 INSERT, 라인 입력 누락 | save 트랜잭션에 contract_item 다중 UPSERT + contract_item_serial 처리 추가 |
| G4 | 🟠 | 결재 자동판정 (checkApprovalRequired) |
(별도 컨트롤러, 신규수주/가격인하 룰) | 미구현. APPROVAL_REQUIRED='N' 라벨 표시만 | 룰 분석 후 endpoint 신설. 외부 amaranth SSO는 RPS 결재 모듈 결정 후 |
| G5 | 🟠 | 견적템플릿 일반/장비 분기 + PDF | ContractMgmtService.saveEstimateTemplate/2 (라인 1501/1591) + SmartEditor uploadPdfChunk |
미이식. 추가견적 카운트(시연 시드)만 표시 | template1/template2 popup 라우트 + puppeteer 또는 react-pdf PDF 생성 → attach_file_info doc_type='estimate02' INSERT |
| G6 | 🟠 | SMTP 실제 발송 | ContractMgmtService.sendEstimateMail (라인 1774-1968), MailUtil.sendMailWithAttachFileUTF8 (라인 1925) |
salesEstimateService.ts:618는 mail_log INSERT만 | mailSendSimpleService(nodemailer) 통합 + HTML 본문 생성기(makeEstimateMailContents) 포팅 + 첨부 결합 |
| G7 | 🟡 | 주문서 수정 시 contract_item UPSERT (OBJID 유지) | mapper.upsertContractItemWithOrder (UPSERT 패턴) |
이식본은 단순 UPDATE — 라인 변경 시 OBJID 유지 보장 안 됨 | UPSERT(ON CONFLICT) 패턴 적용 + 삭제된 라인 처리 분기 |
| G8 | 🟡 | 프로젝트 존재 시 견적·주문 삭제 방지 | ContractMgmtService.deleteContractMngInfo (라인 794~808) |
salesOrderMgmtService.ts delete는 사전 체크 없음 | delete 전에 project_mgmt WHERE contract_objid=$1 LIMIT 1 체크 → 있으면 거부 |
| G9 | 🟡 | 견적요청 → 견적작성 라인 자동 복제 UI | (원본은 사용자가 contract_item에서 수동 선택) | 미구현 — 견적 작성 시 매번 라인 재입력 | "이전 라인 복제" 버튼 + contract_item → estimate_template_item 일괄 복사 |
| G10 | 🟢 | 환율 마스터 + EXCHANGE_RATE 자동 변환 | contractBase SQL EST_TOTAL_AMOUNT_KRW 환산식 |
환산식만 있고 환율 마스터 미구축 | 환율 테이블 신설(또는 ECOS API 동기화) |
| G11 | 🟢 | 결재 모듈 (amaranth_approval / 자체) | 외부 amaranth + APPR_STATUS 라벨 | RPS 결재 정책 미정 | vexplor approvalController 매핑 vs amaranth_approval 도입 결정 |
3. 코드/SQL 정합성 메모
3.1 견적·주문은 같은 contract_mgmt 행
원본은 상태 전이형 모델: 같은 contract_mgmt 행이 견적단계(IS_DIRECT_ORDER='N') → 수주(CONTRACT_RESULT='0000964') → FCST(CONTRACT_RESULT='0000968') 로 진행. 새 INSERT는 §3 통합폼과 §10 프로젝트 생성에서만 일어남. 우리 이식본은 이 단계 모델에 맞춰져 있어 list 단의 SQL은 정합성 OK.
3.2 project_no 채번 룰 (G1의 핵심)
형식: {주문유형}-{제품구분}-{YYMMDD}-{순번3자리}
예: R-CT-260507-001
주문유형 매핑 (CATEGORY_CD → 1글자):
오버홀=O, 개조=M, 개발=D, 견적=Q, 수리=R, 판매=S, 기타=T
제품구분 매핑 (PRODUCT → 2글자):
Machine=MC, A/S=AS, D/S=DS, B/S=BS, C/T=CT, A/C=AC, W/M=WM, 기타=원문
순번:
같은 (주문유형 + 제품구분 + 날짜) 조합 내 MAX(순번)+1
없으면 001부터
출처: wace_plm/src/com/pms/projectmgmt/mapper/project.xml:7518-7581.
RPS의 project_mgmt 89건이 모두 이 룰로 채번되어 있으니, 이식 시 새 행도 같은 룰을 따라야 일관성 유지됨.
3.3 Machine 분기
contract_item 1라인의 PRODUCT가 0000928(Machine)이면 수량만큼 N회 project_mgmt INSERT (각 quantity=1). 그 외(A/S·D/S·C/T 등)는 1회 INSERT (수주수량 그대로). 이 분기 누락 시 시리얼 단위 추적이 깨짐.
3.4 첨부 파일 doc_type
| 단계 | doc_type | 그리드 컬럼 |
|---|---|---|
| 견적 PDF | estimate01 (메인 견적서) |
(없음) |
| 추가 견적 | estimate02 |
"추가견적" |
| 주문서 첨부 | ORDER_DOC 또는 FTC_ORDER |
"주문서첨부" (CU01_CNT) |
02-order.md에 주문서 첨부 컬럼이 미정의되어 있음 — 보완 필요.
4. 다음 PR 후보 (3개로 묶기)
PR-A: 수주확정 → 프로젝트 자동생성 (G1)
- 단독 PR. SQL·트랜잭션 위주, UI 변경 거의 없음.
- 작업:
salesOrderMgmtService.updateStatus안에 project 생성 로직 + project_no 채번 helper + Machine 분기. - 검증:
0000964/0000968코드로 상태 변경 시 project_mgmt에 새 행 생기는지, project_no 형식 일치하는지.
PR-B: 직접등록 통합폼 (G2 + G3)
- 주문관리 화면 "신규" 버튼이 통합 다이얼로그 띄움 →
IS_DIRECT_ORDER='Y'+ contract_item 다중 입력. - G3(견적요청등록 라인 입력)도 같은 라인 입력 컴포넌트 재사용 가능 → 묶어서.
PR-C: 결재·메일·PDF (G4 + G5 + G6)
- 분량 큼. RPS 결재 정책 결정(G11) 선행 필요.
- 단계: SMTP(G6) → PDF(G5) → 결재(G4) 순서로 사이즈 작은 것부터.
백로그
- G7~G11은 위 3개 끝난 뒤 평가.
5. 검증 체크리스트 (PR마다)
- 원본 endpoint와 이식 endpoint 매핑표 갱신 (이 문서 §1)
- 영향 받는 테이블의 BEFORE/AFTER row count 기록
- wace 운영 화면(waceplm.esgrin.com)과 동일 시나리오 비교 스크린샷
project_mgmt새 행이 89건 + N 으로 늘어나는지 (G1)IS_DIRECT_ORDER='Y'행 신규 생성 확인 (G2)