ERP-node/backend-node/src/controllers/productionController.ts

192 lines
6.7 KiB
TypeScript
Raw Normal View History

/**
*
*/
import { Response } from "express";
import { AuthenticatedRequest } from "../types/auth";
import * as productionService from "../services/productionPlanService";
import { logger } from "../utils/logger";
// ─── 수주 데이터 조회 (품목별 그룹핑) ───
export async function getOrderSummary(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const { excludePlanned, itemCode, itemName } = req.query;
const data = await productionService.getOrderSummary(companyCode, {
excludePlanned: excludePlanned === "true",
itemCode: itemCode as string,
itemName: itemName as string,
});
return res.json({ success: true, data });
} catch (error: any) {
logger.error("수주 데이터 조회 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
// ─── 안전재고 부족분 조회 ───
export async function getStockShortage(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const data = await productionService.getStockShortage(companyCode);
return res.json({ success: true, data });
} catch (error: any) {
logger.error("안전재고 부족분 조회 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
// ─── 생산계획 상세 조회 ───
export async function getPlanById(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const planId = parseInt(req.params.id, 10);
const data = await productionService.getPlanById(companyCode, planId);
if (!data) {
return res.status(404).json({ success: false, message: "생산계획을 찾을 수 없습니다" });
}
return res.json({ success: true, data });
} catch (error: any) {
logger.error("생산계획 조회 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
// ─── 생산계획 수정 ───
export async function updatePlan(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const planId = parseInt(req.params.id, 10);
const updatedBy = req.user!.userId;
const data = await productionService.updatePlan(companyCode, planId, req.body, updatedBy);
return res.json({ success: true, data });
} catch (error: any) {
logger.error("생산계획 수정 실패", { error: error.message });
return res.status(error.message.includes("찾을 수 없") ? 404 : 500).json({
success: false,
message: error.message,
});
}
}
// ─── 생산계획 삭제 ───
export async function deletePlan(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const planId = parseInt(req.params.id, 10);
await productionService.deletePlan(companyCode, planId);
return res.json({ success: true, message: "삭제되었습니다" });
} catch (error: any) {
logger.error("생산계획 삭제 실패", { error: error.message });
return res.status(error.message.includes("찾을 수 없") ? 404 : 500).json({
success: false,
message: error.message,
});
}
}
// ─── 자동 스케줄 생성 ───
export async function generateSchedule(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const createdBy = req.user!.userId;
const { items, options } = req.body;
if (!items || !Array.isArray(items) || items.length === 0) {
return res.status(400).json({ success: false, message: "품목 정보가 필요합니다" });
}
const data = await productionService.generateSchedule(companyCode, items, options || {}, createdBy);
return res.json({ success: true, data });
} catch (error: any) {
logger.error("자동 스케줄 생성 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
// ─── 스케줄 병합 ───
export async function mergeSchedules(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const mergedBy = req.user!.userId;
const { schedule_ids, product_type } = req.body;
if (!schedule_ids || !Array.isArray(schedule_ids) || schedule_ids.length < 2) {
return res.status(400).json({ success: false, message: "2개 이상의 스케줄을 선택해주세요" });
}
const data = await productionService.mergeSchedules(
companyCode,
schedule_ids,
product_type || "완제품",
mergedBy
);
return res.json({ success: true, data });
} catch (error: any) {
logger.error("스케줄 병합 실패", { error: error.message });
const status = error.message.includes("동일 품목") || error.message.includes("찾을 수 없") ? 400 : 500;
return res.status(status).json({ success: false, message: error.message });
}
}
// ─── 반제품 계획 자동 생성 ───
export async function generateSemiSchedule(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const createdBy = req.user!.userId;
const { plan_ids, options } = req.body;
if (!plan_ids || !Array.isArray(plan_ids) || plan_ids.length === 0) {
return res.status(400).json({ success: false, message: "완제품 계획을 선택해주세요" });
}
const data = await productionService.generateSemiSchedule(
companyCode,
plan_ids,
options || {},
createdBy
);
return res.json({ success: true, data });
} catch (error: any) {
logger.error("반제품 계획 생성 실패", { error: error.message });
return res.status(500).json({ success: false, message: error.message });
}
}
// ─── 스케줄 분할 ───
export async function splitSchedule(req: AuthenticatedRequest, res: Response) {
try {
const companyCode = req.user!.companyCode;
const splitBy = req.user!.userId;
const planId = parseInt(req.params.id, 10);
const { split_qty } = req.body;
if (!split_qty || split_qty <= 0) {
return res.status(400).json({ success: false, message: "분할 수량을 입력해주세요" });
}
const data = await productionService.splitSchedule(companyCode, planId, split_qty, splitBy);
return res.json({ success: true, data });
} catch (error: any) {
logger.error("스케줄 분할 실패", { error: error.message });
return res.status(error.message.includes("찾을 수 없") ? 404 : 400).json({
success: false,
message: error.message,
});
}
}