Commit Graph

3066 Commits

Author SHA1 Message Date
hjjeong b38f5957f2 구매관리 7메뉴 신규 + M-BOM PR-B3·B5 + 발주관리 DataGrid 통일 + 생산계획&실적 라우트
구매관리 (wace 1:1)
- backend: services/purchaseService.ts (7 list + 옵션 3종) + controllers/purchaseController.ts + routes/purchaseRoutes.ts (/api/purchase 마운트)
- frontend: lib/api/purchase.ts + 7 page.tsx (list/quote-request/proposal/inbound/inbound-by-item/inbound-by-date/project-status)
- 영업관리 4메뉴 DataGrid 패턴 통일 — pageSizeOptions=[10,15,20,50,100], emptyMessage, showColumnSettings/summaryStats/onRefresh/onDownload/showChart
- 마스터단독 데이터(sales_request_master, project_mgmt+mbom_detail) 노출, detail/part 누락 테이블 의존은 빈 그리드 + UI

발주관리 (purchase/order/page.tsx)
- EDataTable → DataGrid 교체 + logicstudio 6종 props + 날짜/숫자 pre-format

M-BOM PR-B3 — 구매리스트 생성 (wace createPurchaseListFromMBom.do 1:1)
- mbomService.createSalesRequest + controller + route POST /api/production/mbom/sales-request
- 단건 체크 + 1:1 강제 + R-YYYYMMDD-NNN 채번 + sales_request_master 단건 INSERT
- production/mbom/page.tsx 에 [구매리스트 생성] 버튼

M-BOM PR-B5 — BOM 할당 (mBomEbomSelectPopup.do)
- mbomService.searchAssignableEboms/assignBom + controller + routes
- MbomAssignDialog 신규, MbomDetailDialog 통합

생산관리 4메뉴 라우트 (생산계획&실적, 소요량)
- prodPlanResultService/Controller + productionPlanResultRoutes (planResult/mbomReq)
- mbomRequirementService + 4 page.tsx (prod-plan-result, prod-plan-result-equip, raw-material-requirement, semi-product-requirement)
- lib/api/prodPlanResult.ts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 17:31:12 +09:00
hjjeong dee03f6024 생산관리 M-BOM PR-B2 — 본 편집 다이얼로그 행 추가/삭제 (팝업 방식)
행 추가: MbomAddPartDialog 신설 (devPartApi.list 재사용)
  · 품번/품명 검색 + 체크박스 multi-select + 페이지네이션
  · 선택 행 1개면 그 자식으로 추가, 없으면 root (level=1)

편집 모드 확장 (MbomDetailDialog):
  · 체크박스 컬럼(맨 왼쪽) + 전체 선택 토글
  · 선택 행 파란 배경, 새 행 초록 배경 (temp- prefix 식별)
  · toolbar [+ 행 추가] / [선택 삭제] 버튼 추가
  · 선택 삭제 — cascade(선택 + 하위) + 확인창

backend save() UPDATE 분기:
  · client temp- child_objid → 서버 발급 createObjId 매핑
    (객체 ID 안정성 + DB 에 임시 ID 잔존 방지 + 충돌 회피)
  · parent_objid 가 temp- 참조면 신규 ID 로 remap

운영판은 좌(M-BOM)+중앙(<<,>>,변경)+우(소스 트리) 3분할이지만
좌측 19컬럼이 좁아져 가로스크롤 강제되는 약점. 팝업 방식이
트리 풀너비 확보 + 모바일 친화 → 사용자 결정으로 팝업 채택.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 16:59:29 +09:00
hjjeong 8dd5f184ae 생산관리 M-BOM 변경이력 다이얼로그(PR-B4) + 그리드 컬럼 폭 다듬기
운영 productionplanning.getMbomHistory (3448~3470) 1:1 이식:
  · backend mbomService.getHistory(projectObjid) — project 단위 mbom_header 변경이력
    시간순 최신 우선, USER_INFO join 으로 변경자명 함께
  · GET /api/production/mbom/history/:projectObjid
  · frontend MbomHistoryDialog — 5컬럼 그리드(변경일시/유형/내용/변경자/M-BOM품번)
    CREATE=파란 뱃지, UPDATE=황색 뱃지, max-w-900px
  · MbomDetailDialog toolbar 에 "변경이력" 버튼 (편집 모드 아닐 때만 노출)

PR-B1 의 history 저장 결과를 사용자가 직접 확인할 수 있도록 보는 화면 마무리.

부수: production/mbom/page 그리드 컬럼 폭 정돈 + summaryStats(전체/페이지/수주합/M-BOM 비율).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 16:39:48 +09:00
hjjeong a6692c4e21 생산관리 — M-BOM 관리에 logicstudio 스타일 DataGrid 적용
PR-B1(7a7f4f03)에 이미 들어간 서버 페이지네이션 + folder 컬럼은 유지하고,
영업관리/개발관리 패턴의 toolbar + 통계만 얹는다.
구매관리 mbom 메뉴는 production/mbom 페이지 re-export 이므로 자동 적용.

추가 DataGrid props:
- showColumnSettings · summaryStats · showChart
- onRefresh = fetchList · onDownload = exportToExcel(현재 페이지 행만, 라벨 매핑)
- systemColumnKeys=["writer_name","mbom_regdate"]

summaryStats (페이지 기준 + 서버 total):
- 전체 건수(서버 total) / 페이지 건수 / 수주수량 합계 / M-BOM 저장 비율(N/M + %)

부수 정리:
- 부모 wrapper 영업관리 통일: flex h-full flex-col overflow-hidden p-2 gap-2
  + DataGrid 직접 자식으로 (min-h-0 flex-1 wrapper 제거)
- 컬럼 폭: ⋮⋮ 핸들 추가로 좁아진 4글자 한국어 라벨을 100~125px 로 보정

서버 페이지네이션 모드라 onDownload 는 현재 페이지만 export.
전체 export 가 필요하면 별 endpoint(서버에서 페이징 없는 전체 응답)와 함께 추가 가능.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 16:30:51 +09:00
hjjeong 7a7f4f03b5 생산관리 M-BOM 본 편집(PR-B1) + 폴더 컬럼 + DataGrid 서버 페이지네이션 + bigint=varchar fix
PR-B1 본 편집/저장 (운영 saveMbom.do 1:1)
  · 매퍼 7종 1:1 (insert/updateMbomHeader, insert/updateMbomDetail,
    deleteMbomDetailByObjid, insertMbomHistory, updateProjectMbomStatus)
  · 신규 CREATE: createObjId + generateMbomNo(M-{partNo}-YYMMDD-NN) +
    child_objid 재매핑 + detail 일괄 insert + history(CREATE) + project_mgmt.mbom_status='Y'
  · 수정 UPDATE: 기존 mbom_header.objid UPSERT(insert/update/delete) + history(UPDATE)
  · POST /api/production/mbom/save (BEGIN/COMMIT/ROLLBACK 트랜잭션)
  · MbomDetailDialog: '본 편집' 토글 + 13개 셀 인라인 편집 + 저장/취소 가드

M-BOM 컬럼 폴더 아이콘
  · production/mbom/page.tsx: mbom_status 컬럼 → mbom_has(0/1) renderType=folder
  · onClick → MbomDetailDialog 오픈 (행 더블클릭도 그대로 유지)
  · 운영판 wace 견적/partMng 폴더 아이콘 패턴 1:1

DataGrid 서버 페이지네이션
  · props 신설: serverPaging/serverPage/serverPageSize/serverTotalItems
    + onPageChange/onPageSizeChange
  · 5메뉴 적용: production/mbom, development/change-list/ebom-regist/part-search/part-regist
  · pageSizeOptions=[10,15,20,50,100,200,500] 통일
  · 클라이언트 모드 하위호환 유지

bigint=varchar fix (mbom 트리 SQL 4종)
  · ATTACH_FILE_INFO 서브쿼리: P.OBJID(bigint) = F.TARGET_OBJID(varchar) → P.OBJID::varchar 캐스트
  · EBOM_WORKING_TREE_SQL INNER JOIN: P.OBJID = COALESCE(V.LAST_PART_OBJID,V.PART_NO) → ::varchar 캐스트
  · 사용자 보고: 폴더 클릭 시 'operator does not exist: bigint = character varying' 토스트

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 16:26:20 +09:00
hjjeong 3a5bcb5e3a 공용 — getDirectFileUrl 로컬 origin 을 NEXT_PUBLIC_API_URL fallback 으로
localhost/127.0.0.1 일 때 하드코딩된 http://localhost:8080 대신
NEXT_PUBLIC_API_URL 의 origin(/api suffix 제거) 을 우선 사용.
환경변수 없을 때만 기존 http://localhost:8080 으로 떨어짐.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 16:09:05 +09:00
hjjeong c955fe0dac 개발관리 — 5메뉴(PART/E-BOM/EO이력)에 logicstudio 스타일 DataGrid 적용
영업관리/프로젝트관리 패턴(fc959d88·6a181371)을 개발관리 5메뉴 전체로 확장.

공통 변경:
- 부모 wrapper 영업관리 통일: flex h-full flex-col overflow-hidden p-2 gap-2
  + DataGrid 를 직접 자식으로 (불필요한 min-h-0 flex-1 wrapper 제거)
- DataGrid props 확장:
  - showColumnSettings · paginationStyle="range" · pageSizeOptions=[10,15,20,50,100]
  - onRefresh = fetchList(또는 runQuery) · onDownload = exportToExcel(GRID_COLUMNS 라벨 매핑)
  - showChart
- 컬럼 폭: ⋮⋮ 드래그 핸들 추가로 좁아진 4글자 한국어/영문 라벨을 95~125px 로 보정

메뉴별 summaryStats:
- PART 등록(M1): 전체·페이지 건수 / 환산수량·개당수량·BOM 수량 합계
- PART 조회(M2): 전체·페이지 건수 / BOM 수량·환산수량·개당수량 합계
- E-BOM 등록(M3): 전체·페이지 건수 + 상태별(status_title) 분포 4종
- E-BOM 조회(M4): 모드(정/역전개) + 표시·원본 행 + MAX_LEVEL + 수량·항목수량 합계
- 설계변경 리스트(M5): 전체·페이지 건수 / 수량·변경수량 합계

systemColumnKeys 분리 (컬럼 설정의 데이터/시스템 그룹 구분):
- PART 등록: revision, status
- PART 조회: revision, eo_no
- E-BOM 등록: dept_user_name, reg_date, deploy_date, revision, status_title
- 설계변경: writer_name, his_reg_date_title

id 매핑 누락 보강 (350ddcd3 함정 재발 방지):
- ebom-search: gridData 에 child_objid 또는 인덱스 fallback id 부여
- change-list: rows 에 objid 또는 인덱스 fallback id 부여
- (PART/E-BOM 등록은 이미 gridRows 매핑 있음)

E-BOM 조회 특수:
- defaultPageSize=100, pageSizeOptions=[20,50,100,200,500] — BOM 트리 가독성
- onDownload 는 PageHeader 의 정/역전개 엑셀 버튼과 동일 동작(현재 direction)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:23:33 +09:00
hjjeong 350ddcd3b8 프로젝트관리 — DataGrid 행 id 매핑 누락 + selectedId 가드
증상:
프로젝트관리 진행관리/WBS 그리드의 모든 행이 회색(bg-accent) 으로 표시.
원인 추적 결과 DataGrid 의 isSelected 평가식 `selectedId === row.id` 가
selectedId 도 row.id 도 둘 다 undefined 일 때 `undefined === undefined` = true
가 되어 모든 행이 selected 상태로 잡힘 (memory: feedback_datagrid_id_mapping
함정의 또 다른 발현 — 영업관리는 항상 id 매핑이 있어 우연히 회피).

수정:
- project/progress/page.tsx, project/wbs-template/page.tsx
  - setRows 에서 `id: r.objid ?? "...-${i}"` 매핑 추가
  - 부모 wrapper 도 영업관리 패턴 `overflow-hidden` + DataGrid 직접 자식으로 통일
- components/common/DataGrid.tsx
  - isSelected 가드 — selectedId/row.id 가 nullish 면 무조건 false 처리.
    향후 다른 페이지에서 id 매핑 누락 시에도 그리드 색 폭주는 차단.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 15:12:34 +09:00
hjjeong 6a1813719a 프로젝트관리 — 진행관리/WBS템플릿에 logicstudio 스타일 DataGrid 적용
영업관리(fc959d88)와 동일 패턴을 프로젝트관리 2개 메뉴로 확장:

공통 DataGrid props:
- gridId 는 기존(project-progress-wbslist3 / project-wbs-template) 그대로 유지
- showColumnSettings, paginationStyle="range", pageSizeOptions=[10,15,20,50,100]
- onRefresh = fetchList(혹은 fetchList(filterProduct)), onDownload = exportToExcel(라벨 매핑)
- showChart

도메인별 summaryStats:
- 진행관리: 프로젝트 건수 / 수주수량 합계 / 입고율 평균(% 문자열 파싱)
- WBS 템플릿: 템플릿 건수 / WBS 작업 합계 / 평균 WBS 작업수

WBS 템플릿 systemColumnKeys: writer_title, reg_date_title (등록자/등록일 시스템 영역)

컬럼 폭 보정:
- ⋮⋮ 드래그 핸들 추가로 좁아진 4글자 한국어/영문 라벨 95~120px 로 확대
- 진행관리: 주문유형·제품구분·국내/해외·요청납기·E-BOM·M-BOM·제조1,2팀·제조3팀 등
- WBS: WBS 컬럼 100→115, 등록일 130→140

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 14:56:54 +09:00
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