feat: Implement default version management for routing versions
- Added functionality to set and unset default versions for routing items. - Introduced new API endpoints for setting and unsetting default versions. - Enhanced the ItemRoutingComponent to support toggling default versions with user feedback. - Updated database queries to handle default version logic effectively. - Improved the overall user experience by allowing easy management of routing versions.
This commit is contained in:
@@ -39,16 +39,18 @@ export async function getItemsWithRouting(req: AuthenticatedRequest, res: Respon
|
||||
if (search) params.push(`%${search}%`);
|
||||
|
||||
const query = `
|
||||
SELECT DISTINCT
|
||||
SELECT
|
||||
i.id,
|
||||
i.${nameColumn} AS item_name,
|
||||
i.${codeColumn} AS item_code
|
||||
i.${codeColumn} AS item_code,
|
||||
COUNT(rv.id) AS routing_count
|
||||
FROM ${tableName} i
|
||||
INNER JOIN ${routingTable} rv ON rv.${routingFkColumn} = i.${codeColumn}
|
||||
LEFT JOIN ${routingTable} rv ON rv.${routingFkColumn} = i.${codeColumn}
|
||||
AND rv.company_code = i.company_code
|
||||
WHERE i.company_code = $1
|
||||
${searchCondition}
|
||||
ORDER BY i.${codeColumn}
|
||||
GROUP BY i.id, i.${nameColumn}, i.${codeColumn}, i.created_date
|
||||
ORDER BY i.created_date DESC NULLS LAST
|
||||
`;
|
||||
|
||||
const result = await getPool().query(query, params);
|
||||
@@ -82,10 +84,10 @@ export async function getRoutingsWithProcesses(req: AuthenticatedRequest, res: R
|
||||
|
||||
// 라우팅 버전 목록
|
||||
const versionsQuery = `
|
||||
SELECT id, version_name, description, created_date
|
||||
SELECT id, version_name, description, created_date, COALESCE(is_default, false) AS is_default
|
||||
FROM ${routingVersionTable}
|
||||
WHERE ${routingFkColumn} = $1 AND company_code = $2
|
||||
ORDER BY created_date DESC
|
||||
ORDER BY is_default DESC, created_date DESC
|
||||
`;
|
||||
const versionsResult = await getPool().query(versionsQuery, [
|
||||
itemCode,
|
||||
@@ -127,6 +129,92 @@ export async function getRoutingsWithProcesses(req: AuthenticatedRequest, res: R
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 기본 버전 설정
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* 라우팅 버전을 기본 버전으로 설정
|
||||
* 같은 품목의 다른 버전은 기본 해제
|
||||
*/
|
||||
export async function setDefaultVersion(req: AuthenticatedRequest, res: Response) {
|
||||
const pool = getPool();
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const companyCode = req.user?.companyCode;
|
||||
if (!companyCode) {
|
||||
return res.status(401).json({ success: false, message: "인증 필요" });
|
||||
}
|
||||
|
||||
const { versionId } = req.params;
|
||||
const {
|
||||
routingVersionTable = "item_routing_version",
|
||||
routingFkColumn = "item_code",
|
||||
} = req.body;
|
||||
|
||||
await client.query("BEGIN");
|
||||
|
||||
const versionResult = await client.query(
|
||||
`SELECT ${routingFkColumn} AS item_code FROM ${routingVersionTable} WHERE id = $1 AND company_code = $2`,
|
||||
[versionId, companyCode]
|
||||
);
|
||||
|
||||
if (versionResult.rowCount === 0) {
|
||||
await client.query("ROLLBACK");
|
||||
return res.status(404).json({ success: false, message: "버전을 찾을 수 없습니다" });
|
||||
}
|
||||
|
||||
const itemCode = versionResult.rows[0].item_code;
|
||||
|
||||
await client.query(
|
||||
`UPDATE ${routingVersionTable} SET is_default = false WHERE ${routingFkColumn} = $1 AND company_code = $2`,
|
||||
[itemCode, companyCode]
|
||||
);
|
||||
|
||||
await client.query(
|
||||
`UPDATE ${routingVersionTable} SET is_default = true WHERE id = $1 AND company_code = $2`,
|
||||
[versionId, companyCode]
|
||||
);
|
||||
|
||||
await client.query("COMMIT");
|
||||
|
||||
logger.info("기본 버전 설정", { companyCode, versionId, itemCode });
|
||||
return res.json({ success: true, message: "기본 버전이 설정되었습니다" });
|
||||
} catch (error: any) {
|
||||
await client.query("ROLLBACK");
|
||||
logger.error("기본 버전 설정 실패", { error: error.message });
|
||||
return res.status(500).json({ success: false, message: error.message });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 기본 버전 해제
|
||||
*/
|
||||
export async function unsetDefaultVersion(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
const companyCode = req.user?.companyCode;
|
||||
if (!companyCode) {
|
||||
return res.status(401).json({ success: false, message: "인증 필요" });
|
||||
}
|
||||
|
||||
const { versionId } = req.params;
|
||||
const { routingVersionTable = "item_routing_version" } = req.body;
|
||||
|
||||
await getPool().query(
|
||||
`UPDATE ${routingVersionTable} SET is_default = false WHERE id = $1 AND company_code = $2`,
|
||||
[versionId, companyCode]
|
||||
);
|
||||
|
||||
logger.info("기본 버전 해제", { companyCode, versionId });
|
||||
return res.json({ success: true, message: "기본 버전이 해제되었습니다" });
|
||||
} catch (error: any) {
|
||||
logger.error("기본 버전 해제 실패", { error: error.message });
|
||||
return res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 작업 항목 CRUD
|
||||
// ============================================================
|
||||
@@ -330,7 +418,10 @@ export async function getWorkItemDetails(req: AuthenticatedRequest, res: Respons
|
||||
const { workItemId } = req.params;
|
||||
|
||||
const query = `
|
||||
SELECT id, work_item_id, detail_type, content, is_required, sort_order, remark, created_date
|
||||
SELECT id, work_item_id, detail_type, content, is_required, sort_order, remark,
|
||||
inspection_code, inspection_method, unit, lower_limit, upper_limit,
|
||||
duration_minutes, input_type, lookup_target, display_fields,
|
||||
created_date
|
||||
FROM process_work_item_detail
|
||||
WHERE work_item_id = $1 AND company_code = $2
|
||||
ORDER BY sort_order, created_date
|
||||
@@ -355,7 +446,11 @@ export async function createWorkItemDetail(req: AuthenticatedRequest, res: Respo
|
||||
return res.status(401).json({ success: false, message: "인증 필요" });
|
||||
}
|
||||
|
||||
const { work_item_id, detail_type, content, is_required, sort_order, remark } = req.body;
|
||||
const {
|
||||
work_item_id, detail_type, content, is_required, sort_order, remark,
|
||||
inspection_code, inspection_method, unit, lower_limit, upper_limit,
|
||||
duration_minutes, input_type, lookup_target, display_fields,
|
||||
} = req.body;
|
||||
|
||||
if (!work_item_id || !content) {
|
||||
return res.status(400).json({
|
||||
@@ -375,8 +470,10 @@ export async function createWorkItemDetail(req: AuthenticatedRequest, res: Respo
|
||||
|
||||
const query = `
|
||||
INSERT INTO process_work_item_detail
|
||||
(company_code, work_item_id, detail_type, content, is_required, sort_order, remark, writer)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
(company_code, work_item_id, detail_type, content, is_required, sort_order, remark, writer,
|
||||
inspection_code, inspection_method, unit, lower_limit, upper_limit,
|
||||
duration_minutes, input_type, lookup_target, display_fields)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
@@ -389,6 +486,15 @@ export async function createWorkItemDetail(req: AuthenticatedRequest, res: Respo
|
||||
sort_order || 0,
|
||||
remark || null,
|
||||
writer,
|
||||
inspection_code || null,
|
||||
inspection_method || null,
|
||||
unit || null,
|
||||
lower_limit || null,
|
||||
upper_limit || null,
|
||||
duration_minutes || null,
|
||||
input_type || null,
|
||||
lookup_target || null,
|
||||
display_fields || null,
|
||||
]);
|
||||
|
||||
logger.info("작업 항목 상세 생성", { companyCode, id: result.rows[0].id });
|
||||
@@ -410,7 +516,11 @@ export async function updateWorkItemDetail(req: AuthenticatedRequest, res: Respo
|
||||
}
|
||||
|
||||
const { id } = req.params;
|
||||
const { detail_type, content, is_required, sort_order, remark } = req.body;
|
||||
const {
|
||||
detail_type, content, is_required, sort_order, remark,
|
||||
inspection_code, inspection_method, unit, lower_limit, upper_limit,
|
||||
duration_minutes, input_type, lookup_target, display_fields,
|
||||
} = req.body;
|
||||
|
||||
const query = `
|
||||
UPDATE process_work_item_detail
|
||||
@@ -419,6 +529,15 @@ export async function updateWorkItemDetail(req: AuthenticatedRequest, res: Respo
|
||||
is_required = COALESCE($3, is_required),
|
||||
sort_order = COALESCE($4, sort_order),
|
||||
remark = COALESCE($5, remark),
|
||||
inspection_code = $8,
|
||||
inspection_method = $9,
|
||||
unit = $10,
|
||||
lower_limit = $11,
|
||||
upper_limit = $12,
|
||||
duration_minutes = $13,
|
||||
input_type = $14,
|
||||
lookup_target = $15,
|
||||
display_fields = $16,
|
||||
updated_date = NOW()
|
||||
WHERE id = $6 AND company_code = $7
|
||||
RETURNING *
|
||||
@@ -432,6 +551,15 @@ export async function updateWorkItemDetail(req: AuthenticatedRequest, res: Respo
|
||||
remark,
|
||||
id,
|
||||
companyCode,
|
||||
inspection_code || null,
|
||||
inspection_method || null,
|
||||
unit || null,
|
||||
lower_limit || null,
|
||||
upper_limit || null,
|
||||
duration_minutes || null,
|
||||
input_type || null,
|
||||
lookup_target || null,
|
||||
display_fields || null,
|
||||
]);
|
||||
|
||||
if (result.rowCount === 0) {
|
||||
@@ -544,8 +672,10 @@ export async function saveAll(req: AuthenticatedRequest, res: Response) {
|
||||
for (const detail of item.details) {
|
||||
await client.query(
|
||||
`INSERT INTO process_work_item_detail
|
||||
(company_code, work_item_id, detail_type, content, is_required, sort_order, remark, writer)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
||||
(company_code, work_item_id, detail_type, content, is_required, sort_order, remark, writer,
|
||||
inspection_code, inspection_method, unit, lower_limit, upper_limit,
|
||||
duration_minutes, input_type, lookup_target, display_fields)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)`,
|
||||
[
|
||||
companyCode,
|
||||
workItemId,
|
||||
@@ -555,6 +685,15 @@ export async function saveAll(req: AuthenticatedRequest, res: Response) {
|
||||
detail.sort_order || 0,
|
||||
detail.remark || null,
|
||||
writer,
|
||||
detail.inspection_code || null,
|
||||
detail.inspection_method || null,
|
||||
detail.unit || null,
|
||||
detail.lower_limit || null,
|
||||
detail.upper_limit || null,
|
||||
detail.duration_minutes || null,
|
||||
detail.input_type || null,
|
||||
detail.lookup_target || null,
|
||||
detail.display_fields || null,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,10 @@ router.use(authenticateToken);
|
||||
router.get("/items", ctrl.getItemsWithRouting);
|
||||
router.get("/items/:itemCode/routings", ctrl.getRoutingsWithProcesses);
|
||||
|
||||
// 기본 버전 설정/해제
|
||||
router.put("/versions/:versionId/set-default", ctrl.setDefaultVersion);
|
||||
router.put("/versions/:versionId/unset-default", ctrl.unsetDefaultVersion);
|
||||
|
||||
// 작업 항목 CRUD
|
||||
router.get("/routing-detail/:routingDetailId/work-items", ctrl.getWorkItems);
|
||||
router.post("/work-items", ctrl.createWorkItem);
|
||||
|
||||
Reference in New Issue
Block a user