Files
hjjeong 12ea68616d 견적관리 그리드 V1 컬럼 보강(제품구분·국내해외·반납사유) + wace 1:1 검증 문서·자동 검증 SQL
- getList SQL: 라인 집계에 product_summary(=PRODUCT_NAME, contract_item.product distinct join) / return_reason_summary 추가. wace는 헤더 product 폐지·라인으로 이동(운영 90건 contract_mgmt.product NULL) → 라인 집계로 그리드 표시
- GRID_COLUMNS 3개 추가: 제품구분 / 국내해외 / 반납사유
- searchForm.search_partName 필드 추가(초기화 포함). 검색 폼 UI는 PartSelect mode=partName 이미 존재
- docs/migration/sales/01-estimate-verify.md: wace ↔ RPS 항목 매핑 / 운영 데이터 코드 체계 / 갭 우선순위
- scripts/verify-estimate.sql: BEGIN/ROLLBACK 5개 시나리오 (등록·수정·G1·수주취소·그리드) 자동 검증

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

10 KiB

01. 견적관리 wace 1:1 검증

작성: 2026-05-09 / 사이클: 구조적 검증 1차 (견적관리 메뉴) 목적: wace 운영 화면과 RPS 견적관리를 항목/식별자/채번 단위로 1:1 매칭 + 갭 도출 + 자동 검증 시나리오

1. 항목 매핑

1.1 등록/수정 폼 — 헤더 8개 (estimateRegistFormPopup.jsp 1행/2행)

# wace 라벨 wace name RPS 폼 코드 그룹 필수 운영 데이터
1 주문유형 category_cd EstimateBody.category_cd 0000167 0001792(판매)·0001791(수리)·0900221(자체개발)
2 국내/해외 area_cd EstimateBody.area_cd 0001219 0001220(국내)·0001221(해외)
3 고객사 customer_objid EstimateBody.customer_objid C_{customer_code} 90건 일치
4 유/무상 paid_type EstimateBody.paid_type (raw paid/free) paid 85·free 4·NULL 1
5 접수일 receipt_date EstimateBody.receipt_date (date varchar) YYYY-MM-DD
6 견적환종 contract_currency EstimateBody.contract_currency 0001533 0001566(원)·0001534(달러)·0001537(엔)
7 견적환율 exchange_rate EstimateBody.exchange_rate (raw text)
8 결재여부 approval_required EstimateBody.approval_required (Y/N 체크박스) 90건 N (결재모듈 미도입)

1.2 등록/수정 폼 — 라인 8개 + 삭제

# wace 라벨 wace name RPS 라인 컬럼/그룹 필수
1 No (자동) (auto seq) seq integer
2 제품구분 item_product[] EstimateItem.product comm_code 0000001
3 품번 item_part_no_select[] EstimateItem.part_objid+part_no PartSelect
4 품명 item_part_name_select[] EstimateItem.part_name PartSelect
5 S/N item_serial_no[] EstimateItem.serials[] S/N 다이얼로그
6 견적수량 item_quantity[] EstimateItem.quantity integer
7 요청납기 item_due_date[] EstimateItem.due_date date varchar
8 반납사유 item_return_reason[] EstimateItem.return_reason comm_code 0001810
9 고객요청사항 item_customer_request[] EstimateItem.customer_request text

1.3 그리드 컬럼 — wace 활성 22개

# wace title wace field RPS GRID_COLUMNS 상태
1 영업번호 CONTRACT_NO contract_no (frozen)
2 주문유형 CATEGORY_NAME category_name
3 접수일 RECEIPT_DATE receipt_date
4 요청납기 EARLIEST_DUE_DATE earliest_due_date_label
5 고객사 CUSTOMER_NAME customer_name
6 품명 ITEM_SUMMARY item_summary
7 견적수량 ESTIMATE_QUANTITY estimate_quantity
8 유/무상 PAID_TYPE paid_type_name
9 공급가액 EST_TOTAL_AMOUNT est_total_amount
10 원화환산공급가액 EST_TOTAL_AMOUNT_KRW est_total_amount_krw
11 견적현황 EST_STATUS est_status (folder)
12 추가견적 ADD_EST_CNT add_est_cnt (clip)
13 결재상태 APPR_STATUS appr_status
14 메일발송 MAIL_SEND_STATUS mail_send_status_label
15 환종 CONTRACT_CURRENCY_NAME contract_currency_name
16 환율 EXCHANGE_RATE exchange_rate
17 S/N SERIAL_NO serial_no
18 품번 PART_NO part_no
19 작성자 WRITER_NAME writer_name
20 제품구분 PRODUCT_NAME (없음) 🔴
21 국내/해외 AREA_NAME (없음) 🔴
22 반납사유 RETURN_REASON_SUMMARY (없음) 🔴 갭 (집계 컬럼 신설 필요)

1.4 검색 폼 — wace 활성 7개

# wace 라벨 wace name RPS searchForm 상태
1 주문유형 category_cd category_cd
2 고객사 customer_objid customer_objid
3 품번 search_partNo search_partObjId 🟡 (PartSelect로 part_objid 단일 검색)
4 품명 search_partName (없음) 🔴
5 S/N search_serialNo search_serialNo
6 결재상태 appr_status appr_status
7 접수일 receipt_start_date~end_date receipt_start_date/end_date

1.5 액션 버튼

버튼 wace endpoint RPS 동작 상태
조회 /contractMgmt/estimateGridList.do GET /sales/estimate/list
삭제 /contractMgmt/deleteEstimateMgmtInfo.do DELETE /sales/estimate/:id
견적요청등록/수정 /contractMgmt/saveContractMgmtInfo.do POST/PUT /sales/estimate (선택 시 수정 분기)
견적작성 `/contractMgmt/saveEstimate.do saveEstimate2.do` (template1/2) placeholder
결재상신 /contractMgmt/checkApprovalRequired.do → 아마란스 SSO placeholder 🟠 G4 별도 PR
메일발송 /contractMgmt/sendEstimateMail.do POST /sales/estimate/mail (mail_log INSERT만) 🟡 SMTP 미구현(G6)

2. 운영 데이터 코드 체계 (90건 검증 완료)

2.1 식별자

항목 형식 검증
contract_mgmt.objid varchar (raw integer hash 또는 'CM-...') wace 운영은 raw integer (문자열로 보관)
contract_mgmt.contract_no {YY}C-{NNNN} 90/90건 일치 (regex ^[0-9]{2}C-[0-9]{4}$)
contract_mgmt.customer_objid C_{customer_code} (10자리 padded) 90/90건 customer_mng.customer_code로 매칭
contract_item.objid varchar (raw integer 또는 'CI-...')

2.2 comm_code 그룹 ID

용도 parent_code_id 자식 예시
주문유형 (category_cd) 0000167 0001791(수리)/0001792(판매)/0900221(자체개발)/0000170(오버홀)/0000171(개조)/0000168(신규개발)/0001790(견적)/0900214(계획생산)
국내/해외 (area_cd) 0001219 0001220(국내)/0001221(해외)
제품구분 (product) 0000001 0000928(Machine)/0000930(A/S)/0001525(D/S)/0001539(B/S)/0001793(C/T)/0001794(A/C)/0001807(W/M)/0001809(기타)
환종 (contract_currency) 0001533 0001534(달러$)/0001535(유로€)/0001536(위안¥)/0001537(엔¥)/0001566(원₩)
수주상태 (contract_result) 0000963 0000964(수주)/0000965(Cancel)/0000966(Hold)/0000968(수주FCST)
반납사유 (return_reason) 0001810 0001811(수리불가)

2.3 채번 룰

항목 적용 위치
contract_no {YY}C-{NNNN} (4자리 zero-pad, 같은 prefix MAX+1) salesOrderMgmtService.generateContractNo
project_no {주문유형1}-{제품구분2}-{YYMMDD}-{NNN} (예: R-CT-260507-001) salesOrderMgmtService.generateProjectNo

3. 발견된 갭 (우선순위)

# 우선 항목 권장 작업
V1 🔴 그리드 컬럼 3개 누락 (제품구분/국내해외/반납사유) RPS GRID_COLUMNS 추가 + getList SQL에 PRODUCT_NAME/AREA_NAME/RETURN_REASON_SUMMARY 컬럼 추가. RETURN_REASON_SUMMARY는 contract_item 집계로 LATERAL JOIN
V2 🟠 품명 검색 누락 (search_partName) searchForm에 search_partName 추가 + 백엔드 SQL where 조건 추가
V3 🟡 paid_type NULL 1건 (운영 데이터 이슈) 폼에서 신규 시 paid default 강제 — 이미 적용. 기존 NULL 데이터 정리는 별도
V4 🟢 결재모듈 (G4) — 모든 운영 데이터 approval_required='N' G4 별도 PR
V5 🟢 견적작성 PDF (G5) G5 별도 PR
V6 🟢 SMTP 실발송 (G6) G6 별도 PR

4. 자동 검증 시나리오 (BEGIN/ROLLBACK)

각 시나리오는 dev DB에서 트랜잭션 안에서 실제 SQL 실행 + 결과 검증 후 ROLLBACK. 영향 0.

시나리오 1: 신규 견적요청 등록

BEFORE: contract_mgmt 90 / contract_item N0 / contract_item_serial S0
- INSERT contract_mgmt 1건 (contract_no=26C-0802, customer_objid='C_0000005546', ...)
- INSERT contract_item 1건 (product=0001793, part_objid=1868255719, quantity=2)
- INSERT contract_item_serial 0건 (S/N 미입력)
AFTER: contract_mgmt 91 / contract_item N0+1 / serial S0
ROLLBACK → 모두 원복

시나리오 2: 견적요청 수정 (라인 1→2 확장)

BEFORE: 26C-0801 contract_item 1건
- upsertItems: 기존 라인 status='INACTIVE'
- INSERT 새 라인 2건 (objid 새로 발급, ON CONFLICT 미발동)
AFTER: contract_item ACTIVE 2건, INACTIVE 1건 (= 누적 3건)
ROLLBACK

시나리오 3: 견적요청 삭제

BEFORE: 26C-XXXX contract_item N건, contract_item_serial M건
- UPDATE contract_item_serial SET status='INACTIVE' WHERE item_objid IN (...)
- DELETE contract_item WHERE contract_objid=$
- DELETE contract_mgmt WHERE objid=$
AFTER: 모두 사라짐
ROLLBACK

시나리오 4: 수주확정 → 프로젝트 자동생성 (G1)

BEFORE: project_mgmt 89 / contract_mgmt.contract_result NULL
- UPDATE contract_mgmt SET contract_result='0000964'
- 트리거: createProjectsFromContract
  - hasProject=false
  - contract_item N개 루프 → Machine 분기 → project_no 채번 → INSERT
AFTER: project_mgmt 89+N 또는 89+sum(Machine_qty)+non_machine_count
ROLLBACK

(검증 완료: 26C-0801 1라인 C/T qty=2 → project_no=R-CT-260508-001 1건 INSERT)

시나리오 5: 수주취소 (cancel_qty 입력)

BEFORE: contract_item.cancel_qty NULL
- UPDATE contract_item SET cancel_qty='1', chgdate=NOW(), chg_user_id=$
- contract_mgmt.contract_result 미변경
검증: cancel_qty < order_qty (전체 취소 불가)
ROLLBACK

5. 다음 단계

  1. 갭 V1·V2 수정 (그리드 3컬럼 + 품명 검색) → 사용자 확인 후 커밋
  2. 자동 검증 SQL 스크립트 정리 (scripts/verify-estimate.sql — BEGIN/ROLLBACK 트랜잭션 모음)
  3. 사용자 dev 환경 최종 확인 → 견적관리 메뉴 종결 → 주문관리 진행