208 lines
5.3 KiB
JavaScript
208 lines
5.3 KiB
JavaScript
|
// src/services/department.service.js
|
||
|
const { Department, Company, Branch, User } = require("../models");
|
||
|
const alertService = require("./alert.service");
|
||
|
|
||
|
class DepartmentService {
|
||
|
async findByCompanyId(companyId) {
|
||
|
const departments = await Department.findAll({
|
||
|
where: { companyId },
|
||
|
include: [
|
||
|
{
|
||
|
model: User,
|
||
|
attributes: ["id", "name", "email"],
|
||
|
},
|
||
|
],
|
||
|
});
|
||
|
|
||
|
const buildHierarchy = (items) => {
|
||
|
const map = new Map();
|
||
|
const roots = [];
|
||
|
|
||
|
items.forEach((item) => {
|
||
|
map.set(item.id, { ...item.get({ plain: true }), children: [] });
|
||
|
});
|
||
|
|
||
|
items.forEach((item) => {
|
||
|
if (item.parentId) {
|
||
|
const parent = map.get(item.parentId);
|
||
|
if (parent) {
|
||
|
parent.children.push(map.get(item.id));
|
||
|
}
|
||
|
} else {
|
||
|
roots.push(map.get(item.id));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
return roots;
|
||
|
};
|
||
|
|
||
|
return buildHierarchy(departments);
|
||
|
}
|
||
|
|
||
|
async findById(id) {
|
||
|
return await Department.findByPk(id, {
|
||
|
include: [
|
||
|
{
|
||
|
model: Department,
|
||
|
as: "parent",
|
||
|
attributes: ["id", "name"],
|
||
|
},
|
||
|
{
|
||
|
model: Department,
|
||
|
as: "children",
|
||
|
attributes: ["id", "name"],
|
||
|
},
|
||
|
{
|
||
|
model: User,
|
||
|
attributes: ["id", "name", "email"],
|
||
|
},
|
||
|
],
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// 추가: 앱에서 사용할 부서 목록 조회 메서드
|
||
|
async findAll(currentUser, format = "flat", includeInactive = false) {
|
||
|
let where = {};
|
||
|
|
||
|
// company_admin은 자신의 회사 부서만 조회 가능
|
||
|
if (currentUser.role === "company_admin") {
|
||
|
where.companyId = currentUser.companyId;
|
||
|
}
|
||
|
|
||
|
// 활성 상태 필터링
|
||
|
if (!includeInactive) {
|
||
|
where.isActive = true;
|
||
|
}
|
||
|
|
||
|
const departments = await Department.findAll({
|
||
|
where,
|
||
|
include: [
|
||
|
{
|
||
|
model: Company,
|
||
|
attributes: ["id", "name"],
|
||
|
},
|
||
|
{
|
||
|
model: Branch,
|
||
|
attributes: ["id", "name"],
|
||
|
},
|
||
|
{
|
||
|
model: Department,
|
||
|
as: "parent",
|
||
|
attributes: ["id", "name"],
|
||
|
},
|
||
|
{
|
||
|
model: User,
|
||
|
attributes: ["id", "name"],
|
||
|
},
|
||
|
],
|
||
|
order: [
|
||
|
["parentId", "ASC NULLS FIRST"],
|
||
|
["name", "ASC"],
|
||
|
],
|
||
|
});
|
||
|
|
||
|
// 트리 구조로 반환
|
||
|
if (format === "tree") {
|
||
|
const buildHierarchy = (items, parentId = null) => {
|
||
|
return items
|
||
|
.filter((item) => item.parentId === parentId)
|
||
|
.map((item) => ({
|
||
|
...item.get({ plain: true }),
|
||
|
children: buildHierarchy(items, item.id),
|
||
|
// 추가 정보 계산
|
||
|
userCount: item.Users ? item.Users.length : 0,
|
||
|
path: this.getDepartmentPath(items, item),
|
||
|
}));
|
||
|
};
|
||
|
|
||
|
return buildHierarchy(departments);
|
||
|
}
|
||
|
|
||
|
// 평면 구조로 반환
|
||
|
return departments.map((dept) => {
|
||
|
const json = dept.get({ plain: true });
|
||
|
// 추가 정보 계산
|
||
|
json.path = this.getDepartmentPath(departments, dept);
|
||
|
json.childCount = departments.filter(
|
||
|
(d) => d.parentId === dept.id
|
||
|
).length;
|
||
|
json.userCount = dept.Users ? dept.Users.length : 0;
|
||
|
return json;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// 부서 경로 생성 헬퍼 메서드
|
||
|
getDepartmentPath(departments, department) {
|
||
|
const path = [];
|
||
|
let current = department;
|
||
|
|
||
|
while (current) {
|
||
|
path.unshift(current.name);
|
||
|
current = departments.find((d) => d.id === current.parentId);
|
||
|
}
|
||
|
|
||
|
return path.join(" > ");
|
||
|
}
|
||
|
|
||
|
async hasChildren(id) {
|
||
|
const childCount = await Department.count({
|
||
|
where: { parentId: id },
|
||
|
});
|
||
|
return childCount > 0;
|
||
|
}
|
||
|
|
||
|
async createDepartment(departmentData, user) {
|
||
|
const department = await Department.create(departmentData);
|
||
|
|
||
|
await alertService.createAlert({
|
||
|
type: "info",
|
||
|
message: `부서 ${department.name}이(가) ${user.name}에 의해 생성되었습니다.`,
|
||
|
companyId: department.companyId,
|
||
|
});
|
||
|
|
||
|
return department;
|
||
|
}
|
||
|
|
||
|
async updateDepartment(id, updateData, user) {
|
||
|
const department = await Department.findByPk(id);
|
||
|
if (!department) throw new Error("Department not found");
|
||
|
|
||
|
// parentId가 undefined이면 업데이트에서 제외, 명확히 null일 경우만 null로 설정
|
||
|
if (updateData.parentId === undefined) {
|
||
|
delete updateData.parentId;
|
||
|
} else if (updateData.parentId === null) {
|
||
|
updateData.parentId = null;
|
||
|
}
|
||
|
|
||
|
const updatedDepartment = await department.update(updateData);
|
||
|
|
||
|
await alertService.createAlert({
|
||
|
type: "info",
|
||
|
message: `부서 ${department.name}이(가) ${user.name}에 의해 수정되었습니다.`,
|
||
|
companyId: department.companyId,
|
||
|
});
|
||
|
|
||
|
return updatedDepartment;
|
||
|
}
|
||
|
|
||
|
async deleteDepartment(id, user) {
|
||
|
const department = await Department.findByPk(id);
|
||
|
if (!department) throw new Error("Department not found");
|
||
|
|
||
|
const departmentName = department.name;
|
||
|
const companyId = department.companyId;
|
||
|
|
||
|
await department.destroy();
|
||
|
|
||
|
await alertService.createAlert({
|
||
|
type: "info",
|
||
|
message: `부서 ${departmentName}이(가) ${user.name}에 의해 삭제되었습니다.`,
|
||
|
companyId: companyId,
|
||
|
});
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = new DepartmentService();
|