Files
help_desk/routes/admin.js
T

368 lines
14 KiB
JavaScript

const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const { isCompanyAdmin } = require('../middleware/auth');
const User = require('../models/User');
const Department = require('../models/Department');
const Ticket = require('../models/Ticket');
const Herramienta = require('../models/Herramienta');
const HerramientaSet = require('../models/HerramientaSet');
const HerramientaAsignacion = require('../models/HerramientaAsignacion');
router.get('/dashboard', isCompanyAdmin, async (req, res) => {
try {
const users = await User.findAll(req.session.user.company_id);
const tickets = await Ticket.findAll(req.session.user.company_id);
const departments = await Department.findAll(req.session.user.company_id);
const stats = await Ticket.countByStatus(req.session.user.company_id);
res.render('admin/dashboard', { users, tickets, departments, stats });
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al cargar dashboard');
res.redirect('/');
}
});
router.get('/users', isCompanyAdmin, async (req, res) => {
try {
const users = await User.findAll(req.session.user.company_id);
res.render('admin/users', { users });
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al cargar usuarios');
res.redirect('/admin/dashboard');
}
});
router.get('/users/create', isCompanyAdmin, (req, res) => {
res.render('admin/create-user');
});
router.post('/users/create', isCompanyAdmin, async (req, res) => {
const { nombre, email, password, rol } = req.body;
if (!nombre || !email || !password) {
req.flash('error_msg', 'Todos los campos son obligatorios');
return res.redirect('/admin/users/create');
}
try {
const existing = await User.findByEmail(email);
if (existing) {
req.flash('error_msg', 'El email ya existe');
return res.redirect('/admin/users/create');
}
const hashedPassword = await bcrypt.hash(password, 10);
const userId = await User.create(req.session.user.company_id, nombre, email, hashedPassword, rol || 'client');
req.flash('success_msg', 'Usuario creado exitosamente');
res.redirect('/admin/users');
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al crear usuario');
res.redirect('/admin/users/create');
}
});
router.post('/users/invite/:id', isCompanyAdmin, async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user || user.company_id !== req.session.user.company_id) {
req.flash('error_msg', 'Usuario no encontrado');
return res.redirect('/admin/users');
}
const token = await User.generateInviteToken(user.id);
const inviteLink = `${req.protocol}://${req.get('host')}/invite/${token}`;
req.flash('success_msg', `Link de invitación: ${inviteLink}`);
res.redirect('/admin/users');
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al generar invitación');
res.redirect('/admin/users');
}
});
router.post('/users/delete/:id', isCompanyAdmin, async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user || user.company_id !== req.session.user.company_id) {
req.flash('error_msg', 'Usuario no encontrado');
return res.redirect('/admin/users');
}
if (user.rol === 'superadmin') {
req.flash('error_msg', 'No puedes eliminar al superadmin');
return res.redirect('/admin/users');
}
await User.delete(req.params.id);
req.flash('success_msg', 'Usuario eliminado');
res.redirect('/admin/users');
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al eliminar usuario');
res.redirect('/admin/users');
}
});
router.get('/departments', isCompanyAdmin, async (req, res) => {
try {
const departments = await Department.findAll(req.session.user.company_id);
res.render('admin/departments', { departments });
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al cargar departamentos');
res.redirect('/admin/dashboard');
}
});
router.post('/departments/create', isCompanyAdmin, async (req, res) => {
const { nombre, descripcion } = req.body;
if (!nombre) {
req.flash('error_msg', 'El nombre es obligatorio');
return res.redirect('/admin/departments');
}
try {
await Department.create(req.session.user.company_id, nombre, descripcion || '');
req.flash('success_msg', 'Departamento creado');
res.redirect('/admin/departments');
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al crear departamento');
res.redirect('/admin/departments');
}
});
router.post('/departments/update/:id', isCompanyAdmin, async (req, res) => {
const { nombre, descripcion } = req.body;
try {
await Department.update(req.params.id, nombre, descripcion || '');
req.flash('success_msg', 'Departamento actualizado');
res.redirect('/admin/departments');
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al actualizar departamento');
res.redirect('/admin/departments');
}
});
router.post('/departments/delete/:id', isCompanyAdmin, async (req, res) => {
try {
await Department.delete(req.params.id);
req.flash('success_msg', 'Departamento eliminado');
res.redirect('/admin/departments');
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al eliminar departamento');
res.redirect('/admin/departments');
}
});
// ==========================================
// GESTIÓN DE HERRAMIENTAS Y SETS / KITS FSM
// ==========================================
router.get('/herramientas', isCompanyAdmin, async (req, res) => {
try {
const companyId = req.session.user.company_id;
const [herramientas, sets, asignaciones, stats, allUsers] = await Promise.all([
Herramienta.findAll(companyId),
HerramientaSet.findAll(companyId),
HerramientaAsignacion.findAll(companyId),
Herramienta.countByEstado(companyId),
User.findAll(companyId)
]);
const tecnicos = allUsers.filter(u => u.rol === 'agent' || u.rol === 'admin');
res.render('admin/herramientas', {
title: 'Herramientas & Sets',
herramientas,
sets,
asignaciones,
stats,
tecnicos
});
} catch (error) {
console.error('Error al cargar herramientas:', error);
req.flash('error_msg', 'Error al cargar gestión de herramientas');
res.redirect('/admin/dashboard');
}
});
// Crear Herramienta Individual
router.post('/herramientas/create', isCompanyAdmin, async (req, res) => {
const { nombre, codigo, numero_serie, categoria, marca, modelo, estado, ubicacion_bodega, notas } = req.body;
if (!nombre) {
req.flash('error_msg', 'El nombre de la herramienta es obligatorio');
return res.redirect('/admin/herramientas');
}
try {
await Herramienta.create({
company_id: req.session.user.company_id,
nombre,
codigo: codigo || null,
numero_serie: numero_serie || null,
categoria: categoria || 'general',
marca: marca || null,
modelo: modelo || null,
estado: estado || 'operativo',
ubicacion_bodega: ubicacion_bodega || null,
notas: notas || null
});
req.flash('success_msg', `Herramienta "${nombre}" registrada correctamente`);
res.redirect('/admin/herramientas#tab-herramientas');
} catch (error) {
console.error('Error al crear herramienta:', error);
req.flash('error_msg', 'Error al registrar la herramienta: ' + error.message);
res.redirect('/admin/herramientas');
}
});
// Editar Herramienta Individual
router.post('/herramientas/edit/:id', isCompanyAdmin, async (req, res) => {
const { nombre, codigo, numero_serie, categoria, marca, modelo, estado, ubicacion_bodega, notas } = req.body;
try {
await Herramienta.update(req.params.id, req.session.user.company_id, {
nombre,
codigo,
numero_serie,
categoria,
marca,
modelo,
estado,
ubicacion_bodega,
notas
});
req.flash('success_msg', 'Herramienta actualizada exitosamente');
res.redirect('/admin/herramientas#tab-herramientas');
} catch (error) {
console.error('Error al actualizar herramienta:', error);
req.flash('error_msg', 'Error al actualizar herramienta: ' + error.message);
res.redirect('/admin/herramientas');
}
});
// Eliminar Herramienta Individual
router.post('/herramientas/delete/:id', isCompanyAdmin, async (req, res) => {
try {
await Herramienta.delete(req.params.id, req.session.user.company_id);
req.flash('success_msg', 'Herramienta eliminada');
res.redirect('/admin/herramientas#tab-herramientas');
} catch (error) {
console.error('Error al eliminar herramienta:', error);
req.flash('error_msg', 'Error al eliminar herramienta');
res.redirect('/admin/herramientas');
}
});
// Crear Set / Kit de Herramientas
router.post('/herramientas/sets/create', isCompanyAdmin, async (req, res) => {
const { nombre, codigo, descripcion, categoria, herramientas_ids } = req.body;
if (!nombre) {
req.flash('error_msg', 'El nombre del Set / Kit es obligatorio');
return res.redirect('/admin/herramientas');
}
try {
let items = [];
if (Array.isArray(herramientas_ids)) {
items = herramientas_ids;
} else if (herramientas_ids) {
items = [herramientas_ids];
}
await HerramientaSet.create({
company_id: req.session.user.company_id,
nombre,
codigo: codigo || null,
descripcion: descripcion || null,
categoria: categoria || 'general'
}, items);
req.flash('success_msg', `Kit de herramientas "${nombre}" creado con ${items.length} instrumentos.`);
res.redirect('/admin/herramientas#tab-sets');
} catch (error) {
console.error('Error al crear set de herramientas:', error);
req.flash('error_msg', 'Error al crear set: ' + error.message);
res.redirect('/admin/herramientas');
}
});
// Editar Set / Kit de Herramientas
router.post('/herramientas/sets/edit/:id', isCompanyAdmin, async (req, res) => {
const { nombre, codigo, descripcion, categoria, is_active, herramientas_ids } = req.body;
try {
let items = null;
if (herramientas_ids !== undefined) {
items = Array.isArray(herramientas_ids) ? herramientas_ids : (herramientas_ids ? [herramientas_ids] : []);
}
await HerramientaSet.update(req.params.id, req.session.user.company_id, {
nombre,
codigo,
descripcion,
categoria,
is_active: is_active === '1' || is_active === 1 ? 1 : 0
}, items);
req.flash('success_msg', 'Set / Kit actualizado exitosamente');
res.redirect('/admin/herramientas#tab-sets');
} catch (error) {
console.error('Error al actualizar set:', error);
req.flash('error_msg', 'Error al actualizar set: ' + error.message);
res.redirect('/admin/herramientas');
}
});
// Eliminar Set / Kit de Herramientas
router.post('/herramientas/sets/delete/:id', isCompanyAdmin, async (req, res) => {
try {
await HerramientaSet.delete(req.params.id, req.session.user.company_id);
req.flash('success_msg', 'Set / Kit eliminado');
res.redirect('/admin/herramientas#tab-sets');
} catch (error) {
console.error('Error al eliminar set:', error);
req.flash('error_msg', 'Error al eliminar set');
res.redirect('/admin/herramientas');
}
});
// Asignar Set de Herramientas a Técnico (Dotación Fija)
router.post('/herramientas/asignar', isCompanyAdmin, async (req, res) => {
const { tecnico_id, set_id, herramienta_id, tipo_asignacion, observaciones_entrega } = req.body;
if (!tecnico_id || (!set_id && !herramienta_id)) {
req.flash('error_msg', 'Debe seleccionar un técnico y al menos un set o herramienta');
return res.redirect('/admin/herramientas');
}
try {
await HerramientaAsignacion.create({
company_id: req.session.user.company_id,
tecnico_id: parseInt(tecnico_id),
set_id: set_id ? parseInt(set_id) : null,
herramienta_id: herramienta_id ? parseInt(herramienta_id) : null,
tipo_asignacion: tipo_asignacion || 'dotacion_fija',
observaciones_entrega: observaciones_entrega || 'Asignación administrativa de equipamiento',
asignado_por: req.session.user.id
});
req.flash('success_msg', 'Equipamiento asignado al técnico exitosamente');
res.redirect('/admin/herramientas#tab-asignaciones');
} catch (error) {
console.error('Error al asignar herramientas:', error);
req.flash('error_msg', 'Error al asignar equipamiento: ' + error.message);
res.redirect('/admin/herramientas');
}
});
// Registrar Devolución de Herramientas
router.post('/herramientas/devolver/:id', isCompanyAdmin, async (req, res) => {
const { observaciones_devolucion, estado } = req.body;
try {
await HerramientaAsignacion.devolver(req.params.id, req.session.user.company_id, {
observaciones_devolucion: observaciones_devolucion || 'Devuelto conforme a bodega',
estado: estado || 'devuelto'
});
req.flash('success_msg', 'Devolución de herramientas registrada correctamente');
res.redirect('/admin/herramientas#tab-asignaciones');
} catch (error) {
console.error('Error al registrar devolución:', error);
req.flash('error_msg', 'Error al registrar devolución');
res.redirect('/admin/herramientas');
}
});
module.exports = router;