Files
wace_rps/docs/migration/sales/00-gap.md
T
hjjeong b17d7b063d PR-D G11 견적 결재상신 — Amaranth 직행 (wace estimateList_new.jsp btnApproval 1:1)
G11 수주 결재상신(905d5c09)과 동일 패턴을 견적관리에 확장. target_type='CONTRACT_ESTIMATE',
target_objid=estimate_template.objid(최신 차수), formId='1162' (수주 1161과 별도 양식).

- 백엔드: salesEstimateService.startEstimateApproval + POST /sales/estimate/:id/amaranth-approval
- 견적 list SQL: LEFT JOIN amaranth_approval(CONTRACT_ESTIMATE) + APPR_STATUS 4단계 한글 라벨 + approval_required='N' fallback (wace contractMgmt.xml:513~522 1:1)
- 프론트: 견적관리 placeholder 토스트 → handleAmaranthApproval 핸들러 + sky-600 Send 버튼 (수주 페이지와 통일)
- docker-compose 3개: AMARANTH_OUT_PROCESS_CODE_CONTRACT_ESTIMATE + AMARANTH_FORM_ID_CONTRACT_ESTIMATE=1162 추가
- 가드: 행 미선택 / est_objid 없음(견적서 미작성) / inProcess+complete / notRequired+approval_required='N'
- 사전판정(checkApprovalRequired)은 G4 영역으로 분리 — 이번 PR은 단순 SSO 흐름만

검증: BEGIN/ROLLBACK으로 26C-0712(est_objid=-452406811) 4단계 상태(create→inProcess→complete→reject)
+ amaranth row 삭제 시 approval_required='N' fallback 모두 한글 라벨 정상. 문서 08-estimate-approval-verify.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 18:16:43 +09:00

13 KiB
Raw Blame History

영업관리 이식 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 (라인 29873113) + project.xml (75187581) salesOrderMgmtService.ts:521 updateStatusCONTRACT_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 신설 (사전판정 룰만 — SSO 흐름은 G11에서 처리됨)
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 수주복사 (헤더 + contract_item + 시리얼 통째로 복제, 새 영업번호 채번) ContractMgmtService.copyEstimateAndOrderInfo (라인 2601) + 매퍼 copyContractMgmt/copyContractItems/copyContractItemSerials/getNextContractNo 완료 (2026-05-11)salesOrderMgmtService.copyOrder + POST /sales/order-mgmt/:id/copy + 주문관리 그리드 "수주복사" 버튼. 검증: 06-copy-order-verify.md
G10 환율 마스터 + EXCHANGE_RATE 자동 변환 (영업관리 GAP 아님 — Admin 도메인) wace 영업관리 화면도 exchange_rate는 사용자 직접 입력. COMM_EXCHANGE_RATE 테이블·환율관리 화면은 wace AdminController(4898~4993) + admin.xml(8191~8336) 소속 영업관리 GAP에서 제외. Admin 메뉴 이식 시점에 별도로 다룸
G11 수주 결재상신 (Amaranth 직행) wace ApprovalService.getAmaranthSsoUrl (라인 17821909) + orderMgmtList.btnApproval (132175) chpark의 amaranthApprovalClient(HMAC-SHA256 + AES-128-CBC) 기반. amaranth_approval 테이블만 사용, 자체 approval 미경유 (wace 패턴 동일). target_type=CONTRACT_ORDER, formId=1161, compSeq=1000 완료 (2026-05-11)salesOrderMgmtService.startOrderApproval + POST /sales/order-mgmt/:id/amaranth-approval + 주문관리 "결재상신" 버튼 + 결재상태 컬럼(작성중/결재중/결재완료/반려). DB ALTER: amaranth_approval.target_objid → VARCHAR. 검증: 07-amaranth-approval-verify.md. 백로그: 첨부파일 원챔버 업로드
G11E 견적 결재상신 (Amaranth 직행, G11 동일 패턴) wace estimateList_new.jsp:154~270, 868~916 + ApprovalService.getAmaranthSsoUrl CONTRACT_ESTIMATE 분기 G11과 동일 흐름. 차이점: target_type=CONTRACT_ESTIMATE, target_objid=estimate_template.objid(최신 차수), formId=1162. 사전판정(checkApprovalRequired)은 G4 영역으로 분리 완료 (2026-05-11)salesEstimateService.startEstimateApproval + POST /sales/estimate/:id/amaranth-approval + 견적관리 "결재상신" 버튼 + 견적 list SQL LEFT JOIN amaranth_approval + 결재상태 4단계 라벨 + notRequired/approval_required='N' fallback. 검증: 08-estimate-approval-verify.md. 백로그: 첨부파일 원챔버 업로드, 사전판정(G4)

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)