feat(bom): COMPANY_7 BOM에 대체 품목 관리 기능 추가
- bom_detail_substitute 테이블 신규 (varchar PK, FK 미설정 / 코드 조인) - 백엔드: 단일 행 substitute CRUD + BOM 단위 갯수 맵 API 5종 추가 - 프론트(COMPANY_7): 트리 행에 '대체 N' 뱃지 + 대체 품목 모달 · 드래그앤드롭으로 우선순위 변경 + 자동 채번/재할당 · 250ms debounce 실시간 검색, 결과 클릭 시 자동 행 추가 · inline blur 저장, zebra 행 구분, sticky 헤더 단색 처리 - 트리뷰 액션 버튼 통합: 가상 루트 선택 시 1레벨, 일반 행 선택 시 하위로 추가 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -224,3 +224,93 @@ export async function deleteBomVersion(req: Request, res: Response) {
|
||||
res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 대체품 (Substitute) ─────────────────────────────
|
||||
|
||||
export async function getBomDetailSubstitutes(req: Request, res: Response) {
|
||||
try {
|
||||
const { detailId } = req.params;
|
||||
const companyCode = (req as any).user?.companyCode || "*";
|
||||
const data = await bomService.getBomDetailSubstitutes(detailId, companyCode);
|
||||
res.json({ success: true, data });
|
||||
} catch (error: any) {
|
||||
logger.error("대체품 조회 실패", { error: error.message });
|
||||
res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
export async function getBomSubstituteCounts(req: Request, res: Response) {
|
||||
try {
|
||||
const { bomId } = req.params;
|
||||
const companyCode = (req as any).user?.companyCode || "*";
|
||||
const versionId = (req.query.versionId as string) || undefined;
|
||||
const rows = await bomService.getBomSubstituteCounts(bomId, companyCode, versionId);
|
||||
const map: Record<string, number> = {};
|
||||
for (const r of rows as any[]) {
|
||||
map[r.bom_detail_id] = Number(r.count);
|
||||
}
|
||||
res.json({ success: true, data: map });
|
||||
} catch (error: any) {
|
||||
logger.error("대체품 갯수 조회 실패", { error: error.message });
|
||||
res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
export async function createBomDetailSubstitute(req: Request, res: Response) {
|
||||
try {
|
||||
const { detailId } = req.params;
|
||||
const companyCode = (req as any).user?.companyCode || "*";
|
||||
const writer = (req as any).user?.userName || (req as any).user?.userId || "";
|
||||
const { substitute_item_id, priority, ratio, remark, status } = req.body;
|
||||
|
||||
if (!substitute_item_id) {
|
||||
res.status(400).json({ success: false, message: "substitute_item_id는 필수입니다" });
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await bomService.createBomDetailSubstitute({
|
||||
bom_detail_id: detailId,
|
||||
substitute_item_id,
|
||||
priority,
|
||||
ratio,
|
||||
remark,
|
||||
status,
|
||||
company_code: companyCode,
|
||||
writer,
|
||||
});
|
||||
res.json({ success: true, data });
|
||||
} catch (error: any) {
|
||||
logger.error("대체품 등록 실패", { error: error.message });
|
||||
res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateBomDetailSubstitute(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const data = await bomService.updateBomDetailSubstitute(id, req.body);
|
||||
if (!data) {
|
||||
res.status(404).json({ success: false, message: "대체품을 찾을 수 없습니다" });
|
||||
return;
|
||||
}
|
||||
res.json({ success: true, data });
|
||||
} catch (error: any) {
|
||||
logger.error("대체품 수정 실패", { error: error.message });
|
||||
res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteBomDetailSubstitute(req: Request, res: Response) {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const result = await bomService.deleteBomDetailSubstitute(id);
|
||||
if (!result) {
|
||||
res.status(404).json({ success: false, message: "대체품을 찾을 수 없습니다" });
|
||||
return;
|
||||
}
|
||||
res.json({ success: true });
|
||||
} catch (error: any) {
|
||||
logger.error("대체품 삭제 실패", { error: error.message });
|
||||
res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user