Commit Graph

3057 Commits

Author SHA1 Message Date
hjjeong fc959d8872 영업관리 — 주문/판매/매출에 logicstudio 스타일 DataGrid 적용
견적관리(36c1f357)와 동일한 패턴을 나머지 3개 메뉴로 확장:

공통 DataGrid props:
- gridId (sales-order / sales-sale / sales-revenue) 로 컬럼 visibility·순서·너비·차트 영속
- showColumnSettings, paginationStyle="range", pageSizeOptions=[10,15,20,50,100]
- onRefresh = fetchList, onDownload = exportToExcel(GRID_COLUMNS 라벨 매핑)
- showChart

도메인별 summaryStats (하단 통계 행):
- 주문: 수주 건수 / 수주수량·수주취소 합계 / 공급가액·부가세·총액·원화총액 합계
- 판매: 판매 라인 / 수주·판매·잔량 수량 합계 / 판매공급가액·판매원화·잔량원화 합계
- 매출: 매출 이력 / 수량 합계 / 공급가액·부가세·총액·원화총액 합계

컬럼 폭 보정:
- ⋮⋮ 드래그 핸들 추가로 좁아진 4글자 한국어 라벨이 잘리지 않도록 95~135px로 확대
- 시스템 컬럼: 주문관리 writer_name (systemColumnKeys 분리)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:53:07 +09:00
hjjeong 36c1f3579e 공용 DataGrid — logicstudio 스타일 toolbar + footer 통계 + 차트 분석 패널 흡수, 견적관리 적용
DataGrid:
- ⟳ Refresh · ⬇ Download · ⚙️ 컬럼 표시 설정 · 📊 차트 분석 toolbar
- 컬럼 visibility 토글 (데이터/시스템 그룹 분리 + 표시·순서·너비 reset)
- summaryStats 하단 통계 행 (라벨/값/접미사)
- paginationStyle 'range' — "1-N / 총 X건" + 페이지 크기 Select
- 행 높이 컴팩트화 (h-7 + py-0 + leading-none, 아이콘 h-3.5)
- sticky 헤더 불투명 배경(bg-muted)으로 스크롤 시 본문 비침 차단
- ⋮⋮ 드래그 핸들 항상 표시

DataGridChartPanel (신규):
- 여러 차트 추가/삭제, 제목 인라인 편집, 드래그 순서 변경
- Bar/Line/Pie + X/Y축 선택 + count/sum/avg/min/max 집계
- localStorage 영속, 360px 고정 높이 + 내부 스크롤

견적관리:
- 컬럼 폭 조정 (⋮⋮ 추가로 좁아진 한국어 4글자 라벨 보장)
- summaryStats, onRefresh, onDownload(exportToExcel) 연결
- gridId="sales-estimate"로 영속화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:42:52 +09:00
hjjeong 49956f7afa 개발관리·생산관리 — 3D/2D/PDF 카운트 컬럼을 폴더 아이콘으로 통일
사용자 보고: "품명/3D 컬럼이 좁아서 겹쳐 보임 + 폴더 모양(파랑/투명)으로 표시해줘"

운영판 wace 견적현황·partMng 폴더 아이콘 패턴 1:1 적용:
  - 값 > 0  → 파란 폴더 (fill-[#1a73e8])
  - 값 = 0  → 흰색 폴더 (투명 효과, fill-white + muted text)

수정:
  - app/(main)/COMPANY_16/development/part-regist/page.tsx — 3D/2D/PDF (60→70px, center, folder)
  - app/(main)/COMPANY_16/development/part-search/page.tsx — 3D/2D/PDF (60→70px, center, folder)
  - app/(main)/COMPANY_16/development/ebom-search/page.tsx — 3D/2D/PDF (60→70px width 통일)
  - components/development/BomReportTreeDialog.tsx — "Y/공백" → FolderCell
  - components/production/MbomDetailDialog.tsx       — "Y/공백" → FolderCell

sales/{order,sale,revenue}.tsx 의 cu01_cnt 는 "주문서첨부" clip 아이콘이라 별 의미라 미수정.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:40:25 +09:00
hjjeong a136867f52 공용 — 검색·초기화 버튼을 PageHeader 우측 액션 영역으로 이전
사용자 보고: "초기화, 검색 버튼은 상단의 메뉴이름 쪽에 다른 버튼들이랑 같이 있으면 될거같아"

CompactFilterBar 안에 있던 [초기화][검색] 버튼이 자리 차지 + 시선 분산.
PageHeader 의 actions 슬롯 옆으로 통합하면서 11개 페이지 일괄 적용.

PageHeader 확장:
  - onSearch / onReset / loading / searchLabel / resetLabel prop 추가
  - actions 뒤에 [초기화][검색] 버튼 자동 렌더 (h-8 / text-xs)

CompactFilterBar 단순화:
  - onSearch / onReset / loading / searchLabel / resetLabel prop 제거
  - children + totalText 만 유지 (필드 컨테이너 + 합계 텍스트)

11개 페이지: <CompactFilterBar onSearch onReset loading> 3 prop 을
              <PageHeader onSearch onReset loading> 로 이동

메모리: feedback_compact_search_pattern.md 에 "검색·초기화 위치 = PageHeader" 박제

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:17:24 +09:00
hjjeong 4f5dd8b47f 공용 — 영업 4 + 프로젝트 2 + 개발 5메뉴 PageHeader + CompactFilterBar 일괄 적용
총 11개 페이지를 동일한 페이지 구조 표준으로 마이그레이션. 페이지 메뉴명은
PageHeader 가 useMenu() 자동 매칭, 검색 영역은 CompactFilterBar/CompactFilterField,
날짜 범위는 CompactDateRange 로 통일. 모든 자체 grid 검색폼 + 자체 h1 + 자체 액션
버튼 그룹 제거.

영업관리 4:
  - sales/estimate (견적관리) — 7필드 + 결재상태 SmartSelect
  - sales/order    (주문서관리) — 9필드 (날짜 2종)
  - sales/sale     (판매관리)   — 10필드 (출하지시상태 SmartSelect)
  - sales/revenue  (매출관리)   — 11필드 (날짜 3종)

프로젝트관리 2:
  - project/progress     (진행관리)         — 11필드 (그리드 6→자동 wrap)
  - project/wbs-template (제품구분_WBS관리) — 1필드

개발관리 5:
  - development/part-regist  (PART 등록)      — 2필드 (자동완성) + 7 액션
  - development/part-search  (PART 조회)      — 2필드 + 5 액션
  - development/ebom-regist  (E-BOM 등록)     — 4필드 + 3 액션 (잔재 Field helper 제거)
  - development/ebom-search  (E-BOM 조회)     — 3필드 + 4 액션 (정/역전개)
  - development/change-list  (설계변경 리스트) — 8필드 (read-only)

DB:
  - menu_info.menu_desc 11개 메뉴 보강 (PageHeader 자동 표시)
  - docs/migration/common/menu_desc_sync.sql (멱등 UPDATE)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 17:10:07 +09:00
hjjeong e208d26e51 공용 — PageHeader 탭 시스템 대응 (활성 탭 adminUrl 매칭)
RPS 는 탭 기반 라우터라 usePathname() 이 /main 으로 고정됨.
사용자 보고: M-BOM 페이지에서 PageHeader 가 메뉴명을 못 잡아 빈 상태.

수정: useCurrent2ndLevelMenuObjid 와 동일 패턴 적용
  - useTabStore.selectTabs / selectActiveTabId 로 활성 탭 조회
  - pathname='/main' 이면 활성 탭의 adminUrl 로 매칭
  - stripCompanyPrefix 로 /COMPANY_NN 무시 → menu_info.menu_url 양방향 비교

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:51:16 +09:00
hjjeong 2e3a430cf7 공용 — PageHeader 신설 (메뉴명 자동 매칭) + M-BOM 메뉴명 복원
CompactFilterBar 마이그레이션 과정에서 M-BOM 페이지 상단 메뉴명/설명이 사라진
회귀를 해결. customer-cs/cs 의 페이지 헤더 패턴을 공용 컴포넌트로 추출.

신설:
  - components/common/PageHeader.tsx
    · usePathname() + useMenu() 자동 매칭 → menu_info.menu_name_kor + menu_desc
    · 명시 props (title/description/actions) 지원
    · 동적 라우트 prefix fallback (/foo/123 → /foo 매칭)

적용:
  - production/mbom/page.tsx 상단에 <PageHeader /> 1줄 추가

DB:
  - menu_info.menu_desc 보강 (objid 100016/100032)
    "생산용 BOM 트리 + read-only 조회 (운영판 mBomMgmtList 1:1)"

메모리: feedback_compact_search_pattern.md 갱신
  - PageHeader 도 의무 사용 컴포넌트 목록에 추가
  - 페이지 구조 표준 코드 예시 명시

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:49:09 +09:00
hjjeong 364d4707fe 공용 — native <select> 금지 + CompactFilterBar 신설 + M-BOM 시범 마이그레이션
영업관리에 이미 적용된 SmartSelect/CustomerSelect 패턴을 다른 메뉴(생산/개발/프로젝트)
의 native <select> 7개 자리에 일괄 적용. customer-cs/cs 메뉴의 컴팩트 검색바 패턴을
공용 컴포넌트로 추출하고 M-BOM 페이지에 시범 마이그레이션.

신설:
  - components/common/CompactFilterBar.tsx — CompactFilterBar + CompactFilterField + CompactDateRange
    · rounded-md border bg-muted/20 p-2 + flex-wrap (자동 줄바꿈)
    · 자식 input/combobox 자동 h-7 + text-xs 컴팩트화
    · onSearch / onReset / totalText 슬롯

native <select> → SmartSelect 일괄 교체:
  - production/mbom/page.tsx          5건 (주문유형/제품구분/국내해외/고객사/유무상)
  - development/change-list/page.tsx  1건 (년도)
  - development/ebom-regist/page.tsx  1건 (상태)
  - development/ebom-search/page.tsx  1건 (표시레벨)
  - project/progress/page.tsx         3건 (년도/국내해외/유무상)
  - components/development/PartFormDialog.tsx — BasicSelect 가 내부적으로 SmartSelect 위임
  - components/development/BomReportExcelImportDialog.tsx — E-BOM 복사 옵션

M-BOM 시범 마이그레이션:
  - 기존: 2행 grid 6×2 검색 폼 (h-9 큰 입력)
  - 변경: <CompactFilterBar> 안에 <CompactFilterField> 10개 (h-7 컴팩트)

원칙:
  - 향후 모든 신규/수정 페이지는 CompactFilterBar + SmartSelect/CustomerSelect 사용 필수
  - native <select> + 자체 grid 검색폼 작성 금지
  - 메모리: feedback_compact_search_pattern.md

타입체크 0건 에러 (변경 파일 기준).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:44:26 +09:00
hjjeong dd88dc6e8c 생산관리>M-BOM 관리 — PR-A2 단건 상세 + read-only 트리 4분기 (wace mBomPopupLeft.do 1:1)
행 더블클릭 → MbomDetailDialog (헤더 메타 + 동적 LEVEL × 19컬럼 트리 그리드).
운영판 ProductionPlanningController:1113~1276 의 4분기 자동 판별을 백엔드에서 처리:
  1) SAVED         mbom_header.status='Y' 우선 → getSavedMbomTreeList CTE
  2) ASSIGNED_EBOM source_bom_type='EBOM' → partMng.getBOMTreeList(working) CTE
  3) ASSIGNED_MBOM source_bom_type='MBOM' → getMbomStructureOnly CTE
  4) TEMPLATE      Machine 이외 + 동일 part_no → mbom_header 템플릿 CTE
  5) NONE          빈 트리

backend:
  - mbomService.getDetail (getProjectMgmtDetail 1:1, TOTAL_PROD_QTY = production_plan 우선)
  - mbomService.getTree   (4분기 orchestrator + 매퍼 4종 CTE 1:1)
  - GET /api/production/mbom/detail/:objid
  - GET /api/production/mbom/tree/:objid

frontend:
  - lib/api/mbom.ts  : MbomDetail / MbomTreeRow / MbomBomDataType / getDetail / getTree
  - components/production/MbomDetailDialog.tsx (max-w-1600px, 헤더 14필드 + 트리 그리드)
  - page.tsx 행 더블클릭 핸들러

검증: O-RING (593315995) SAVED 분기 5행 정상. TOTAL_PROD_QTY production_plan=5 / QUANTITY=2 fallback 확인.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:29:52 +09:00
hjjeong 66cee22be3 생산관리>M-BOM 관리 — PR-A1 그리드/검색 (mBomMgmtGridList 1:1 이식)
운영 wace productionplanning/mBomMgmtList.jsp + productionplanning.xml:2874-3119
mBomMgmtGridList 매퍼 1:1 이식. PROJECT_MGMT × CONTRACT_ITEM 펼침 그리드
+ M-BOM 헤더/히스토리/구매리스트 상태 표시 + 9 검색 필터.

백엔드 (3 파일 + app.ts 마운트):
- services/mbomService.ts — list() : 9 검색 필터 + 30+ 컬럼 SELECT
  · 주문유형/제품구분/국내해외(CODE_NAME 비교)/고객사(C_ 3-way)/유무상/SN(EXISTS)
  · 품번/품명(PM·CI 양쪽 LIKE)/접수일·요청납기 범위
  · WRITER_NAME/MBOM_EDITOR : user_name() PL/pgSQL (PR-A0 신설)
  · MBOM_STATUS/MBOM_PART_NO/MBOM_REGDATE/MBOM_VERSION : mbom_header+history 서브쿼리
  · PURCHASE_LIST_OBJID/_DATE : sales_request_master.mbom_header_objid 매칭
  · CUSTOMER_NAME : CASE C_% → client_mng / ELSE → supply_mng
- controllers/mbomController.ts — getList
- routes/productionMbomRoutes.ts — GET /list
- app.ts — /api/production/mbom 마운트 (productionRoutes 다음)

프론트 (3 파일):
- lib/api/mbom.ts — MbomListFilter / MbomRow / mbomApi.list
- app/(main)/COMPANY_16/production/mbom/page.tsx — 검색 폼 2행(12 필드) + 16 컬럼 DataGrid
  · comm_code 옵션 로드: /api/sales/codes/0000167 (주문유형) /0000001 (제품구분) /0001782 (유무상)
  · 고객사: /api/sales/customers 재사용 (customer_mng)
  · 국내/해외 + 유상/무상 raw 옵션
- app/(main)/COMPANY_16/purchase/mbom/page.tsx — production/mbom 페이지 re-export
  (사용자 요청: 구매관리 메뉴 트리에도 동일 화면 노출)

메뉴 (data-sync):
- 03_mbom_menu_dedup.sql — menu_info 100016(purchase/mbom) + 100032(production/mbom)
  양쪽 active 보장 (이미 DB에 등록되어 있던 entry)

PR-A2 이후 분리:
- 단건 상세 다이얼로그, read-only mbom_detail 트리 표시
- BOM 복사 (E-BOM→M-BOM 트리 복사)
- 구매리스트 생성 액션 (M-BOM→PURCHASE)
- M-BOM 본 편집 (4프레임 팝업)

검증:
- backend nodemon hot-load OK (401 TOKEN_MISSING 응답으로 라우터 등록 확인)
- 매퍼 SQL 직접 실행: PROJECT_MGMT × CONTRACT_ITEM 5건 + CUSTOMER/M-BOM 매칭 정상
- typecheck: 신규 코드 0 에러 (pre-existing 에러만 잔존)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 15:57:23 +09:00
hjjeong cac879eded Merge pull request 'hjjeong' (#9) from hjjeong into main
Reviewed-on: https://g.wace.me/chpark/vexplor_rps/pulls/9
2026-05-13 05:37:08 +00:00
hjjeong 7218edc500 개발관리>PART 도면 다중 업로드 — M1·M2 [도면 다중 업로드] 버튼 + 파일명↔품번 자동 매칭
wace partMngTempList.jsp btnDrawingUpload + PartMngController.uploadDrawingFilesForPartList +
partMng.xml partMngListByPartNos 1:1 이식.

- 백엔드 (devPartService.drawingMultiUpload):
  · 확장자 → doc_type 매핑 (STP/STEP=3D_CAD, DWG/DXF=2D_DRAWING_CAD, PDF=2D_PDF_CAD)
  · 파일명에서 알려진 확장자 반복 제거 (.idw .dwg .dxf .stp .step .pdf .chg)
  · PART_NO 매칭: 정확 일치 우선 → 안 되면 longest prefix
  · partNoList 지정 → 그 목록 IN 절로 후보 제한 (M1, 현재 그리드 기반)
  · partNoList 미지정 → IS_LAST='1' 전체 part_mng 매칭 (M2, 페이지 밖도 허용)
    (wace partMngListByPartNos <if PART_NO_LIST != null> 분기 1:1)
  · 매칭 성공 → attach_file_info INSERT (target_objid = part_mng.objid)
  · 매칭 실패 → notFoundCount + 임시 파일 삭제
  · 결과 details[] 반환 (파일별 상태/매칭품번/사유)

- 엔드포인트: POST /api/development/part/drawing-multi-upload
  · multer 파일당 200MB · 최대 500개 · 임시 디스크 저장 후 회사/날짜 폴더 이동

- 프론트 PartDrawingMultiUploadButton (개발관리 공용):
  · 버튼 클릭 → 숨김 input(multiple, accept=.stp,.step,.dwg,.dxf,.pdf)
  · 확장자별 분류 + "총 N개 업로드?" confirm (wace 1:1 텍스트)
  · 결과 다이얼로그 — 총합/성공/품번 미존재/실패 + 파일별 상세표

- M1(part-regist): partNoList = 현재 그리드 rows.part_no 전달
- M2(part-search): partNoList 미전달 → 전체 part_mng 매칭

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:36:24 +09:00
hjjeong 119f0f3f2e 개발관리>PART 도면 다중 업로드 (DEV-7) — 공통 AttachFileDropZone 신설 + CAD Data 활성
- 공통 컴포넌트: frontend/components/common/AttachFileDropZone.tsx
  · wace fnc_setFileDropZone + fn_fileCallback2 + fileDelete 1:1
  · /api/files (upload·list·delete·download) attach_file_info 기반
  · readOnly 옵션 (Detail 다이얼로그용), accept 옵션, dragenter+dropEffect=copy
  · 도메인 무관 — ERP/ECR/생산실적 등 어디서나 재사용

- 프론트 채번 유틸: frontend/lib/utils/objidUtil.ts
  · backend objidUtil 1:1 (UUID v4 → Java String.hashCode int32)
  · 신규 등록 시 다이얼로그 진입 시점에 part_mng.objid 선채번
    (wace partMngFormPopUp resultMap.OBJID 패턴)

- PartFormDialog (M1 신규/수정): CAD Data placeholder 제거,
  AttachFileDropZone 3종(3D_CAD / 2D_DRAWING_CAD / 2D_PDF_CAD) 활성.
  신규 모드는 createObjId 로 선채번 후 part_objid 로 백엔드 전달.

- PartDetailDialog: CadCount 제거, AttachFileDropZone readOnly 로 교체
  (목록·다운로드만, 드롭존/삭제 숨김).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:04:50 +09:00
hjjeong 7d67a5ab1d 개발관리>PART 등록·조회 + E-BOM 등록 검색 폼 select2-part 자동완성 (운영판 1:1)
3 페이지 검색 폼이 단순 Input + 품번/품명 LIKE 였음. 운영판 wace 는 class="select2-part"
자동완성 (initPartSelect2Ajax) + 한쪽 선택 시 다른 쪽 자동 채움.

수정 페이지 (모두 DevPartSelect 적용):
- part-regist/page.tsx (M1 PART 등록 — wace partMngTempList.jsp)
- part-search/page.tsx (M2 PART 조회 — wace partMngList.jsp)
- ebom-regist/page.tsx (M3 E-BOM 등록 — wace structureList.jsp)

동작:
- 품번/품명 양쪽 DevPartSelect (part_mng IS_LAST='1' 캐시)
- 품번 선택 → 품명 자동 채움 (row.part_name)
- 품명 선택 → 품번 자동 채움 (row.part_no)
- setFilter 함수형 업데이트로 동시 setState 충돌 방지

ebom-search 와 동일 패턴 통일 — DevPartSelect 1개 컴포넌트로 4 페이지 공유.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:28:38 +09:00
hjjeong 68d2dcb32e 개발관리>E-BOM 조회 — 운영판 1:1 그리드 + 토글 + 품번 상세 + 검색 anchor 정정
(1) 정전개 트리 화면 운영판 wace structureAscendingList.jsp 1:1 정정:
   - L1..LMaxLevel 컬럼 — row.lev 와 일치하는 컬럼에만 "*" 표시 (이전엔 품번 표시)
   - 별도 품번 컬럼 1개 (모든 행 part_no)
   - 3D/2D/PDF — renderType: "folder" (wace fnc_getFolderIcon 1:1)
   - 컬럼 운영판 1:1 : 품번/품명/수량/항목수량/3D/2D/PDF/재료/열처리경도/열처리방법/표면처리/메이커/범주이름/비고
   - 제거 : 변경일/REV/규격/중량 (운영판 미사용)

(2) 토글 -/+ 버튼 추가 (wace 트리 1:1):
   - 첫 컬럼 __toggle — 자식 있는 행만 − / + 표시, 클릭 시 자식 숨김/표시
   - collapsedChildIds Set<string> 상태로 접힘 관리
   - ancestor 체인: parent_objid → 부모 행 child_objid 추적 (cycle guard)
   - 가시 행 필터: ancestor 중 하나라도 collapsed Set 에 있으면 hide → 자손 전체 숨김
   - 새 조회 시 collapsed Set 초기화 (모두 펼침)

(3) 품번 셀 클릭 → PartDetailDialog (wace partMngDetailPopUp 1:1):
   - row.part_no = part_mng.objid::varchar 이므로 그대로 detail dialog 의 objid 로 전달
   - ebom-search 페이지에 PartDetailDialog 임포트 + state

(4) 검색 필터 anchor 정정 (사용자 검증: 1행만 나오고 자식 안 풀림):
   - 이전: search_part_no/search_part_name 을 결과 단계 WHERE PM.part_no LIKE ... 로 적용
            → 매칭 행 1개만 살아남고 자식 잘림
   - 정정: anchor 단계에서 매칭된 PART 가 들어있는 bom_report_objid 전체를 startWhere 로
            → 재귀 CTE 가 자식 모두 풀어냄 (운영판 1:1)
   - search_level (1~5) 은 결과 단계 유지 (트리 깊이 제한)
   - ascending / ascendingForExcel 양쪽 동일 패턴

(5) ascending SELECT 풀 컬럼 보강:
   - 추가 : item_qty(p_qty), heat_treatment_hardness/method, surface_treatment,
            maker, part_type, part_type_title (comm_code.code_name)
   - TREE CTE 컬럼에 item_qty 추가
   - BomTreeRow 타입 동기 (lib/api/devBom.ts)

(6) 상태변경 시 확정일(DEPLOY_DATE) 처리 — 사용자 요청:
   - status = 'Y' 변경 시 DEPLOY_DATE = TO_CHAR(NOW(), 'YYYY-MM-DD') 채움 (varchar)
   - 'N' 변경 시 기존 DEPLOY_DATE 보존
   - $5 prepared statement 타입 추론 충돌 (varchar vs unknown) → $5::varchar 명시 캐스팅
   - STATUS_TITLE 매핑은 운영판 1:1 — CREATE/CHANGEDESIGN/DEPLOY 만 라벨, Y/N 등은 raw 표시

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 12:11:08 +09:00
hjjeong 20a429eecb 개발관리>E-BOM 화면 운영판 1:1 정정 다수 — 검색폼·상태변경·체크박스·STATUS 표시
사용자 검증으로 발견된 5가지 함정 일괄 정정.

(1) ebom-search 검색폼 운영판 1:1 — wace structureAscendingList.jsp 노출 필드만:
   - 제거: 프로젝트 OBJID (raw input), UNIT_CODE (raw input)
     운영판도 고객사/프로젝트번호/유닛명 모두 주석 처리되어 노출 안 됨
   - 유지: 품번 / 품명 / 표시 레벨 (1~5 select)
   - BomTreeFilter.search_level 추가 + ascending/descending CTE 에 T.lev <= $search_level::int

(2) 품번/품명 자동완성 (wace select2-part 1:1):
   - 영업관리 PartSelect 는 item_info 마스터 기반 → 개발관리(part_mng)용 별도 컴포넌트 신설
   - backend GET /api/development/part/options : IS_LAST='1' part_mng 전체 (영업관리 sales/parts 패턴)
   - frontend DevPartSelect.tsx : SmartSelect 캐시 + mode partNo/partName 분리
   - ebom-search 페이지 단순 Input → DevPartSelect 교체
   - 품번 선택 시 품명 자동 채움 / 품명 선택 시 품번 자동 채움 (운영판 select2-part 1:1)

(3) BomReportStatusDialog 운영판 1:1 재작성 — wace structureStatusChangePopup.jsp:
   - 잘못된 점: read-only 박스 + 상태 select(create/changeDesign/deploy 3옵션)
   - 정정: 5필드 모두 편집 가능 (CommCodeSelect 제품구분 / 품번 input / 품명 input /
           Version input / 상태 Y/N 라디오) — 운영 매퍼 updateStructureStatus 5컬럼 UPDATE 1:1
   - 헤더 파란 바 + 4컬럼 테이블(25%/75%) + 저장/닫기 중앙 배치 (운영판 스타일 1:1)

(4) DataGrid id 매핑 — 체크박스 ID 키 불일치 함정:
   - DataGrid 는 row.id 로 체크박스 ID 관리, 백엔드 응답은 row.objid (postgres lowercase)
   - 결과: checkedIds[0] 가 undefined → 상태변경/수정/삭제 다이얼로그가 objid=undefined 로 열려
     detail 호출 안 됨 → 빈 폼 표시 (사용자 지적 "기본 정보 표시 안됨")
   - 일괄 수정 (3 페이지) : ebom-regist / part-regist / part-search
     gridRows = useMemo(() => rows.map(r => ({ ...r, id: r.objid })), [rows])
     영업관리 페이지 동일 패턴 1:1

(5) STATUS_TITLE 매핑 운영판 1:1 — 운영 그리드는 'Y'/'N' 글자 그대로 표시:
   CASE UPPER(T.STATUS)
     WHEN 'CREATE' THEN '등록중'
     WHEN 'CHANGEDESIGN' THEN '설계변경미배포'
     WHEN 'DEPLOY' THEN '배포완료'
     ELSE COALESCE(T.STATUS, '') END AS STATUS_TITLE
   - 운영 매퍼는 ELSE '' 이지만 RPS 는 raw fallback (사용자 화면에서 식별 가능)
   - 'Y'/'N' 매핑 라벨 추가 → 운영 스크린샷 확인 후 제거 (운영판은 raw)

미해결 (별 작업):
- 확정일 (DEPLOY_DATE) 표시 — 운영판은 별도 "배포" 액션 (deployBomReport 매퍼) 으로 채움.
  RPS ebom-regist 에 배포 버튼 미구현 → 신규 BOM 확정일 빈값. 별 PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:43:29 +09:00
hjjeong 61bd02b9dc Merge pull request 'hjjeong' (#10) from hjjeong into main
Reviewed-on: https://g.wace.me/chpark/vexplor_rps/pulls/10
2026-05-13 01:11:23 +00:00
hjjeong 429b1d1e8a 개발관리>E-BOM 등록 — BOM 구조 다이얼로그 신설 + 트리 조인 버그 정정
사용자 검증 중 두 가지 문제 발견:

1) 트리가 1레벨만 표시되고 자식들이 안 풀림 — ascending/descending CTE 의 재귀
   조인 조건 버그.
   잘못된 조인: B.parent_objid = T.objid
   올바른 조인: B.parent_objid = T.child_objid (ascending),
                B.child_objid  = T.parent_objid (descending)

   wace relatePartInfo 1:1 패턴 — BOM_PART_QTY INSERT 시 OBJID 와 별도로
   createObjId() 따로 발급되는 CHILD_OBJID 가 부모 식별자. 자식 행의 PARENT_OBJID
   는 부모 행의 CHILD_OBJID 와 매칭됨 (PARENT_OBJID = T.OBJID 가 아님).

   4 함수 일괄 정정 : ascending / descending / ascendingForExcel / descendingForExcel
   검증 : test-20003-0082 BOM → Level 1 루트 + Level 2 자식 2건 정상 트리 출력.

2) E-BOM 컬럼이 숫자(bom_cnt)로 표시되어 어디를 눌러 BOM 구조를 봐야 할지 불명확.
   운영판 wace 는 fnc_getFolderIcon 으로 폴더 아이콘 + 클릭 → setStructurePopupMainFS.

backend:
- GET /api/development/ebom-tree/full → ascendingForExcel 1:1, 풀 컬럼 JSON 노출
  (HEAT_TREATMENT_HARDNESS/METHOD/SURFACE_TREATMENT/MAKER/PART_TYPE_TITLE/CU_파일 카운트 포함)

frontend:
- BomReportTreeDialog.tsx 신설 (wace 4-Frame 팝업 → 단일 다이얼로그 통합)
  · 헤더 메타 8필드 (제품구분/품번/품명/Version/상태/등록자/등록일/확정일)
  · 동적 LEVEL 컬럼 (L1..LMaxLevel, "*" 표시) + 운영판 14컬럼
  · 노란 배경 헤더 (운영판 스타일 1:1)
  · 엑셀 다운로드 버튼 (해당 BOM 만 ascendingForExcel 호출)
- lib/api/devBom.ts : treeFull() API + BomTreeFullRow 타입
- app/.../ebom-regist/page.tsx :
  · bom_cnt 컬럼 formatNumber → renderType: "folder" (wace fnc_getFolderIcon 1:1)
  · 클릭 핸들러를 품번 → E-BOM 폴더 셀로 이동 (운영판 fn_openSetStructure 동작)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:08:39 +09:00
hjjeong 5662fd2910 개발관리>PART 상세 — wace partMngDetailPopUp.jsp 1:1 재작성 + colgroup 비율 정정
PartDetailDialog 재작성 (운영판 부적합 → 정정):
- 기존: 임의 섹션 분리("기본정보/크기·형상/분류·단위/Y-N 플래그") + 운영판 없는 필드
  (두께/너비/높이/외경/내경/길이/단위/수량/후가공/공급업체) 노출
- 정정: PartFormDialog 와 동일 레이아웃을 readonly 박스(Ro)로 표시
  · 운영판 22필드 그대로 (운영판 없는 9필드 제거)
  · 부속 행 추가 (운영 detail 만 표시) : EO No / EO Date / EO구분(CHANGE_TYPE) / EO사유(CHANGE_OPTION)
  · CAD Data 3행 : 3D / 2D(Drawing) / 2D(PDF) — 첨부 카운트 표시 (실제 파일 다운로드는 DEV-7 별 PR)
  · 헤더: 파란색 바 "품목 상세" (운영판 헤더 1:1)
  · 코드값 → 라벨 매핑 : ODRFG (구매/생산/Phantom), LOT_FG (미사용/사용),
                          USE_YN (미사용/사용), QC_FG (무검사/검사), SETITEM/REQ (부/여)

colgroup 비율 정정 (Form + Detail 공통):
- 기존: 4컬럼 단순 (라벨 110px / input / 라벨 110px / input) → 첫 input 25% 좁음
- 정정: 운영판 JSP colgroup 1:1 (12% / 12% / 25% / 12% / *) + 매 행 첫 Td 에 colSpan={2}
  · 결과 input1 ≈ 37%, input2 ≈ 39% — 양쪽 input 비율 거의 동일 (운영판 일치)
  · 규격/비고 행 colSpan={4} (운영 JSP colspan=4)
  · CAD Data 행 colSpan={3} (작은 라벨 1칸 + 컨텐츠 3칸)
  · Th 의 고정 너비 w-[110px] 제거 — colgroup 이 폭 결정
  · table-fixed 추가로 colgroup 비율 강제 적용

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:32:23 +09:00
hjjeong 82a253ec6a 개발관리>PART 등록 폼 — wace partMngFormPopUp.jsp 1:1 재작성
사용자 지적으로 재발견: 기존 PartFormDialog 는 임의로 "기본정보/크기·형상/분류·단위/Y-N
플래그" 섹션 분리 + 운영판에 없는 필드(두께/너비/높이/외경/내경/길이/수량/단위/후가공/
공급업체코드/제품OBJID) 추가 + Y/N 라디오로 작성되어 있었음. 운영판과 완전 다른 화면.

운영판 1:1 정정:
- 단일 4-col table 레이아웃 (라벨 / input / 라벨 / input)
- 필드 22개만 (운영판 그대로):
  ① 품번 | 품명
  ② 재료 | 열처리경도
  ③ 열처리방법 | 표면처리
  ④ 메이커 | 범주이름* (PART_TYPE, comm_code 0000062)
  ⑤ 규격 (colspan=3)
  ⑥ 계정구분*(comm_code 0900213) | 조달구분*(0=구매/1=생산/8=Phantom 하드)
  ⑦ 재고단위*(comm_code 0001399) | 관리단위*(동일)
  ⑧ 환산수량*(숫자) | LOT구분*(0=미사용/1=사용)
  ⑨ 사용여부*(0=미사용/1=사용) | 검사여부*(0=무검사/1=검사)
  ⑩ SET품여부*(0=부/1=여) | 의뢰여부*(0=부/1=여)
  ⑪ 개당길이 | 개당소요량
  ⑫ 비고 (colspan=3)
  ⑬ CAD Data : 3D / 2D(Drawing) / 2D(PDF) Drag&Drop placeholder
     (실제 업로드 기능은 DEV-7 별 PR — UI 영역만 추가)

- LOT/USE_YN/QC_FG/SETITEM_FG/REQ_FG : Y/N 라디오 → 운영판 select 옵션 그대로 (4개씩 한글값)
- 필수 검증 11개 추가 (wace fn_save 1:1) : 범주이름·계정구분·조달구분·재고단위·관리단위·
  환산수량·LOT구분·사용여부·검사여부·SET품여부·의뢰여부
- DialogTitle "품목 등록" / "품목 수정" (운영판 헤더 그대로) + 파란색 헤더 바
- 저장 / 닫기 버튼 중앙 배치 (운영판 plm_btn_wrap_center)

PartDetailDialog 도 동일하게 운영판 부적합 — 다음 단계에서 별도 재작성 예정.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:18:39 +09:00
hjjeong 7d73d2ee57 개발관리>E-BOM 조회 M4 — 정/역전개 엑셀 다운로드 신설 (wace 1:1)
운영판: structureAscendingListExcel.jsp / structureDescendingListExcel.jsp

backend (devBomService.ts):
- ascendingForExcel / descendingForExcel — 그리드용 ascending/descending 보다 풀 컬럼
  · 추가: P_QTY(bom_part_qty.item_qty), HEAT_TREATMENT_HARDNESS, HEAT_TREATMENT_METHOD,
          SURFACE_TREATMENT, MAKER, PART_TYPE_TITLE(comm_code.code_name)
- devBomExcelExportService.ts 신규 (xlsx 라이브러리)
  · 헤더: 동적 L1..LMaxLevel + 품번 / 품명 / 수량 / 항목수량 / 3D / 2D / PDF /
          재료 / 열처리경도 / 열처리방법 / 표면처리 / 메이커 / 범주 이름 / 비고 (wace 1:1)
  · LEVEL 셀: 행의 LEV 와 동일한 컬럼에 "*", 나머지는 공백
  · 3D/2D/PDF: attach_file_info count > 0 → "Y", 0 → 공백 (wace 1:1)
  · 컬럼 너비: LEVEL 4, 품번/품명/재료/MAKER 등 적절히 조정
  · 시트명: "BOM 정전개" / "BOM 역전개"
- controllers/devBomController.ts: excelAscending / excelDescending 추가
  · Content-Disposition 에 filename + filename*=UTF-8'' 둘 다 (한글 파일명 호환)
- routes/devBomRoutes.ts: /ebom-tree/ascending/excel, /ebom-tree/descending/excel

frontend:
- lib/api/devBom.ts: excelAscending/excelDescending (responseType: "blob")
  · Content-Disposition 의 filename*=UTF-8'' 우선 파싱 헬퍼 추가
- app/.../ebom-search/page.tsx: "정전개 엑셀" / "역전개 엑셀" 버튼 추가
  · 현재 검색 조건 그대로 다운로드, blob → anchor.click 으로 저장
  · 파일명: 서버 응답 헤더의 "BOM 조회(정전개)_YYYY-MM-DD_HH-mm.xlsx" 그대로 사용

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:07:27 +09:00
hjjeong 0c791d21d6 개발관리>E-BOM 등록 — XLSX 구현 폐기 후 CSV(11컬럼·수준 기반)로 재작성
운영판 wace 재확인 결과 BOM 등록은 XLSX가 아니라 CSV 가 진짜 입력 포맷이었음.
근거:
  · openBomReportExcelImportPopUp.jsp : 제목 "PART 및 구조등록 CSV upload",
    Drop Zone "Drag & Drop CSV 템플릿", fnc_setFileDropZone(..., "csv") 로 CSV 만 허용
  · /partMng/parsingExcelFile.do 가 .csv 분기에서 별도 함수 parsingCsvFile() 호출
  · CSV 11컬럼 : 수준 / 품번 / 품명 / 수량 / 항목수량 / 재료 / 열처리경도 / 열처리방법 /
                  표면처리 / 공급업체(MAKER) / 범주이름(PART_TYPE)
  · CSV 는 PARENT_PART_NO 컬럼이 없고 "수준" 으로 부모-자식 자동 결정
    · 숫자("1","2","3"): 깊이 D 의 부모 = D-1 의 최신 품번
    · 점 표기법("1","1.1","1.4.1"): 마지막 점 이전 수준이 부모

backend (devBomExcelImportService.ts):
  · XLSX(xlsx 라이브러리) 파싱 → CSV(iconv-lite) 파싱으로 완전 재작성
  · 인코딩 자동 감지 1:1 — CP949 → UTF-8 → EUC-KR → MS949 순서, � 카운트로 베스트 선택,
    UTF-8 BOM() 자동 제거
  · CSV 영문 범주명 자동 변환 — Assy/ASSY→조립품, Buy/BUY→구매품, Make/MAKE→부품
  · 범주별 ACCTFG/ODRFG 자동 설정 — 조립품(0001813)·부품(0001812) → ACCTFG=4·ODRFG=1,
                                       구매품(0000063) → ACCTFG=7·ODRFG=0
  · 기본값 일괄 — UNIT_DC=0001400(EA) · UNITMANG_DC=0001400 · UNITCHNG_NB=1 ·
                  LOT_FG=1 · USE_YN=1 · QC_FG=0 · SETITEM_FG=0 · REQ_FG=0
  · 검증 1:1 — rowIndex > 2 에서만 모품번 자품번 목록 존재 검사, NOTE 누적
  · 저장 로직(savePartBomMaster)은 동일 유지 — 자식 PART updatePartInfoFromCsv UPDATE /
    insertpartInfo INSERT, 부모 PART 존재 시 lookup·없으면 "" (INSERT 안 함),
    bom_part_qty INSERT 시 ACCTFG/ODRFG/UNIT_DC/UNITCHNG_NB 등 모든 컬럼 동기

frontend:
  · BomExcelRow → BomCsvRow (LEVEL 컬럼 + ACCTFG/ODRFG/UNIT_DC/UNITCHNG_NB/LOT_FG/USE_YN/
    QC_FG/SETITEM_FG/REQ_FG 자동 채움 필드 추가). BomExcelRow 는 호환 type alias 로 보존
  · BomReportExcelImportDialog : 제목 "PART 및 구조등록 CSV upload", accept=".csv", Drop Zone
    안내 텍스트 변경, 그리드 컬럼 — 결과/수준/모품번(자동)/품번/품명/수량/항목수량/재료/
    열처리경도/열처리방법/표면처리/공급업체/범주/계정구분(자동)/조달구분(자동)
  · 파싱 결과의 encoding 정보 표시 (CP949/UTF-8 등)

정적 자산:
  · 운영 BOM_REPORT_EXCEL_IMPORT_TEMPLATE.xlsx 제거 (운영판도 실제 사용 안 함)
  · 신규 BOM_REPORT_CSV_IMPORT_TEMPLATE.csv 추가 (11컬럼 헤더 + 4행 샘플)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:02:15 +09:00
hjjeong 7779f37c17 개발관리>PART·E-BOM Excel Import 메뉴 신설 — wace partMng 1:1 이식
PART Excel Import (M1·M2 공용):
- /partMng/openPartExcelImportPopUp.do + partParsingExcelFile.do + partUploadSave.do 1:1
- 22컬럼 파싱 + NOTE 누적 검증 (품번 필수/중복, PART_TYPE/ACCTFG/UNIT_DC commCode 매핑,
  ODRFG/LOT_FG/USE_YN/QC_FG/SETITEM_FG/REQ_FG 한글 → 코드값)
- 저장은 신규 PART_NO 만 mergePartMng INSERT (기존 IS_LAST='1' 행은 skip)
- part-regist + part-search 페이지에 Excel Upload 버튼 + 다이얼로그 연결

BOM Report Excel Import (M3 = openBomReportExcelImportPopUp = "PART 및 구조등록 Excel upload"):
- /partMng/parsingExcelFile.do + checkDuplicatePartNo.do + getBomDataForCopy.do
  + partBomApplySave.do (savePartBomMaster) 1:1
- 10컬럼 파싱 + 자품번/모품번/품명/수량 필수 검증, 모품번이 자품번 목록(Set)에 존재 검증,
  수량 숫자+>0 검증, PART_TYPE='0001788'(구매품표준) part_mng 존재 검증
- 1레벨(모품번 없는 첫 행) → 헤더 PART_NO/PART_NAME 자동 채움
- 저장 트랜잭션 (wace 1:1):
    헤더 part_bom_report INSERT(신규) / DELETE 자식트리+UPDATE(수정)
    자식 PART: part_mng IS_LAST='1' 존재 시 updatePartInfoFromCsv UPDATE, 없으면 insertpartInfo INSERT
    부모 PART: 존재 시 lookup, 없으면 "" (절대 INSERT 안 함 — wace 5359-5361)
    bom_part_qty INSERT (relatePartInfo) — 부모행 CHILD_OBJID 를 PARENT_OBJID 로 체인
- 헤더 PART_NO 중복 검사 (편집 중인 자신 제외)
- E-BOM 복사 기능 (기존 BOM → 그리드 행) + Template Download
- ebom-regist 페이지에 "E-BOM 등록(Excel)" 버튼 + 다이얼로그 연결

운영 템플릿 정적 자산:
- frontend/public/templates/PART_EXCEL_IMPORT_TEMPLATE.xlsx
- frontend/public/templates/BOM_REPORT_EXCEL_IMPORT_TEMPLATE.xlsx (.gitignore 우회 git add -f)

wace structureExcelImportPopup.jsp 는 옛 차종/제품군/사양 도메인 화면으로 운영 메뉴 트리에
서 더이상 호출되지 않아 이식 대상 제외.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 17:55:17 +09:00
hjjeong c9adfd7327 개발관리>설계변경 리스트 메뉴 신설 (PR-C) — wace partMng 1:1 이식
backend (M5, read-only):
- devEoHistoryService: list + getByObjid
- partMngHistList SQL 1:1 (NVL→COALESCE, PART_MNG.OBJID bigint cast, CODE_NAME→LEFT JOIN comm_code)
- 동적 필터 10종 (Year/contract_objid/unit_code/part_no/part_name/change_option/eo_start~end/change_type/part_type/writer_id)
- 신규등록 제외 가드: NOT (HIS_STATUS='DEPLOY' AND CHANGE_TYPE IS NULL AND REVISION='RE') + BOM_STATUS='deploy'
- 품번변경(CHANGE_OPTION=0001790) 'A->B' 머지 CASE (part_no_disp/part_name_disp/revision_disp)

frontend (M5):
- change-list/page.tsx: 16셀 그리드 + 검색 8필드 + 페이징
- PartHisDetailDialog: 모든 필드 disabled, 4 섹션 (EO/프로젝트/PART/수량)
- AdminPageRenderer dynamic 임포트 + 기존 menu_info URL 그대로 사용

개발관리 5개 메뉴 (M1~M5) baseline 완료.

본 PR 제외 (별 PR): writer SmartSelect, change_type/change_option comm_code 그룹 SmartSelect (그룹 ID 확정 후)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:27:37 +09:00
hjjeong 0872199b30 개발관리>E-BOM 등록·조회 메뉴 신설 (PR-B) — wace partMng 1:1 이식
backend (M3+M4):
- devBomService: list/getByObjid/updateStatus/removeMany/ascending/descending
- M3 그리드 SQL (getBOMStandardStructureGridList 1:1)
  - customer_mng 매핑 (wace SUPPLY_MNG → vexplor customer_mng.customer_code)
  - PRODUCT_NAME LEFT JOIN comm_code (CODE_NAME 함수 대체)
- M3 다중 삭제 트랜잭션 (bom_part_qty + part_bom_report CASCADE)
- M4 정/역전개 재귀 CTE (bom_part_qty 트리 + part_mng JOIN)
- vexplor 적응: M4 product_mgmt_spec/upg/vc 분기 제거 (스키마 단순화)
- PG 재귀 CTE 타입 일치: ARRAY[BP.objid::varchar] 명시 cast

frontend (M3+M4):
- ebom-regist (M3): 9셀 그리드 (제품구분·품번·품명·E-BOM·등록자·등록일·확정일·Version·상태)
- ebom-search (M4): 동적 LEVEL 컬럼 + 정/역전개 토글
- BomReportStatusDialog: 상태 변경 (create/changeDesign/deploy + version)
- AdminPageRenderer dynamic 임포트 2건 + menu_info URL spec 정렬

본 PR 제외 (별 PR): E-BOM Excel Import, 정/역전개 Excel Download, BOM_PART_QTY 수량 편집

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:23:10 +09:00
hjjeong ea6606da0c 개발관리>PART 등록·조회 메뉴 신설 (PR-A) — wace partMng 1:1 이식
backend (M1+M2):
- devPartService: listTemp/listRelease/getByObjid/create/update/deploy/removeMany
- partMngBaseSimple SELECT + 추가 15컬럼(acctfg/odrfg/unit_dc/unitmang_dc/lot_fg 등) 라벨/CASE
- deploy 트랜잭션 3단계 (isLastInit → part_mng_history INSERT → partMngDeploy + EO_NO 채번)
- EO_NO 분기: is_longd='1'→EOB{yy}-{seq} / else EO{yy}-{seq}
- objidUtil: wace CommonUtils.createObjId() 1:1 (bigint objid 채번)
- DDL: 9 신규 테이블 + part_mng 15컬럼 ALTER (운영판 1:1 추출)

frontend (M1+M2):
- part-regist (M1) / part-search (M2): 23셀 그리드 + 검색폼 + 액션
- PartFormDialog: 등록/수정 통합 (mode prop, 4 섹션)
- PartDetailDialog: 읽기 전용 + "수정" dispatch
- AdminPageRenderer dynamic 임포트 2건 + menu_info URL spec 정렬

본 PR 제외 (별 PR): 도면 다중 업로드, ERP 업로드, Excel Import, BOM_PART_QTY R/W

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 16:14:10 +09:00
chpark 2cefbf2855 배치 등록된연결 저장 누락 + 실행 timeout + 권한관리 코드 숨김
Build and Push Images / build-and-push (push) Has been cancelled
- 배치(REST API→DB) 저장 시 매핑 payload 에 from_connection_id 추가
  — 등록된 연결 선택값이 DB 에 저장 안 돼 수정 화면 재진입 시 manual 로 표시되던 문제 해결
- 배치 실행 호출만 timeout 30s → 5분(300000ms) override
  — 외부 API + 대량 INSERT 시 자주 끊기던 AxiosError 해결
- 권한관리 좌측 권한 카드에서 authCode 행 제거
  — authName 만 노출(코드값은 hover tooltip 으로 유지). 검색은 authCode 도 매칭 유지

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:05:41 +09:00
hjjeong d8d9ad3bcc Merge pull request 'hjjeong' (#8) from hjjeong into main
Reviewed-on: https://g.wace.me/chpark/vexplor_rps/pulls/8
2026-05-12 04:47:29 +00:00
hjjeong 5c085dc69e 프로젝트 상세 정보 다이얼로그 wace 운영판 1:1 + 영업관리 판매·매출관리 연결
· 다이얼로그 디자인: 프로젝트정보 박스(주문유형/제품구분/국내해외/고객사·유무상/접수일/견적환종/견적환율) + 품목정보 테이블(No/품번/품명/S/N/요청납기/고객요청사항/반납사유)
· ProjectInfoData 정규화 props — 진행관리/판매관리/매출관리 각각 toProjectInfo 매핑으로 호출
· backend SQL 3곳 보강: exchange_rate (contract_mgmt) + customer_request (CI→CM fallback) + return_reason_name (CI CODE_NAME)
· 판매관리/매출관리 page에 columns useMemo + project_no 셀 onClick + ProjectInfoDialog state 추가
· wace 운영 URL: /salesMgmt/salesRegForm.do?saleNo=detail 1:1 매핑 (새 창 → 같은 탭 다이얼로그)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 13:44:58 +09:00
hjjeong 50669a66ee 프로젝트관리>제품구분_WBS관리 메뉴 신설 — wace WBS 템플릿 1:1 이식
· 메인 그리드 5컬럼(제품구분/제목/WBS/등록자/등록일) + 통합 팝업(트리 CRUD + 엑셀 임포트 + 템플릿 다운로드)
· 운영 매핑: pms_wbs_template(헤더) + pms_wbs_task_standard(트리) — 활성 갈래 확정 (_info/_standard2 갈래는 2021년 멈춘 레거시)
· wace mergeExcelUploadWBS 1:1: 신규=헤더+트리 INSERT, 수정=트리 일괄 DELETE→INSERT (헤더 변경 없음)
· objid 채번 gen_random_uuid()::text, 엑셀 파싱 xlsx(SheetJS), 정적 템플릿 frontend/public/templates/
· DataGrid 컬럼 단위 onClick 추가 (WBS 폴더 셀 클릭용)
· DDL: 8개 테이블 162컬럼 (docs/migration/project/ddl-extracted/200_pms_wbs.sql) / GAP: docs/migration/project/02-wbs-template.md
· 프로젝트 자동 복사/진행관리 연계는 wace도 미완성 — P2 범위 외

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 13:43:51 +09:00
hjjeong 7c4817b045 진행관리 P1.5 재작업 — PROJECT_NO 셀 클릭 시 프로젝트 정보 다이얼로그
· wace fn_openSaleRegPopup(PROJECT_NO, "detail") 의도 재해석 — read-only 상세 조회 모드
· 행 전체 클릭(onRowClick) → PROJECT_NO 컬럼 셀 클릭(cellClick)으로 좁힘 (wace 1:1)
· 판매관리 페이지 라우팅 폐기 → ProjectInfoDialog 신설 (같은 탭, list row 직접 사용, 추가 API 호출 0)
· 표시 항목: 프로젝트번호/영업번호/주문유형/제품구분/국내해외/고객사/유무상/품번/품명/S/N/수주수량/접수일/요청납기/발주일/프로젝트명/작성자
· 영업관리 변경 롤백 (SaleListFilter.project_no, useSearchParams 자동 선택, 초기화 핸들러)
· 01-progress / 01-progress-verify 문서 갱신

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 12:06:01 +09:00
chpark 945b65b870 시퀀스 관리 메뉴 + 테이블 타입관리 코멘트/검증 + 설계 문서
Build and Push Images / build-and-push (push) Has been cancelled
- 시스템 관리 > 시퀀스 관리 신규 메뉴 + 페이지(채번 룰 빌더)
- ensureSequenceMngMenu 부팅 시드
- 테이블 타입관리 → 채번 룰 드롭다운 + 의존성 자동 검증
- 표시명/코멘트 UX 개선
- 설계 문서 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 11:46:11 +09:00
hjjeong 332688a441 진행관리 P1.5 행 클릭 + 검증 문서 — 판매관리 라우팅 (wace fn_openSaleRegPopup 대응)
· 진행관리 행 클릭 → /COMPANY_16/sales/sale?project_no={PROJECT_NO} 라우팅
· 판매관리 page: useSearchParams로 project_no 자동 필터 + 첫 매칭 행 자동 선택 + 초기화 핸들러 보강
· backend SaleListFilter.project_no 추가 (T.project_no = $1 단일 매칭, 기존 영업 흐름 무영향)
· wace 새창 패턴 → RPS SPA 동일 탭 라우팅으로 매핑 (의도 동일)
· docs/migration/project/01-progress.md + 01-progress-verify.md 신설 (영업관리 검증 문서 패턴)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 18:47:56 +09:00
hjjeong b4ed5f3a2a Merge pull request 'hjjeong' (#7) from hjjeong into main
Reviewed-on: https://g.wace.me/chpark/vexplor_rps/pulls/7
2026-05-11 09:26:35 +00:00
hjjeong a1ace22626 프로젝트관리>진행관리 메뉴 신설 — wace projectMgmtWbsList3 1:1 이식
· 그리드: 8그룹 18셀 평탄화 (운영판 projectMgmtWbsGridList SQL 1:1)
· 검색폼: 11필드 (년도/프로젝트번호/주문유형/고객사/제품구분/요청납기/국내해외/유무상/품번/품명/S/N)
· 영업관리 패턴 통일: PartSelect 단일 search_partObjId, customer_mng 단일 LEFT JOIN
· client_mng/supply_mng 분기 → customer_mng로 흡수, CODE_NAME() 함수 직접 사용
· 행 클릭 동작은 P1.5 별도 결정 (영업관리 OrderRegistDialog 재사용 후보)
· PMS_WBS_TASK/SETUP_WBS_TASK 의존 컬럼은 그리드 표시 컬럼에 없어 P2(WBS관리) 보류

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 18:22:06 +09:00
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
hjjeong 905d5c0976 PR-D G9 수주복사 + G11 Amaranth 수주 결재상신 (wace 1:1)
[G9 수주복사 — wace copyEstimateAndOrderInfo 1:1]
- salesOrderMgmtService.copyOrder: 새 영업번호({YY}C-{NNNN}) 채번 +
  contract_mgmt 23컬럼 INSERT-SELECT(contract_result='', is_direct_order='Y' 강제) +
  contract_item + contract_item_serial 통째 복제
- POST /api/sales/order-mgmt/:id/copy 라우트
- 주문관리 그리드 "수주복사" 버튼 (Copy 아이콘) + handleCopyOrder

[G11 Amaranth 수주 결재상신 — wace ApprovalService.getAmaranthSsoUrl 1:1]
- chpark의 amaranthApprovalClient(HMAC-SHA256 + AES-128-CBC) 재사용
- amaranth_approval만 사용(자체 approval 미경유, wace 운영 패턴 동일)
- target_type='CONTRACT_ORDER', formId='1161', compSeq='1000'
- approKey 분기: 신규 / reject·delete·create는 새 approKey UPDATE / 그 외 재사용
- salesOrderMgmtService.startOrderApproval: user_info.emp_seq 조회 →
  라인 0건 가드 → 매핑 분기 → SSO URL 발급 → INSERT/UPDATE → fullUrl 반환
- POST /api/sales/order-mgmt/:id/amaranth-approval 라우트
- 주문관리 그리드 "결재상신" 버튼 (Send 아이콘, sky-600) + handleAmaranthApproval
- getList SQL에 LEFT JOIN amaranth_approval AMR_ORDER 추가 +
  order_appr_status(작성중/결재중/결재완료/반려 한글) + order_amaranth_status 노출

[DB 스키마]
- amaranth_approval.target_objid BIGINT → VARCHAR(80) (wace 운영 1:1)
  · 출처: wace 매퍼 T.OBJID::VARCHAR = AMR_ORDER.TARGET_OBJID
  · 사유: contract_mgmt.objid가 'CM-' prefix varchar라 bigint cast 불가
  · 데이터 0건 무손실, ECR/CS는 bigint→varchar 자동 cast로 무영향
- approvalTableMigration.ts 동기화

[운영 배포 환경변수 — wace Constants 1:1 default 박힘]
- AMARANTH_OUT_PROCESS_CODE=RPSPLM_00001 (wace Constants.java:81)
- AMARANTH_FORM_ID_CONTRACT_ORDER=1161 (wace orderMgmtList.jsp:558)
- AMARANTH_COMP_SEQ=1000 (wace orderMgmtList.jsp:559)
- 3개 docker-compose(deploy/onpremise, docker/deploy, docker/prod) 모두
  ${VAR:-default} 형식으로 매핑 — 호스트 .env 미설정 시 default 동작

[검증]
- G9: BEGIN/ROLLBACK으로 26C-0800(라인 3건) 복사 시뮬레이션 — 헤더 23컬럼 1:1,
  채번 26C-0803, 라인 3→3건 + seq 보존
- G11: 4단계 상태 라벨(create→inProcess→complete→reject) 모두 정상,
  VARCHAR PK(CM-... prefix) JOIN도 정상
- 문서: docs/migration/sales/06-copy-order-verify.md, 07-amaranth-approval-verify.md
- GAP: G9 , G10 (영업 GAP 아님 — Admin 도메인), G11 

[운영 트러블슈팅 노트 — 07-verify.md 트러블슈팅 섹션]
dev에서 amaranth 측이 "API Proxy 호출 시 유효한 레디스 값이 존재하지 않습니다"로
거부. 우리 코드는 정상 — 'Amaranth - 결재' accessToken을 amaranth 서버 측
Redis에 등록받아야 동작. chpark/RPS ERP 담당자 협조 영역(코드 변경 없음).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:44:54 +09:00
chpark a61643c216 Merge remote-tracking branch 'origin/main'
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2026-05-11 17:00:38 +09:00
hjjeong 902118d46e PR-C G6 견적관리 SMTP 메일 발송 (wace sendEstimateMailCustom 1:1)
- nodemailer + pdf-lib로 실제 SMTP 발송. mail_log INSERT(is_send='N') → 발송 → 성공 시 UPDATE(is_send='Y'), 실패 시 UPDATE(error_log). SMTP_SEND_SWITCH='N'면 발송 스킵.
- SMTP 3계정(ERP/SALES/PURCHASE) host/user/pw 환경변수 분리. 견적서는 SALES. dev는 backend-node/.env, 운영은 deploy/onpremise + docker/prod + docker/deploy 3개 compose에 environment 매핑(호스트 .env에서 실값 주입).
- 다이얼로그(EstimateMailDialog): wace estimateMailFormPopup.jsp 1:1. 고객사 담당자 체크박스 + To/CC/제목/내용 자동채움(GET /sales/estimate/mail-info/:id + .../customer/:id/managers). hasBaseEst/hasAddEst 분기로 PDF 첨부 안내. 본문은 다이얼로그 plain text 입력 → <br> 변환.
- PDF 첨부: 메일 다이얼로그가 hidden iframe으로 최신 차수 template1/2 페이지를 렌더 → window.fn_generateAndUploadPdf(cb) 글로벌 → jsPDF.output('datauristring') base64 추출 → 한 요청에 전달. backend가 견적 PDF + estimate02 N건 pdf-lib로 합본 첨부.
- PDF 캡처 수신처 누락 픽스: CustomerSelect의 /sales/customers 옵션 fetch가 iframe에서 dataLoaded=true 뒤에 끝나 셀렉트 라벨이 빈 상태로 캡처되던 현상. fetchCustomers export + template1/2 setLoading(false) 직전 await + onclone에서 [role="combobox"] 라이브 DOM 텍스트 fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:09:10 +09:00
chpark 690b85805c ECR 기능/스키마 wace_plm 일치 + 공통코드·테이블타입 화면 정리
- ECR 관리: wace 의 ecrList/Form/Detail JSP 와 동일하게 5개 필터(연도/기종/요청/작성자/상태),
  변경전/후 2분할 모달, 작성중(0000100)만 삭제·수정 허용, 컬럼 순서/라벨 wace 일치
- ECR 스키마 wace 풀세트 동기화: ecr_mng 컬럼폭 확장, product_mgmt 16컬럼, part_mng 52컬럼,
  user_info 22컬럼, comm_code 보강(id/code_cd/ext_val), code_name(varchar) 함수,
  seq_ecr_no setval(33) 정렬
- wace_plm public.comm_code 733행 시드: src/seed/wace_comm_code.sql 추출 + 부팅 시 자동 적재
  (writer='system-seed' placeholder 자동 정리, 무중단 재적재 엔드포인트 /comm-code-seed)
- wace_plm 데이터 import 풀스키마: PRODUCT(7→16), PART(6→52), USER_INFO·COMM_CODE 신규
- 공통코드 관리 화면: 제목/설명 축소, 카테고리·코드 카드 → 컴팩트 리스트, 활성 토글 점,
  계층 배지 톤다운, hover 시 액션 노출
- 테이블 타입 관리 — 좌측: 한 줄 리스트 + 알파벳 인덱스 sticky 헤더
- 테이블 타입 관리 — 우측: 타입 카드 그리드 → 그룹 셀렉트(기본/참조/자동/첨부/표시변형),
  표시이름 제거 + 코멘트(description) Textarea 신설(화면관리에서 기본 라벨로 활용),
  시스템 자동 생성 컬럼(id/company_code/writer/created_date/updated_date) 잠금,
  표시옵션/고급설정(필수·읽기·기본값·최대길이) 제거 — 화면관리로 이관

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:58:54 +09:00
hjjeong 0afa8b03cf 견적서 자동 채움 보강 + 시행일자 picker 형식 정정
1) getById 응답 구조 fix
   - salesEstimateService.getById는 { ...contract_mgmt 헤더, items } 평면 객체 반환
   - 페이지가 contractInfo.header.customer_objid로 잘못 접근해 고객사·환율·통화 자동 채움이 안 됐던 버그
   - contractInfo.customer_objid 직접 접근으로 수정 (template1·template2 동일)

2) /auth/me 응답에 cellPhone/tel 추가
   - AuthService.getUserInfo는 이미 두 필드 반환하나 authController가 응답에서 누락
   - 견적서 연락처가 wace MailUtil 패턴(cell_phone 우선 → tel 폴백)으로 자동 채워지도록 노출

3) 시행일자 picker 표시 형식 정정
   - input[type="date"]는 한국 Chrome이 "YYYY. MM. DD." 강제 (CSS 변경 불가)
   - text input + hidden type=date 조합: 표시는 YYYY-MM-DD, 클릭 시 hidden picker showPicker() 트리거
   - template1 executor + template2 executor_date 모두 적용

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:07:25 +09:00
hjjeong f88c5e3e40 견적서 담당자/연락처 자동 채움 (wace estimateTemplate1.jsp ready 1:1)
신규 작성 시 useAuth로 로그인 사용자 정보 자동 채움:
- 담당자 = "{deptName} {userName}" (wace: connectUserDeptName + connectUserName)
- 연락처 = user.tel (wace: cell_phone || tel)

조건: templateObjid 없는 신규 작성 + 사용자가 아직 입력하지 않은 빈 값에만 채움.
기존 견적서 수정 모드는 DB 값 우선 (manager_name/manager_contact).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 14:42:36 +09:00
hjjeong 8fdc42df79 PR-C G5-B 일반 견적서 PDF 다운로드 (html2canvas-pro + jspdf)
- frontend deps: html2canvas-pro@^2.0.2, jspdf@^3.0.4
- template1 페이지 "PDF 다운로드" 버튼 → wace fn_generatePdf 1:1 포팅
  · 클라이언트 dynamic import (SSR 회피)
  · html2canvas-pro 캡처 (scale 2, JPEG 0.85) → jsPDF A4 페이지 분할 → save({estimateNo}.pdf)
  · onclone 콜백에서 input/textarea/select → 텍스트 노드로 교체 (글자 잘림 방지)
  · .no-print, .btn-area, 삭제버튼은 클론에서 숨김
- html2canvas-pro 사용 이유: Tailwind 4 oklab/oklch CSS color function 지원
  (기존 html2canvas 1.4.1은 "Attempting to parse an unsupported color function 'oklab'" 에러)

장비 견적서(template2)는 wace 원본부터 PDF 다운로드 버튼이 없어 그대로 유지.
메일 발송용 PDF 합본은 G6 SMTP 묶음에서 처리.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 14:32:29 +09:00
hjjeong 844216c298 PR-C G5-A 견적작성 페이지(일반 template1 + 장비 template2) 1:1 이식
- 백엔드: saveEstimateTemplate1/2 + getTemplateById + listTemplatesByContract
- 라우트: POST /api/sales/estimate/template1·template2, GET /template/:id, /templates/:contractObjid
- 프론트 페이지 /estimate/template{1,2}/pop/[contractObjid]
  · template1: wace estimateTemplate1.jsp 1:1 (헤더·라인·합계·비고·참조사항)
  · template2: wace estimateTemplate2.jsp 1:1 (CNC + 7개 기본 카테고리 + group1 공유 subtotal + 비고 contenteditable + 카테고리 동적 추가/삭제)
  · /pop/ 세그먼트로 (main)/layout.tsx isPop 분기에 걸려 새 창에서 사이드바·탭바 우회
  · 다크모드에서 견적서 양식 검정 텍스트 강제
- 진입점: 견적관리 그리드 "견적작성" → 일반/장비 선택 다이얼로그 → window.open 새 창
- 견적현황(폴더) 컬럼 클릭 → 차수 리스트 다이얼로그 (wace fn_showEstimateList)
- 회사 도장 PNG (wace_plm/WebContent/images/company_stamp.png 1:1 복사, .gitignore *.png 우회 -f)

PDF 다운로드(html2canvas+jspdf) + 메일 PDF 합본은 G5-B 별도 PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 14:08:33 +09:00
hjjeong fa2f232924 주문관리 수주등록 폼 분기 — wace orderRegistFormPopup 1:1 별도 컴포넌트
- 견적요청에서 시작된 행(is_direct_order != 'Y')은 별도 다이얼로그(OrderRegistDialog)
  · 헤더 4개(발주번호/발주일*/견적환종/견적환율)
  · 라인은 contract_item 자동 로드, 추가/삭제 불가
  · 입력은 제품구분 + ORDER_*(수주수량/단가/공급가액/부가세/총액)만
  · 자동계산(수량×단가→공급가액, ×10%→부가세, 공급+부가세→총액)
  · Total 합계 행
- 통합폼은 항상 is_direct_order='Y' 케이스만 노출 — 토글 로직 제거
- list SQL/OrderRow에 is_direct_order 노출 (행 분기 판별용)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 11:12:23 +09:00
hjjeong 12c23d2cb6 주문관리 수주입력 보강: 자동계산 + 행 선택 시 수정 분기 + is_direct_order 따라 폼 모드
- 라인 자동계산 (wace fn_calculateItemAmount / fn_calculateFromSupplyPrice / fn_calculateTotalFromVat 이식)
  · 수량/단가 → 공급가액 = 수량×단가, 부가세 = round(공급가액×0.1), 총액 = 공급가액+부가세
  · 공급가액 직접 → 부가세/총액 재계산
  · 부가세 직접 → 총액만 재계산
  · 총액 직접 → 영향 없음 (수동)
- 수주입력 버튼 분기: selected 없으면 신규(openCreate), 있으면 수정(openEdit). 라벨 자동 토글 ("수주입력" ↔ "수주수정"). 기존 별도 "수정" 버튼 제거.
- 다이얼로그 모드 분기 (is_direct_order):
  · 'Y' (수주통합등록/수정): 라인 13컬럼 + ORDER_* 5개 + Total 합계 행
  · 'N' (견적관리에서 온 견적단계 행): 라인 8컬럼 + ORDER_* 5개·Total 숨김 (견적요청수정 폼)
- openEdit에서 product / return_reason / master_part_no/name fallback 추가

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:52:47 +09:00
hjjeong 0a97f2ec38 S/N 관리·연속번호생성 Dialog 모두 onInteractOutside 차단 (자식 Dialog 닫힘 시 부모 도미노 차단 완성)
이전 커밋에서 메인 등록 Dialog에만 onInteractOutside 추가 — 자식(S/N)·손자(연속번호) Dialog가 닫힐 때 이벤트가 메인까지 도미노로 전파되며 여전히 메인이 닫혔음.

해결: nested Dialog 4개(견적/주문 각각 S/N + 연속번호) 모두에 onInteractOutside={(e) => e.preventDefault()} 추가.
사용자는 X / 취소 / 확인 / 생성 버튼으로만 명시적으로 각 Dialog 닫음.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:39:49 +09:00
hjjeong 447090faca 견적/주문 등록 다이얼로그: 자식 S/N·연속번호 Dialog 닫힐 때 부모 Dialog까지 닫히는 현상 차단
Radix Dialog 알려진 이슈 — nested Dialog 닫힐 때 PointerDown 이벤트가 부모로 전파되어 outside click으로 인식, 부모 Dialog도 함께 닫힘.

수정:
  <DialogContent onInteractOutside={(e) => e.preventDefault()}>
  → 외부 클릭으로 부모 닫힘 차단. 사용자는 X / 취소 / 저장 버튼으로만 닫음.
  ESC는 그대로 — Radix focus stack이 자식만 먼저 닫음.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:35:41 +09:00
hjjeong ae5ef8f7e5 주문서 수주통합등록 다이얼로그 wace G2 1:1 재작성
기존 RPS 폼이 wace estimateAndOrderRegistFormPopup과 크게 어긋남(헤더 항목 잘못 배치 + 라인 누락). 통째 재작성.

수주통합 기본정보 — wace 헤더 9개 정확 일치:
  영업번호(자동채번) / 주문유형* / 국내해외* / 고객사* / 유무상* / 접수일* / 견적환종 / 견적환율 / 발주번호 / 발주일*
  (이전 RPS의 요청납기/통화/수주상태/담당자(PM ID)/출하방법/고객사요청사항 헤더 배치 폐지 — wace 통합폼에 없음)

품목정보 — wace 라인 13컬럼 + Total 합계 행:
  No / 제품구분* / 품번* / 품명* / S/N / 요청납기 / 고객요청사항 / 반납사유 / 수주수량* / 수주단가 / 수주공급가액 / 수주부가세 / 수주총액 / 삭제
  (이전 누락: 제품구분 / S/N / 요청납기 / 고객요청사항 / 반납사유)

추가 컴포넌트:
- 품번/품명: PartSelect (part_mng 8,176건 검색 + 자동 매핑)
- 제품구분/반납사유: CommCodeSelect (0000001 / 0001810)
- S/N: 별도 다이얼로그(테이블 + 연속번호생성) — wace fn_openItemSnPopup / fn_openItemSequentialSnPopup 1:1
- 합계: useMemo로 라인 수량/공급가액/부가세/총액 실시간 집계

EMPTY_ITEM 라인 기본값에 product/serials/due_date/return_reason/customer_request 추가.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:24:25 +09:00
hjjeong 7c03907000 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>
2026-05-11 10:17:04 +09:00