ERP-node/backend-node/src/services/YardLayoutService.ts

338 lines
8.5 KiB
TypeScript
Raw Normal View History

import { getPool } from "../database/db";
export class YardLayoutService {
// 모든 야드 레이아웃 목록 조회
async getAllLayouts() {
const query = `
SELECT
yl.id,
yl.name,
yl.description,
yl.created_by,
yl.created_at,
yl.updated_at,
COUNT(ymp.id) as placement_count
FROM yard_layout yl
LEFT JOIN yard_material_placement ymp ON yl.id = ymp.yard_layout_id
GROUP BY yl.id
ORDER BY yl.updated_at DESC
`;
const pool = getPool();
const result = await pool.query(query);
return result.rows;
}
// 특정 야드 레이아웃 상세 조회
async getLayoutById(id: number) {
const query = `
SELECT
id,
name,
description,
created_by,
created_at,
updated_at
FROM yard_layout
WHERE id = $1
`;
const pool = getPool();
const result = await pool.query(query, [id]);
return result.rows[0] || null;
}
// 새 야드 레이아웃 생성
async createLayout(data: {
name: string;
description?: string;
created_by?: string;
}) {
const query = `
INSERT INTO yard_layout (name, description, created_by)
VALUES ($1, $2, $3)
RETURNING *
`;
const pool = getPool();
const result = await pool.query(query, [
data.name,
data.description || null,
data.created_by || null,
]);
return result.rows[0];
}
// 야드 레이아웃 수정 (이름, 설명만)
async updateLayout(
id: number,
data: { name?: string; description?: string }
) {
const query = `
UPDATE yard_layout
SET
name = COALESCE($1, name),
description = COALESCE($2, description),
updated_at = CURRENT_TIMESTAMP
WHERE id = $3
RETURNING *
`;
const pool = getPool();
const result = await pool.query(query, [
data.name || null,
data.description || null,
id,
]);
return result.rows[0] || null;
}
// 야드 레이아웃 삭제
async deleteLayout(id: number) {
const query = `DELETE FROM yard_layout WHERE id = $1 RETURNING *`;
const pool = getPool();
const result = await pool.query(query, [id]);
return result.rows[0] || null;
}
// 특정 야드의 모든 배치 자재 조회
async getPlacementsByLayoutId(layoutId: number) {
const query = `
SELECT
id,
yard_layout_id,
external_material_id,
material_code,
material_name,
quantity,
unit,
position_x,
position_y,
position_z,
size_x,
size_y,
size_z,
color,
memo,
created_at,
updated_at
FROM yard_material_placement
WHERE yard_layout_id = $1
ORDER BY created_at ASC
`;
const pool = getPool();
const result = await pool.query(query, [layoutId]);
return result.rows;
}
// 야드에 자재 배치 추가
async addMaterialPlacement(layoutId: number, data: any) {
const query = `
INSERT INTO yard_material_placement (
yard_layout_id,
external_material_id,
material_code,
material_name,
quantity,
unit,
position_x,
position_y,
position_z,
size_x,
size_y,
size_z,
color,
memo
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
RETURNING *
`;
const pool = getPool();
const result = await pool.query(query, [
layoutId,
data.external_material_id,
data.material_code,
data.material_name,
data.quantity,
data.unit,
data.position_x || 0,
data.position_y || 0,
data.position_z || 0,
data.size_x || 5,
data.size_y || 5,
data.size_z || 5,
data.color || "#3b82f6",
data.memo || null,
]);
return result.rows[0];
}
// 배치 정보 수정 (위치, 크기, 색상, 메모만)
async updatePlacement(placementId: number, data: any) {
const query = `
UPDATE yard_material_placement
SET
position_x = COALESCE($1, position_x),
position_y = COALESCE($2, position_y),
position_z = COALESCE($3, position_z),
size_x = COALESCE($4, size_x),
size_y = COALESCE($5, size_y),
size_z = COALESCE($6, size_z),
color = COALESCE($7, color),
memo = COALESCE($8, memo),
updated_at = CURRENT_TIMESTAMP
WHERE id = $9
RETURNING *
`;
const pool = getPool();
const result = await pool.query(query, [
data.position_x,
data.position_y,
data.position_z,
data.size_x,
data.size_y,
data.size_z,
data.color,
data.memo,
placementId,
]);
return result.rows[0] || null;
}
// 배치 해제 (자재는 삭제되지 않음)
async removePlacement(placementId: number) {
const query = `DELETE FROM yard_material_placement WHERE id = $1 RETURNING *`;
const pool = getPool();
const result = await pool.query(query, [placementId]);
return result.rows[0] || null;
}
// 여러 배치 일괄 업데이트
async batchUpdatePlacements(layoutId: number, placements: any[]) {
const pool = getPool();
const client = await pool.connect();
try {
await client.query("BEGIN");
const results = [];
for (const placement of placements) {
const query = `
UPDATE yard_material_placement
SET
position_x = $1,
position_y = $2,
position_z = $3,
size_x = $4,
size_y = $5,
size_z = $6,
updated_at = CURRENT_TIMESTAMP
WHERE id = $7 AND yard_layout_id = $8
RETURNING *
`;
const result = await client.query(query, [
placement.position_x,
placement.position_y,
placement.position_z,
placement.size_x,
placement.size_y,
placement.size_z,
placement.id,
layoutId,
]);
if (result.rows[0]) {
results.push(result.rows[0]);
}
}
await client.query("COMMIT");
return results;
} catch (error) {
await client.query("ROLLBACK");
throw error;
} finally {
client.release();
}
}
// 야드 레이아웃 복제
async duplicateLayout(id: number, newName: string) {
const pool = getPool();
const client = await pool.connect();
try {
await client.query("BEGIN");
// 원본 레이아웃 조회
const layoutQuery = `SELECT * FROM yard_layout WHERE id = $1`;
const layoutResult = await client.query(layoutQuery, [id]);
const originalLayout = layoutResult.rows[0];
if (!originalLayout) {
throw new Error("Layout not found");
}
// 새 레이아웃 생성
const newLayoutQuery = `
INSERT INTO yard_layout (name, description, created_by)
VALUES ($1, $2, $3)
RETURNING *
`;
const newLayoutResult = await client.query(newLayoutQuery, [
newName,
originalLayout.description,
originalLayout.created_by,
]);
const newLayout = newLayoutResult.rows[0];
// 배치 자재 복사
const placementsQuery = `SELECT * FROM yard_material_placement WHERE yard_layout_id = $1`;
const placementsResult = await client.query(placementsQuery, [id]);
for (const placement of placementsResult.rows) {
await client.query(
`
INSERT INTO yard_material_placement (
yard_layout_id, external_material_id, material_code, material_name,
quantity, unit, position_x, position_y, position_z,
size_x, size_y, size_z, color, memo
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
`,
[
newLayout.id,
placement.external_material_id,
placement.material_code,
placement.material_name,
placement.quantity,
placement.unit,
placement.position_x,
placement.position_y,
placement.position_z,
placement.size_x,
placement.size_y,
placement.size_z,
placement.color,
placement.memo,
]
);
}
await client.query("COMMIT");
return newLayout;
} catch (error) {
await client.query("ROLLBACK");
throw error;
} finally {
client.release();
}
}
}
export default new YardLayoutService();