192 lines
6.7 KiB
TypeScript
192 lines
6.7 KiB
TypeScript
/**
|
|
* 생산계획 컨트롤러
|
|
*/
|
|
|
|
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,
|
|
});
|
|
}
|
|
}
|