501 Commits

Author SHA1 Message Date
hjjeong e51f5f7b69 구매관리 입고관리 입고등록 + 입고일별 마감정보입력 + 매입마감
- backend purchaseInboundService 신설 — getInboundFormInit / saveInboundForm
  (arrival_plan UPSERT 트랜잭션) / saveDeadlineInfo (8필드 일괄 UPDATE) /
  closeArrival (이미 마감된 건 차단) + listWarehouseOptions / listAcctCodeOptions
- backend routes — GET /inbound-form/:pomObjid / POST /inbound-form/save /
  POST /arrival/deadline / POST /arrival/close + 옵션 2개
- InboundFormDialog 신설 — wace deliveryAcceptanceFormPopUp_new.jsp 1:1
  (좌 발주품목 read-only + 우 차수별 입고입력 + 미입고 일괄적용)
- DeadlineInfoDialog 신설 — wace swal 모달 1:1 (8필드 일괄, 단건 시 prefill)
- inbound 페이지 입고등록 / inbound-by-date 마감정보입력+매입마감 연결
- 입고등록 master SELECT 함정 수정 — RPS 에 POM.delivery_status 없어 reception_status fallback
- DataGrid 다중 frozen 누적 left 계산 인프라 추가 (frozenLeftPx props 보강)
  — shadcn Table 기반이라 진짜 column pinning 불가 (자연 위치 도달 후 sticky),
    입고 3페이지의 frozen 부여는 일단 제거. 진짜 pinning 은 별도 작업
2026-05-20 10:04:39 +09:00
hjjeong 17b08c7a09 구매관리 발주서 메일 발송 + PDF 다운로드 + 행추가/삭제 제거
- backend purchaseOrderMailService 신설 — getOrderMailInfo / getPartnerManagerList /
  sendOrderMail (SMTP PURCHASE, 발송 성공 시 mail_send_yn='Y'/mail_send_date 갱신)
- backend routes — GET /order-form/mail-info/:objid, POST /order-form/mail,
  GET /options/partner-managers/:partnerObjid
- frontend lib/utils/purchaseOrderPdf — html2canvas-pro + jsPDF (A4, scale=2,
  input/textarea → 텍스트 변환). download:true 면 파일 저장, 아니면 base64 반환
- PurchaseOrderMailDialog 신설 — EstimateMailDialog 패턴 단순화 (한글/영문 본문 분기,
  공급업체 단일 email 자동 채움)
- 3개 양식 다이얼로그 — 읽기전용 + 저장된 발주서일 때 "메일 발송" + "PDF 다운로드"
  버튼 노출. window.print 간이판 제거
- 3개 양식 다이얼로그 — "행 추가"/"선택 행 삭제" 버튼 + 그리드 체크박스 컬럼 제거
  (wace 운영판은 모두 주석 처리/부재. 발주서는 품의서에서 자동 채움된 품목 그대로 사용)
2026-05-19 14:57:47 +09:00
hjjeong e48bd83667 구매관리 발주서 폼 저장/삭제 + general 양식 다이얼로그
- 백엔드: POST /api/purchase/order-form/save (마스터 55 + 파트 40 컬럼 UPSERT + 삭제파트 cascade, 트랜잭션, wace mergePurchaseOrderMaster/PartInfo 1:1)
- 백엔드: DELETE /api/purchase/order-form/:objid (마스터+파트 cascade)
- 프론트 lib/api: initOrderForm/getOrderForm/saveOrderForm/deleteOrderForm
- 프론트 컴포넌트: PurchaseOrderGeneralFormDialog — wace purchaseOrderFormPopup_general.jsp 1:1 (좌 5필드/우 담당자 + 회사정보 2줄/그리드 10컬럼/총공급가액/보안문구)
- /purchase/proposal "발주서생성" 버튼 활성화 → 품의서 자동 채움 다이얼로그
- /purchase/order 행 클릭/체크 → 수정/삭제 액션 + 다이얼로그
- Radix UI 접근성: DialogTitle/Description sr-only 처리

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 13:06:18 +09:00
hjjeong 6f73631c7c 구매관리 발주서관리 통합 + 폼 GET API + PageHeader 컨벤션
발주서관리 리스트:
- /purchase/order-wace 임시 라우트 → /purchase/order 통합 (기존 vexplor
  변형판 대체). order-wace 폴더 삭제.
- 백엔드 라우트 /order-wace → /order-list, 함수 listPurchaseOrderWace →
  listPurchaseOrderList, API 클라이언트 listOrderWace → listOrder.

발주서 폼 (general 양식) GET API:
- services/purchaseOrderFormService.ts 신규 (getPurchaseOrderFormInit,
  getPurchaseOrderForm). 품의서 자동채움 = salesMng.getProposalPartList
  매퍼 1:1 → 발주 그리드 형식 변환. 발주번호 채번 RPS{YY}-{MMDD}-{NN}.
- 컨트롤러/라우트: GET /api/purchase/order-form/init?proposal_objid=...
  + /api/purchase/order-form/:objid.
- RPS는 OBJID가 varchar라 wace numeric 캐스트 모두 제거.

PageHeader 컨벤션 일괄 변경:
- 자동매칭이 매칭된 menu의 parent_obj_id로 부모를 찾아
  "{부모}_{자식}" 형식 표기 (wace 컨벤션). 부모가 루트 그룹이면 자식만.
- description prop과 렌더링 완전 제거 (사용처 없음 확인).
- 모든 메뉴 페이지에 일괄 적용.

DB(별도): menu_info 9857401373575 + rel_menu_auth 3건 제거.
저장/삭제 API + 프론트 다이얼로그는 다음 세션.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 11:47:38 +09:00
hjjeong aacbb62ad8 자재관리 2메뉴 풀-CRUD + 액션 (자재리스트 + 불출의뢰서)
- 신규 테이블 5종 (운영 11133 → RPS 11134 DDL 1:1):
  inventory_mgmt / inventory_mgmt_in / inventory_mgmt_out /
  inventory_mgmt_out_master / inventory_mgmt_history
- 백엔드 /api/inventory-mng — 리스트·재고등록·자재이동·삭제·이력 +
  불출의뢰 생성·접수·자재불출(재고 차감)·삭제. 채번 Rfw-YYYY-seq.
- 프론트 /COMPANY_16/material/{list, issue-request} +
  StockRegister / MaterialMove / IssueRequestCreate /
  InventoryHistory / IssueDispatch 다이얼로그 5종.
- AdminPageRenderer 등록 + /material/ prefix.
2026-05-19 11:25:15 +09:00
hjjeong 1b1231d9a9 구매관리 발주서관리 wace 1:1 리스트 페이지 진입
기존 /purchase/order(vexplor 변형판)는 보존하고 wace_plm purchaseOrderList_new
1:1 재이식을 /purchase/order-wace 로 분리 진입. 백엔드 listPurchaseOrderWace
(purchaseOrderMasterList_new 매퍼) + 15개 검색필터/그리드 컬럼 매핑.

- services/purchaseService.ts listPurchaseOrderWace 추가 (POM + APPROVAL/ROUTE
  + PROJECT_MGMT + SALES_REQUEST_MASTER 조인, mail_send_yn 3분기, MULTI 마스터
  필터 등 wace 매퍼 본문 1:1)
- controllers/purchaseController.ts + routes/purchaseRoutes.ts wire-up
  (GET /api/purchase/order-wace)
- lib/api/purchase.ts listOrderWace + category_cd 필드
- app/(main)/COMPANY_16/purchase/order-wace/page.tsx 신규 — wace JSP 검색폼
  2행(14필드) + 그리드 15컬럼, comm_code 그룹 0000167/0000001/0001814 옵션 로딩

DB 마이그레이션(별도): menu_info objid=9857401373575 + rel_menu_auth 3건은
별 세션의 메뉴 동기화 흐름 사용.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 16:28:11 +09:00
hjjeong 6b029e20f9 구매관리 견적요청서 빈 그리드 채움 (quotation_request_master/detail 신설)
- DDL: quotation_request_master(14 cols) + quotation_request_detail(15 cols)
  운영 → RPS 타입 차이: numeric objid → varchar(64), detail.part_objid bigint(part_mng FK)
- 데이터: 운영 sample master 4건 / detail 4건 (sales_request_part 미존재 → NULL fallback)
- 백엔드 listQuotationRequest — wace salesMng.xml:5248-5349 매퍼 1:1
  (vendor → client_mng JOIN, attach_file_info QUOTATION_RECEIVED 카운트)
- listVendorOptions(client_mng) 신규 — 발주서 vendor 옵션이 supply_mng 와 분리됨
- listPurchaseRequest.has_quotation_request 분기 활성화
- quote-request page.tsx UI 문자열 내부 참조 제거, vendor 옵션 client_mng 로 교체
2026-05-15 15:32:05 +09:00
hjjeong 0658630c68 Merge remote-tracking branch 'origin/main' into hjjeong
# Conflicts:
#	frontend/components/common/CompactFilterBar.tsx
2026-05-15 14:55:52 +09:00
hjjeong 1fb438bdcb 공용 DateInput + DataGrid 헤더 가독성 + 구매요청서 수정모드/공급업체 옵션
- 공용 DateInput (YYYY-MM-DD 통일): text input + Popover Calendar,
  숫자 8자리 자동 - 삽입. CompactDateRange / 다이얼로그 입고요청일 적용.
- DataGrid 헤더 라벨 truncate + TableHead 패딩 축소(!px-1.5):
  좁은 컬럼에서 라벨 겹침/잘림 해소.
- 구매요청서관리 그리드 컬럼 너비 합리화 (총 ~300px 절감)로 품명까지
  화면 안에 표시.
- 구매요청서 수정모드: 선택 1건 시 [구매요청서수정] 분기 →
  getDetail 로 헤더/라인 채워 다이얼로그 오픈. 확정·품의서생성 가드.
- 공급업체 옵션을 client_mng 기반 listVendorOptions 로 신설
  (운영 supply_mng=0 / client_mng=8946, M-BOM vendor 매칭).
- 주문유형 CommCodeSelect groupId 0000005 → 0000167 (계약구분).
- 고객사 셀렉트 → CustomerSelect 공용 컴포넌트로 교체.
- 그리드 delivery_request_date 점 형식 → YYYY-MM-DD 정규화.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:40:28 +09:00
hjjeong 75f4ca8127 영업관리 구매요청 2메뉴 액션 완성 + SmartSelect 키보드 네비
- sales_request_part DDL 추출(운영 11133)→RPS(11134) 마이그레이션
- 백엔드 6 엔드포인트: 프로젝트 자동채움/M-BOM 품목/저장/품의서생성/SSO
  · 품의서 결재상신 Amaranth SSO (target_type=PROPOSAL, formId=1163)
- 프론트 다이얼로그 2개 (구매요청서작성 / 품의서생성 확인)
  · 프로젝트 선택→주문유형·제품구분·국내외·고객사·유무상 자동 채움
  · 행추가 시 M-BOM 품번 셀렉트→품명/공급업체/단가 자동 셋팅
- 공용 SmartSelect: ↑↓·Enter·Esc·Home·End·PageUp·Down 키보드 네비
- 그리드 delivery_request_date . → - 형식 정규화

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 14:01:26 +09:00
chpark c74e742b6f 품질관리 4메뉴 — wace_plm JSP + quality.xml MyBatis 1:1 재정합
Build and Push Images / build-and-push (push) Has been cancelled
수입검사 요청 (incoming-request):
 - 필터 12종 (품의서/발주서/프로젝트/품번/품명/공급업체/입고결과/제품구분/
   검사여부/요청현황/요청자/요청일범위)
 - 그리드 12컬럼 (proposal_no, purchase_order_no, project_no, product_name,
   part_no, part_name, partner_name, delivery_status, request_date,
   request_user_name, inspection_yn, request_status)
 - 백엔드: purchase_order_master + incoming_inspection_detail LEFT JOIN
   + sales_request_master + contract_mgmt + part_mng + user_info

수입검사 진행 (incoming-mgmt):
 - 필터 11종 (수입요청과 유사 + 검사일범위 + 검사현황)
 - 그리드 19컬럼 (검사일/검사자/품의서/발주서/프로젝트/제품구분/품명모델/
   부품품번/부품명/공급업체/입고일/입고수량/입고결과/검사수량/불량수량/
   불량률/검사현황/검사성적서)
 - SUM(defect_qty) 서브쿼리로 불량률 자동 계산
 - 하단 요약: 총 입고수량/검사수량/불량수량

공정검사 관리 (process-inspection):
 - 필터 10종 (프로젝트/제품구분/품번/품명/작업환경/측정기/검사일범위/
   검사자/검사결과/진행공정)
 - 그리드 9컬럼 (검사일/검사자/프로젝트/제품구분/품번/품명/검사수량합계/
   검사결과/첨부파일)
 - master/detail 집계 + EXISTS 필터로 wace 1:1

반제품검사 관리 (semi-product-inspection):
 - 필터 8종 (모델명/작업지시번호/부품품번/부품명/검사일범위/검사자/
   불량유형/귀책부서)
 - 그리드 14컬럼 (검사일/검사자/제품구분/모델명/작업지시번호/부품품번/
   부품명/입고수량/양품수량/불량수량/불량률/재생수량/최종양품수량)
 - data_type='GOOD' 마스터 + 동일 inspection_group_id 의 'DEFECT' SUM
 - 재생수량(disposition_type='수정완료') + 최종양품수량 자동 산정
 - 하단 요약: 5개 합계 카드

frontend/lib/api/quality.ts 타입 1:1 정합, 모든 필터 파라미터 직렬화.
2026-05-15 11:23:46 +09:00
hjjeong 6368258797 생산관리 M-BOM PR-B5+ — BOM 복사 다이얼로그 (운영 structureBomCopyFormPopup 1:1)
5개 메뉴 1:1 검증(Agent 5병렬) 후 발견된 mbom 메인 그리드 [BOM 복사] 누락 보완.
저장 매퍼는 PR-B5 saveBomAssignment 재사용 — 백엔드는 EBOM/MBOM 분기 이미 지원,
이번에 MBOM UI 진입점도 첫 노출.

신규 컴포넌트:
 - BomCopyDialog.tsx — 품번/품명 readonly + E-BOM/M-BOM 셀렉트 상호배타 +
   트리 미리보기 + AttachFileDropZone (docType=MBOM_DRAWING, accept=.stp,.step,.dwg,.dxf,.pdf)
 - 메인 page.tsx [BOM 복사] 버튼 추가 + 체크 단건 검증 +
   Machine(0000928) 외 동일 partNo 최신 M-BOM 자동 추천

신규 백엔드 (mbomService/Controller/Routes):
 - searchAssignableMboms — 매퍼 productionplanning.getMbomListForSelect2 (4007~4014) 1:1
 - previewMbomTree     — getStructureOnly + finalize("ASSIGNED_MBOM")
 - getLatestMbomByPartNo — 매퍼 getLatestMbomByPartNo (3426~3445) 1:1, Machine 외 자동 검색
 - 라우트: GET /assignable-mboms, GET /mbom-preview/:objid, GET /latest-mbom-by-partno/:partNo

도면 업로드 차이: 운영 fn_uploadDrawingFiles 는 placeholder("구현 예정"). RPS 는
공용 AttachFileDropZone 재사용해 실구현 (target_objid=projectObjid).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 10:53:35 +09:00
hjjeong 7e7c6a0ac0 영업관리 구매요청서관리·품의서관리 신규 2메뉴 (wace_plm 1:1)
backend
- services/salesPurchaseRequestService.ts: listPurchaseRequestReg(DOC_TYPE='PURCHASE_REG') + listPurchaseRegProposal(DOC_TYPE='PURCHASE_REG_PROPOSAL')
  · 구매요청서 상태 CASE: PURCHASE_REG_PROPOSAL 자식 존재 시 '품의서생성' → '확정'/'작성중' (wace 매퍼 1:1)
  · 품의서 결재상태: amaranth_approval(target_type='PROPOSAL') LEFT JOIN 우선순위
  · sales_request_part 누락 → MBOM_DETAIL+PART_MNG fallback (구매관리 패턴 동일)
- routes/salesPurchaseRequestRoutes.ts + app.ts: /api/sales/purchase-request, /api/sales/purchase-proposal

frontend
- lib/api/salesPurchaseRequest.ts
- sales/purchase-request/page.tsx — 14컬럼, 구매요청서작성/품의서생성 액션 (placeholder 토스트)
- sales/purchase-proposal/page.tsx — 10컬럼, 결재상신 액션 (placeholder 토스트)
- PageHeader+CompactFilterBar+SmartSelect+DataGrid logicstudio 6종 패턴 일관 적용

구매관리>품의서관리 vs 영업관리>품의서관리 차이
- 구매관리: DOC_TYPE in ('PROPOSAL', 'PURCHASE_REG_PROPOSAL'(결재완료만)) → 발주서 생성 풀
- 영업관리: DOC_TYPE='PURCHASE_REG_PROPOSAL' 전용 → 결재상신 화면 (결재완료 시 구매관리로 자동 노출)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 10:04:37 +09:00
hjjeong e785cd8a98 Merge pull request 'hjjeong' (#14) from hjjeong into main
Reviewed-on: https://g.wace.me/chpark/vexplor_rps/pulls/14
2026-05-15 00:25:12 +00:00
chpark d7c645d24c 품질관리/고객CS/ECR — wace_plm 1:1 이식 + 견적관리 그리드 패턴 통일
Build and Push Images / build-and-push (push) Has been cancelled
신규 4개 메뉴 (PageHeader + CompactFilterBar + DataGrid 통일):
 - 품질관리/수입검사 요청 (/quality/incoming-request)
 - 품질관리/수입검사 관리 (/quality/incoming-mgmt)
 - 품질관리/공정검사 관리 (/quality/process-inspection)
 - 품질관리/반제품검사 관리 (/quality/semi-product-inspection)

DB 마이그레이션 (docs/migration/quality/):
 - 01_quality_tables_from_ilshin.sql — ilshin 운영 5개 테이블 vexplor_rps 정합
   (customer_service_mgmt/part/workingtime, inspection_mgmt, delivery_history_defect)
   + ecr_mng 7개 컬럼 동기화 (project_no, customer_cd, equip_name,
     design_dept, unit_cd, memo, check_result)
 - 02_wace_plm_quality_tables.sql — wace_plm quality.xml 매퍼 호환 신규 5개 테이블
   (incoming_inspection_detail/defect, process_inspection_master/detail,
    pms_quality_semi_product_inspection) + 인덱스 정의

백엔드:
 - qualityRoutes.ts — 4개 메뉴 list 엔드포인트 (실 테이블 조회)
 - ecrMngService SELECT_BASE 에 ilshin 신규 7컬럼 노출
 - app.ts 라우팅 등록 (/api/quality/*)

프론트:
 - DataGrid 4개 신규 페이지 + 그리드 툴바 (차트/엑셀/새로고침/컬럼설정/페이지사이즈)
 - customer-cs/cs, ecr/ecr — 견적관리와 동일한 PageHeader + CompactFilterBar
   + DataGrid 패턴으로 리팩토링 (다이얼로그/기존 API 유지)
 - ECR 그리드에 신규 6개 컬럼 추가 (설비명/프로젝트번호/고객사/설계부서/조치결과 등)
 - AdminPageRenderer 4개 라우트 등록

데이터 복사: ilshin → vexplor_rps (workingtime 5건, inspection_mgmt 1건,
ecr_mng 1건). 나머지 ilshin 운영 테이블은 0건이므로 스키마만 정합.
2026-05-14 19:08:15 +09:00
hjjeong bd47ca80df 생산관리 M-BOM PR-B5+ — BOM 할당 다이얼로그 운영판 1:1 재구성 + 미리보기 트리
운영판 mBomEbomSelectPopup.jsp (324 lines) 1:1 레이아웃:
  · 헤더 — "E-BOM 선택" / "E-BOM 상세 및 변경" 토글 제목 + 우측 [E-BOM 변경] 버튼
  · 현재 할당된 E-BOM 정보 카드 — 2×3 table (제품구분/품번/품명/Ver/등록일/작성자)
  · 리스트 토글 — 할당된 경우 변경 모드 ON 시에만 노출
  · 검색폼 운영판 매칭 — 제품구분(SmartSelect) + 품번 + 품명 + 등록일(범위)
  · 리스트 헤더 우측 [조회][E-BOM 할당] 버튼 (footer 제거)
  · 선택 시 하단 미리보기 트리 자동 로드 (read-only, 동적 LEVEL + 폴더아이콘)

신규 백엔드:
  · mbomService.previewEbomTree(bomReportObjid) — EBOM_WORKING_TREE_SQL 재사용
  · GET /api/production/mbom/ebom-preview/:bomReportObjid
  · searchAssignableEboms 필터: material/supplier → product_cd/from_date/to_date 운영판 매칭
  · objid 단건 필터 추가 — 현재 할당 E-BOM 카드 정보 자체 로드용

프론트:
  · MbomAssignDialog 완전 재작성 (full layout, SmartSelect, 미리보기 PreviewTree 컴포넌트)
  · MbomDetailDialog: currentEbomObjid prop 으로 단순화 (다이얼로그 내부에서 상세 fetch)
  · mbomApi.previewEbomTree + AssignableEbomFilter 타입 매칭

이전 b38f5957 의 PR-B5 베이스(검색/할당) 위에 운영판 UX 정합 강화.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 18:13:10 +09:00
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 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
chpark a5ddf852fc 로그인 — 자격증명 오류시 메시지 유지 및 LOGIN_FAILED 코드 처리
- /auth/login 401 응답은 인터셉터에서 리다이렉트하지 않고 그대로 반환해 호출부에서 에러 메시지를 표시하도록 수정
- apiCall에서 errorCode 추출 시 error.code 경로도 지원
- useLogin: errorCode === "LOGIN_FAILED"면 INVALID_CREDENTIALS 메시지 노출
2026-05-14 16:30:11 +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 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 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 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 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
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 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
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
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 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
hjjeong d23b305990 매출관리 그리드 V1 컬럼 9개 보강 + getRevenueList SQL JOIN 확장 + wace 1:1 검증
- getRevenueList SQL: contract_item / user_info / comm_code(CC_RES) / attach_file_info LATERAL 4개 JOIN 추가. receipt_date / payment_type / request_date / customer_request / order_status_name / manager_name / incoterms / cu01_cnt SELECT 보강
- RevenueListRow 타입: 9개 신규 필드 보강
- GRID_COLUMNS 9개 추가: 접수일/유무상/요청납기/고객사요청사항/수주상태/주문서첨부/출하방법/담당자/인도조건 (wace 35/35 일치)
- docs/migration/sales/04-revenue-verify.md, scripts/verify-revenue.sql

영업 4개 메뉴 (견적·주문·판매·매출) 모두 구조적 검증 1차 종결.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 09:42:21 +09:00
hjjeong a0f6e0fa26 판매관리 그리드 V1 컬럼 8개 보강 + cu01_cnt 실데이터 + wace 1:1 검증 문서·자동 검증 SQL
- getList SQL: attach_file_info LATERAL JOIN으로 cu01_cnt(주문서첨부) 실데이터 (contract_mgmt.objid 기반, doc_type IN FTC_ORDER/ORDER)
- SaleListRow 타입: product_type_name/nation_name/receipt_date/customer_request/manager_name/payment_type_name/cu01_cnt 보강
- GRID_COLUMNS 8개 추가: 제품구분/국내해외/접수일/고객사요청사항/주문서첨부/출하방법/담당자/인도조건 (wace 36/36 일치)
- docs/migration/sales/03-sale-verify.md: wace ↔ RPS 매핑 / 갭 처리
- scripts/verify-sale.sql: BEGIN/ROLLBACK 2개 시나리오 (그리드 V1 / 판매상태 wace 로직)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 09:38:57 +09:00
hjjeong 13b4efd2fe 주문관리 그리드 V1 컬럼 보강(제품구분·국내해외·접수일) + wace 1:1 검증 문서·자동 검증 SQL
- getList SQL: 라인 집계에 product_summary 추가, PRODUCT_NAME을 COALESCE(line, header)로 변경 (운영 contract_mgmt.product NULL 패턴 대응)
- GRID_COLUMNS 3개 추가: 제품구분/국내해외/접수일 (wace 27/27 일치)
- OrderRow 타입: product_name / area_name 보강
- searchForm.search_partName 키 추가(초기화 포함, UI 이미 PartSelect mode=partName 존재)
- docs/migration/sales/02-order-verify.md: wace ↔ RPS 항목 매핑 / 운영 데이터 / 갭 처리 결과
- scripts/verify-order.sql: BEGIN/ROLLBACK 4개 시나리오 (그리드 V1 / G1 / 수주취소 / 채번) 자동 검증

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