import * as repo from './repository.js'; import { HttpError } from '../../utils/http.js'; import { logAudit } from '../../utils/audit.js'; function toTree(flat) { const byId = new Map(flat.map((d) => [d.id, { ...d, children: [] }])); const roots = []; for (const dept of byId.values()) { if (dept.parent_id && byId.has(dept.parent_id)) { byId.get(dept.parent_id).children.push(dept); } else { roots.push(dept); } } return roots; } export async function listTree() { const flat = await repo.findAllFlat(); return toTree(flat); } export async function createDepartment(payload, actorId) { if (!payload.name) throw new HttpError(400, 'El nombre es obligatorio'); const dept = await repo.create(payload); await logAudit({ userId: actorId, action: 'create', entityType: 'department', entityId: dept.id }); return dept; } export async function updateDepartment(id, payload, actorId) { if (!payload.name) throw new HttpError(400, 'El nombre es obligatorio'); if (Number(payload.parentId) === Number(id)) throw new HttpError(400, 'Un departamento no puede ser su propio padre'); const dept = await repo.update(id, payload); await logAudit({ userId: actorId, action: 'update', entityType: 'department', entityId: id }); return dept; } export async function deleteDepartment(id, actorId) { if (await repo.hasChildren(id)) throw new HttpError(400, 'Tiene sub-departamentos; reasignalos antes de eliminar'); if (await repo.hasUsers(id)) throw new HttpError(400, 'Tiene usuarios asignados; reasignalos antes de eliminar'); await repo.remove(id); await logAudit({ userId: actorId, action: 'delete', entityType: 'department', entityId: id }); }