- Updated the outbound and outsourcing outbound controllers to replace `source_type` with `source_table` for improved clarity and consistency in data handling. - Enhanced the work instruction controller to include automatic migration for the `work_instruction_info` table, allowing for better management of work instruction notes. - Implemented new logic to handle material input types in the work instruction detail modal, supporting both automatic and manual input methods. - Added new routes for retrieving work instruction information, facilitating better data retrieval for editing purposes. (TASK: ERP-node-095, ERP-node-096)
307 lines
10 KiB
TypeScript
307 lines
10 KiB
TypeScript
import { apiClient } from "@/lib/api/client";
|
|
|
|
export interface PaginatedResponse {
|
|
success: boolean;
|
|
data: any[];
|
|
totalCount: number;
|
|
page: number;
|
|
pageSize: number;
|
|
}
|
|
|
|
export async function getWorkInstructionList(params?: Record<string, any>) {
|
|
const res = await apiClient.get("/work-instruction/list", { params });
|
|
return res.data as { success: boolean; data: any[]; totalCount?: number; page?: number; pageSize?: number };
|
|
}
|
|
|
|
export async function previewWorkInstructionNo() {
|
|
const res = await apiClient.get("/work-instruction/preview-no");
|
|
return res.data as { success: boolean; instructionNo: string };
|
|
}
|
|
|
|
export async function saveWorkInstruction(data: any) {
|
|
const res = await apiClient.post("/work-instruction/save", data);
|
|
return res.data as { success: boolean; data?: any; message?: string };
|
|
}
|
|
|
|
export async function deleteWorkInstructions(ids: string[]) {
|
|
const res = await apiClient.post("/work-instruction/delete", { ids });
|
|
return res.data as { success: boolean; deletedCount?: number; message?: string };
|
|
}
|
|
|
|
export async function getWIItemSource(params?: Record<string, any>) {
|
|
const res = await apiClient.get("/work-instruction/source/item", { params });
|
|
return res.data as PaginatedResponse;
|
|
}
|
|
|
|
export async function getWISalesOrderSource(params?: Record<string, any>) {
|
|
const res = await apiClient.get("/work-instruction/source/sales-order", { params });
|
|
return res.data as PaginatedResponse;
|
|
}
|
|
|
|
export async function getWIProductionPlanSource(params?: Record<string, any>) {
|
|
const res = await apiClient.get("/work-instruction/source/production-plan", { params });
|
|
return res.data as PaginatedResponse;
|
|
}
|
|
|
|
export async function getEquipmentList() {
|
|
const res = await apiClient.get("/work-instruction/equipment");
|
|
return res.data as { success: boolean; data: { id: string; equipment_code: string; equipment_name: string }[] };
|
|
}
|
|
|
|
export async function getEmployeeList() {
|
|
const res = await apiClient.get("/work-instruction/employees");
|
|
return res.data as { success: boolean; data: { user_id: string; user_name: string; dept_name: string | null }[] };
|
|
}
|
|
|
|
// BOM 기준수(0레벨 base_qty) 일괄 조회 — 작업지시 등록 모달의 기준수/배치수 산출용
|
|
export async function getBomBaseQtyMap(itemCodes: string[]) {
|
|
const res = await apiClient.post("/work-instruction/bom-base-qty", { itemCodes });
|
|
// batchUse: 품목별 배치사용여부 (Y=사용/N=미사용). 미포함 시 'Y' 간주 (하위호환)
|
|
return res.data as { success: boolean; data: Record<string, number | null>; batchUse?: Record<string, "Y" | "N"> };
|
|
}
|
|
|
|
// ─── 라우팅 & 공정작업기준 API ───
|
|
|
|
export interface RoutingProcess {
|
|
routing_detail_id: string;
|
|
seq_no: string;
|
|
process_code: string;
|
|
process_name: string;
|
|
is_required?: string;
|
|
work_type?: string;
|
|
}
|
|
|
|
export interface RoutingVersionData {
|
|
id: string;
|
|
version_name: string;
|
|
description?: string;
|
|
is_default: boolean;
|
|
processes: RoutingProcess[];
|
|
}
|
|
|
|
export interface WIWorkItemDetail {
|
|
id?: string;
|
|
work_item_id?: string;
|
|
detail_type?: string;
|
|
content?: string;
|
|
is_required?: string;
|
|
sort_order?: number;
|
|
remark?: string;
|
|
|
|
// 검사항목(inspection) 전용
|
|
process_inspection_apply?: string; // "apply" | "none"
|
|
inspection_code?: string;
|
|
inspection_method?: string;
|
|
unit?: string;
|
|
lower_limit?: string;
|
|
upper_limit?: string;
|
|
base_value?: string;
|
|
tolerance?: string;
|
|
auto_collect?: string; // "Y" | "N"
|
|
plc_data?: string;
|
|
|
|
// 작업절차(procedure) 전용
|
|
duration_minutes?: number;
|
|
|
|
// 직접입력(input) 전용
|
|
input_type?: string;
|
|
|
|
// 문서참조(lookup) 전용
|
|
lookup_target?: string;
|
|
display_fields?: string;
|
|
|
|
// 설비점검(equip_inspection) 전용
|
|
equip_inspection_apply?: string; // "apply" | "none"
|
|
|
|
// 설비조건(equip_condition) 전용
|
|
condition_name?: string;
|
|
condition_unit?: string;
|
|
condition_base_value?: string;
|
|
condition_tolerance?: string;
|
|
condition_auto_collect?: string;
|
|
condition_plc_data?: string;
|
|
|
|
// 실적등록(production_result) 전용
|
|
work_qty_auto_collect?: string;
|
|
work_qty_plc_data?: string;
|
|
defect_qty_auto_collect?: string;
|
|
defect_qty_plc_data?: string;
|
|
good_qty_auto_collect?: string;
|
|
good_qty_plc_data?: string;
|
|
loss_qty_auto_collect?: string;
|
|
loss_qty_plc_data?: string;
|
|
|
|
// 자재투입(material_input) 전용 - BOM 자동연동
|
|
material_code?: string;
|
|
material_name?: string;
|
|
quantity?: string;
|
|
material_unit?: string;
|
|
selected_bom_items?: string[] | string;
|
|
bom_item_id?: string;
|
|
bom_item_name?: string;
|
|
bom_qty?: string;
|
|
bom_unit?: string;
|
|
material_input_type?: string; // "auto"(자동투입, 기본) | "manual"(수동투입)
|
|
}
|
|
|
|
export interface WIWorkItem {
|
|
id?: string;
|
|
routing_detail_id?: string;
|
|
work_phase: string;
|
|
title: string;
|
|
is_required: string;
|
|
sort_order: number;
|
|
description?: string;
|
|
detail_count?: number;
|
|
details?: WIWorkItemDetail[];
|
|
source_work_item_id?: string;
|
|
}
|
|
|
|
export interface WIWorkStandardProcess {
|
|
routing_detail_id: string;
|
|
seq_no: string;
|
|
process_code: string;
|
|
process_name: string;
|
|
workItems: WIWorkItem[];
|
|
}
|
|
|
|
export async function getRoutingVersions(wiNo: string, itemCode: string) {
|
|
const res = await apiClient.get(`/work-instruction/${wiNo}/routing-versions/${encodeURIComponent(itemCode)}`);
|
|
return res.data as { success: boolean; data: RoutingVersionData[] };
|
|
}
|
|
|
|
export async function updateWIRouting(wiNo: string, routingVersionId: string) {
|
|
const res = await apiClient.put(`/work-instruction/${wiNo}/routing`, { routingVersionId });
|
|
return res.data as { success: boolean };
|
|
}
|
|
|
|
export async function getWIWorkStandard(wiNo: string, routingVersionId: string) {
|
|
const res = await apiClient.get(`/work-instruction/${wiNo}/work-standard`, { params: { routingVersionId } });
|
|
return res.data as { success: boolean; data: { processes: WIWorkStandardProcess[]; isCustom: boolean } };
|
|
}
|
|
|
|
export async function copyWorkStandard(wiNo: string, routingVersionId: string) {
|
|
const res = await apiClient.post(`/work-instruction/${wiNo}/work-standard/copy`, { routingVersionId });
|
|
return res.data as { success: boolean };
|
|
}
|
|
|
|
export async function saveWIWorkStandard(wiNo: string, routingDetailId: string, workItems: WIWorkItem[]) {
|
|
const res = await apiClient.put(`/work-instruction/${wiNo}/work-standard/save`, { routingDetailId, workItems });
|
|
return res.data as { success: boolean };
|
|
}
|
|
|
|
export async function resetWIWorkStandard(wiNo: string) {
|
|
const res = await apiClient.delete(`/work-instruction/${wiNo}/work-standard/reset`);
|
|
return res.data as { success: boolean };
|
|
}
|
|
|
|
// ─── BOM 대체품 / 작업지시 단위 자재투입 매핑 (TASK:ERP-node-090) ───
|
|
|
|
// BOM 자재 행 (작업지시 등록 모달에서 펼침)
|
|
export interface WIBomMaterial {
|
|
id: string; // bom_detail.id
|
|
child_item_id: string | null; // item_info.id (자재 품목 id)
|
|
child_item_code?: string | null;
|
|
child_item_name?: string | null;
|
|
quantity?: string | number | null;
|
|
detail_unit?: string | null;
|
|
item_unit?: string | null;
|
|
process_type?: string | null;
|
|
}
|
|
|
|
// 품목 코드(item_code)로 그 품목의 BOM 자재 목록을 조회 (단일 레벨)
|
|
// process-info의 /process-info/bom-materials/:itemCode 라우트 재활용
|
|
export async function getWIBomMaterials(itemCode: string) {
|
|
const res = await apiClient.get(`/process-info/bom-materials/${encodeURIComponent(itemCode)}`);
|
|
return res.data as { success: boolean; data: WIBomMaterial[] };
|
|
}
|
|
|
|
// BOM 트리 조회 — 다중 레벨 자재를 재귀 트리로 반환 (TASK:ERP-node-090 트리화)
|
|
// 활성 버전(current_version_id) 기준. 미초기화 BOM은 version_id IS NULL 폴백.
|
|
export interface WIBomTreeNode {
|
|
id: string; // bom_detail.id
|
|
bom_id: string;
|
|
parent_detail_id: string | null;
|
|
child_item_id: string | null;
|
|
child_item_code?: string | null;
|
|
child_item_name?: string | null;
|
|
quantity?: string | number | null;
|
|
detail_unit?: string | null;
|
|
item_unit?: string | null;
|
|
process_type?: string | null;
|
|
level?: number | string | null;
|
|
seq_no?: string | null;
|
|
children: WIBomTreeNode[];
|
|
}
|
|
// 루트 노드(품목 자체) 정보 — BomTreeComponent와 동일하게 0레벨로 표시
|
|
export interface WIBomTreeRootItem {
|
|
itemId: string | null;
|
|
itemCode: string;
|
|
itemName: string;
|
|
baseQty: string | number | null;
|
|
unit: string;
|
|
}
|
|
export async function getWIBomTree(itemCode: string) {
|
|
const res = await apiClient.get(`/work-instruction/bom-tree/${encodeURIComponent(itemCode)}`);
|
|
return res.data as {
|
|
success: boolean;
|
|
hasBom: boolean;
|
|
treeRoots: WIBomTreeNode[];
|
|
rootItem: WIBomTreeRootItem | null;
|
|
};
|
|
}
|
|
|
|
// bom_detail.id 단위 대체품 후보 조회 (마스터 bom_detail_substitute)
|
|
export interface WIBomSubstitute {
|
|
id: string;
|
|
bom_detail_id: string;
|
|
substitute_item_id: string;
|
|
substitute_item_name?: string | null;
|
|
substitute_item_number?: string | null;
|
|
substitute_unit?: string | null;
|
|
priority?: number | string | null;
|
|
ratio?: number | string | null;
|
|
status?: string | null;
|
|
}
|
|
export async function getWIBomSubstitutes(detailId: string) {
|
|
const res = await apiClient.get(`/bom/details/${encodeURIComponent(detailId)}/substitutes`);
|
|
return res.data as { success: boolean; data: WIBomSubstitute[] };
|
|
}
|
|
|
|
// 작업지시별 자재투입 매핑 조회 (편집 복원용)
|
|
export interface WIMaterialOverrideMaterial {
|
|
detailId: string;
|
|
bomItemId: string;
|
|
bomItemName: string;
|
|
bomQty: string;
|
|
bomUnit: string;
|
|
content: string;
|
|
isOverride: boolean;
|
|
originalBomItemId: string | null;
|
|
}
|
|
export interface WIMaterialOverrideRouting {
|
|
routingDetailId: string;
|
|
processCode: string;
|
|
processName: string;
|
|
materials: WIMaterialOverrideMaterial[];
|
|
}
|
|
export async function getWIMaterialOverrides(wiNo: string) {
|
|
const res = await apiClient.get(`/work-instruction/${encodeURIComponent(wiNo)}/material-overrides`);
|
|
return res.data as { success: boolean; data: WIMaterialOverrideRouting[] };
|
|
}
|
|
|
|
// ─── 작업지시 인포(메모) 조회 — 편집 모달 복원용 (TASK:ERP-node-095) ───
|
|
export interface WIInfo {
|
|
id: string;
|
|
content: string;
|
|
sort_order: number;
|
|
}
|
|
export async function getWIInfos(wiNo: string) {
|
|
const res = await apiClient.get(`/work-instruction/${encodeURIComponent(wiNo)}/infos`);
|
|
return res.data as { success: boolean; data: WIInfo[] };
|
|
}
|
|
|
|
// 품목 검색 (대체품 SmartSelect 옵션 — 마스터에 등록 안 된 임의 자재로 교체할 때 사용)
|
|
// 작업지시 등록 모달의 source/item 라우트를 재활용 (이미 keyword 검색 지원)
|
|
// → getWIItemSource(params={ keyword, page, pageSize })
|