Files
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

366 lines
12 KiB
TypeScript

import { apiClient } from "./client";
// ============================================================
// 생산관리 > M-BOM 관리 — wace productionplanning.xml 1:1
// 라우트:
// GET /api/production/mbom/list (PR-A1, 그리드)
// GET /api/production/mbom/detail/:objid (PR-A2, 단건 상세)
// GET /api/production/mbom/tree/:objid (PR-A2, read-only 트리 4분기)
// ============================================================
export interface MbomListFilter {
search_category_cd?: string;
search_product_cd?: string;
search_area_cd?: string;
search_customer_objid?: string;
search_paid_type?: string;
search_serial_no?: string;
search_part_no?: string;
search_part_name?: string;
search_receipt_date_from?: string;
search_receipt_date_to?: string;
search_req_del_date_from?: string;
search_req_del_date_to?: string;
page?: number;
page_size?: number;
}
export interface MbomRow {
objid: string;
contract_objid: string | null;
project_no: string | null;
category_cd: string | null;
category_name: string | null;
product: string | null;
product_name: string | null;
area_cd: string | null;
area_name: string | null;
receipt_date: string | null;
writer_name: string | null;
customer_objid: string | null;
customer_name: string | null;
paid_type: string | null;
paid_type_name: string | null;
part_no: string | null;
part_name: string | null;
part_objid: string | null;
serial_no: string | null;
serial_no_list: string | null;
quantity: string | number | null;
req_del_date: string | null;
customer_request: string | null;
bom_report_objid: string | null;
ebom_status: string | null;
ebom_regdate: string | null;
mbom_header_objid: string | null;
purchase_list_objid: string | null;
purchase_list_date: string | null;
mbom_status: string | null;
mbom_part_no: string | null;
mbom_regdate: string | null;
mbom_editor: string | null;
mbom_version: number | null;
}
export interface MbomListResponse {
rows: MbomRow[];
totalCount: number;
page: number;
pageSize: number;
}
// ─── 단건 상세 (PR-A2) ──────────────────────────────────────
export interface MbomDetail {
objid: string;
contract_objid: string | null;
project_no: string | null;
bom_report_objid: string | null;
part_objid: string | null;
part_no: string | null;
part_name: string | null;
source_bom_type: string | null;
source_ebom_objid: string | null;
source_mbom_objid: string | null;
quantity: string | number | null;
total_prod_qty: string | number | null;
mbom_part_no: string | null;
category_cd: string | null;
category_name: string | null;
product: string | null;
product_code: string | null;
product_name: string | null;
area_cd: string | null;
area_name: string | null;
customer_objid: string | null;
customer_name: string | null;
paid_type: string | null;
req_del_date: string | null;
receipt_date: string | null;
mbom_regdate: string | null;
}
// ─── read-only 트리 (PR-A2) ─────────────────────────────────
// 운영판 mBomPopupLeft.do 4분기 자동 판별:
// SAVED — mbom_header.status='Y' 최신
// ASSIGNED_EBOM — source_bom_type='EBOM' + source_ebom_objid
// ASSIGNED_MBOM — source_bom_type='MBOM' + source_mbom_objid
// TEMPLATE — Machine 이외 + 동일 part_no 의 mbom_header
// NONE — 빈 트리
export type MbomBomDataType = "SAVED" | "ASSIGNED_EBOM" | "ASSIGNED_MBOM" | "TEMPLATE" | "NONE";
export interface MbomTreeRow {
objid: string;
parent_objid: string | null;
child_objid: string | null;
part_objid: string | null;
part_no: string | null;
part_name: string | null;
qty: string | number | null;
item_qty: string | number | null;
qty_temp: string | number | null;
level: number;
sub_part_cnt: number;
seq: number;
status: string | null;
unit: string | null;
unit_title: string | null;
supply_type: string | null;
make_or_buy: string | null;
raw_material_no: string | null;
raw_material_spec: string | null;
raw_material: string | null;
size: string | null;
processing_vendor: string | null;
processing_vendor_name: string | null;
processing_deadline: string | null;
grinding_deadline: string | null;
required_qty: string | number | null;
order_qty: string | number | null;
production_qty: string | number | null;
vendor: string | null;
vendor_name: string | null;
unit_price: string | number | null;
total_price: string | number | null;
currency: string | null;
writer: string | null;
regdate: string | null;
editer: string | null;
edit_date: string | null;
remark: string | null;
spec: string | null;
material: string | null;
weight: string | number | null;
revision: string | null;
cu01_cnt: number;
cu02_cnt: number;
cu03_cnt: number;
[key: string]: any;
}
export interface MbomTreeResponse {
bom_data_type: MbomBomDataType;
bom_report_objid: string | null;
max_level: number;
rows: MbomTreeRow[];
}
// ─── 저장 (PR-B1) ───────────────────────────────────────────
// 운영판 saveMbom.do 1:1 — 신규/수정 통합 엔드포인트.
// is_update=false → 새 mbom_header + child_objid 재매핑 후 detail 일괄 insert
// is_update=true → 기존 mbom_header.objid 조회 → UPSERT + 누락 행 delete
export interface MbomSaveRow {
objid?: string | null;
parent_objid?: string | null;
child_objid?: string | null;
seq?: number | string | null;
level?: number | string | null;
part_objid?: string | number | null;
part_no?: string | null;
part_name?: string | null;
qty?: number | string | null;
item_qty?: number | string | null;
unit?: string | null;
supply_type?: string | null;
make_or_buy?: string | null;
raw_material_no?: string | null;
raw_material_spec?: string | null;
raw_material?: string | null;
size?: string | null;
raw_material_size?: string | null;
processing_vendor?: string | null;
processing_deadline?: string | null;
grinding_deadline?: string | null;
required_qty?: number | string | null;
order_qty?: number | string | null;
production_qty?: number | string | null;
remark?: string | null;
}
export interface MbomSavePayload {
project_obj_id: string;
is_update: boolean;
mbom_part_no?: string | null;
rows: MbomSaveRow[];
}
export interface MbomSaveResult {
mode: "CREATE" | "UPDATE";
mbom_header_objid: string;
mbom_no: string;
inserted: number;
updated: number;
deleted: number;
}
// ─── 구매리스트 생성 (PR-B3) ────────────────────────────────
// 운영판 createPurchaseListFromMBom.do 1:1. SALES_REQUEST_MASTER 단건 생성.
// 동일 mbom_header_objid 로 이미 생성된 SRM 있으면 400 에러.
export interface CreateSalesRequestPayload {
mbom_header_objid: string;
project_mgmt_objid: string;
}
export interface CreateSalesRequestResult {
objid: string;
request_mng_no: string;
mbom_header_objid: string;
}
export const mbomApi = {
async list(filter: MbomListFilter = {}): Promise<MbomListResponse> {
const res = await apiClient.get("/production/mbom/list", { params: filter });
return res.data?.data as MbomListResponse;
},
async getDetail(objid: string): Promise<MbomDetail> {
const res = await apiClient.get(`/production/mbom/detail/${encodeURIComponent(objid)}`);
return res.data?.data as MbomDetail;
},
async getTree(objid: string): Promise<MbomTreeResponse> {
const res = await apiClient.get(`/production/mbom/tree/${encodeURIComponent(objid)}`);
return res.data?.data as MbomTreeResponse;
},
async save(payload: MbomSavePayload): Promise<MbomSaveResult> {
const res = await apiClient.post("/production/mbom/save", payload);
return res.data?.data as MbomSaveResult;
},
async getHistory(projectObjid: string): Promise<MbomHistoryRow[]> {
const res = await apiClient.get(`/production/mbom/history/${encodeURIComponent(projectObjid)}`);
return (res.data?.data ?? []) as MbomHistoryRow[];
},
async createSalesRequest(payload: CreateSalesRequestPayload): Promise<CreateSalesRequestResult> {
const res = await apiClient.post("/production/mbom/sales-request", payload);
return res.data?.data as CreateSalesRequestResult;
},
async searchAssignableEboms(filter: AssignableEbomFilter = {}): Promise<AssignableEbomRow[]> {
const res = await apiClient.get("/production/mbom/assignable-eboms", { params: filter });
return (res.data?.data ?? []) as AssignableEbomRow[];
},
async previewEbomTree(bomReportObjid: string): Promise<MbomTreeResponse> {
const res = await apiClient.get(`/production/mbom/ebom-preview/${encodeURIComponent(bomReportObjid)}`);
return res.data?.data as MbomTreeResponse;
},
async assignBom(payload: AssignBomPayload): Promise<AssignBomResult> {
const res = await apiClient.post("/production/mbom/assign", payload);
return res.data?.data as AssignBomResult;
},
async searchAssignableMboms(filter: AssignableMbomFilter = {}): Promise<AssignableMbomRow[]> {
const res = await apiClient.get("/production/mbom/assignable-mboms", { params: filter });
return (res.data?.data ?? []) as AssignableMbomRow[];
},
async previewMbomTree(mbomHeaderObjid: string): Promise<MbomTreeResponse> {
const res = await apiClient.get(`/production/mbom/mbom-preview/${encodeURIComponent(mbomHeaderObjid)}`);
return res.data?.data as MbomTreeResponse;
},
async getLatestMbomByPartNo(partNo: string): Promise<LatestMbomByPartNoRow | null> {
const res = await apiClient.get(`/production/mbom/latest-mbom-by-partno/${encodeURIComponent(partNo)}`);
return (res.data?.data ?? null) as LatestMbomByPartNoRow | null;
},
};
// ─── BOM 할당 (PR-B5) ───────────────────────────────────────
// 운영판 mBomEbomSelectPopup.do + saveBomAssignment.do 1:1.
// project_mgmt.source_bom_type='EBOM' + source_ebom_objid 만 우선 지원.
export interface AssignableEbomFilter {
objid?: string;
product_cd?: string;
search_part_no?: string;
search_part_name?: string;
search_from_date?: string;
search_to_date?: string;
limit?: number;
}
export interface AssignableEbomRow {
objid: string;
product_cd: string | null;
product_name: string | null;
part_no: string | null;
part_name: string | null;
status: string | null;
revision: string | null;
reg_date: string | null;
writer_name: string | null;
dept_name: string | null;
material: string | null;
supplier: string | null;
}
export interface AssignBomPayload {
project_obj_id: string;
source_bom_type: "EBOM" | "MBOM";
source_bom_obj_id: string;
}
export interface AssignBomResult {
success: boolean;
source_bom_type: string;
source_obj_id: string;
}
// ─── BOM 복사 보조 (PR-B5+) ─────────────────────────────────
// 운영판 partMng/structureBomCopyFormPopup.jsp 의 셀렉트/자동검색 보조 API.
export interface AssignableMbomFilter {
search_part_no?: string;
search_part_name?: string;
search_from_date?: string;
search_to_date?: string;
limit?: number;
}
export interface AssignableMbomRow {
objid: string;
mbom_no: string | null;
part_no: string | null;
part_name: string | null;
reg_date: string | null;
}
export interface LatestMbomByPartNoRow {
template_header_objid: string;
mbom_no: string | null;
project_objid: string | null;
part_no: string | null;
part_name: string | null;
save_date: string | null;
}
// ─── 변경이력 (PR-B4) ───────────────────────────────────────
export interface MbomHistoryRow {
objid: string;
mbom_header_objid: string;
change_type: string; // CREATE | UPDATE
change_description: string | null;
change_user: string | null;
change_user_name: string | null;
change_date: string;
mbom_part_no: string | null;
mbom_regdate: string | null;
}