feat(fsm): implementar gestion y asignacion de sets de herramientas a tecnicos

This commit is contained in:
2026-10-31 17:07:30 -05:00
parent 06ef042538
commit c07162c375
13 changed files with 1793 additions and 9 deletions
+64 -5
View File
@@ -4,6 +4,9 @@ const { isAgent } = require('../middleware/auth');
const Ticket = require('../models/Ticket');
const Department = require('../models/Department');
const TicketVisita = require('../models/TicketVisita');
const HerramientaSet = require('../models/HerramientaSet');
const HerramientaAsignacion = require('../models/HerramientaAsignacion');
const User = require('../models/User');
const TareasHubService = require('../config/tareasHubService');
router.get('/dashboard', isAgent, async (req, res) => {
@@ -55,8 +58,9 @@ router.get('/ticket/:id', isAgent, async (req, res) => {
}
const tecnicosHub = await TareasHubService.obtenerTecnicos();
const setsHerramientas = await HerramientaSet.findAll(ticket.company_id);
res.render('agent/view-ticket', { ticket, respuestas, agents, visita, tecnicosHub });
res.render('agent/view-ticket', { ticket, respuestas, agents, visita, tecnicosHub, setsHerramientas });
} catch (error) {
console.error(error);
req.flash('error_msg', 'Error al cargar ticket');
@@ -139,7 +143,8 @@ router.post('/ticket/:id/visita', isAgent, async (req, res) => {
fechaVisita,
fechaFin,
prioridad,
checklist_items
checklist_items,
setHerramientasId
} = req.body;
if (!emailTecnico) {
@@ -147,6 +152,12 @@ router.post('/ticket/:id/visita', isAgent, async (req, res) => {
return res.redirect(`/agent/ticket/${req.params.id}`);
}
// Buscar información del set de herramientas si se seleccionó uno
let selectedSet = null;
if (setHerramientasId) {
selectedSet = await HerramientaSet.findById(setHerramientasId, ticket.company_id);
}
// Procesar checklist
let checklistArr = [];
if (typeof checklist_items === 'string') {
@@ -182,7 +193,7 @@ router.post('/ticket/:id/visita', isAgent, async (req, res) => {
});
// 2. Guardar en MariaDB ticket_visitas
await TicketVisita.create({
const visitaId = await TicketVisita.create({
company_id: ticket.company_id,
ticket_id: ticket.id,
external_id: hubRes.tareaId,
@@ -195,15 +206,39 @@ router.post('/ticket/:id/visita', isAgent, async (req, res) => {
fecha_fin: fechaFin ? new Date(fechaFin) : null,
estado: 'programada',
checklist_json: checklistArr,
historial_json: hubRes.tarea || null
historial_json: hubRes.tarea || null,
set_herramientas_id: selectedSet ? selectedSet.id : null,
set_herramientas_nombre: selectedSet ? selectedSet.nombre : null
});
// 2.1 Vincular asignación de set de herramientas a nivel FSM
if (selectedSet) {
try {
let tecUser = await User.findByEmail(emailTecnico);
if (!tecUser) {
tecUser = req.session.user;
}
await HerramientaAsignacion.create({
company_id: ticket.company_id,
tecnico_id: tecUser.id,
set_id: selectedSet.id,
ticket_visita_id: visitaId,
tipo_asignacion: 'visita_fsm',
observaciones_entrega: `Despachado con ${selectedSet.nombre} para visita FSM (Ticket #${ticket.id})`,
asignado_por: req.session.user.id
});
} catch (errAsign) {
console.warn('Advertencia registrando asignación FSM de herramientas:', errAsign.message);
}
}
// 3. Actualizar estado del ticket a 'en_progreso'
await Ticket.update(ticket.id, { status: 'en_progreso' });
// 4. Registrar respuesta en el hilo del ticket
const fechaStr = fechaVisita ? new Date(fechaVisita).toLocaleString('es-EC') : 'A coordinar';
const msgHilo = `📅 **Visita técnica programada**: Se ha asignado al técnico **${tecnicoNombre || emailTecnico}** para el **${fechaStr}**.\n\n📍 **Ubicación:** ${ubicacion || 'En sitio del cliente'}${referencia ? ` (${referencia})` : ''}\n\n📋 **Checklist operativo inicial:**\n${checklistArr.map(c => `- ${c}`).join('\n')}\n\n*ID de tarea en Hub:* \`${hubRes.tareaId}\``;
const kitInfoStr = selectedSet ? `\n🧰 **Set de Herramientas asignado:** ${selectedSet.nombre} (${selectedSet.codigo || 'Kit FSM'})` : '';
const msgHilo = `📅 **Visita técnica programada**: Se ha asignado al técnico **${tecnicoNombre || emailTecnico}** para el **${fechaStr}**.${kitInfoStr}\n\n📍 **Ubicación:** ${ubicacion || 'En sitio del cliente'}${referencia ? ` (${referencia})` : ''}\n\n📋 **Checklist operativo inicial:**\n${checklistArr.map(c => `- ${c}`).join('\n')}\n\n*ID de tarea en Hub:* \`${hubRes.tareaId}\``;
await Ticket.addResponse(ticket.id, req.session.user.id, msgHilo);
req.flash('success_msg', 'Visita técnica programada y sincronizada exitosamente con tareas.telcotronics.com');
@@ -271,4 +306,28 @@ router.post('/ticket/:id/visita/sync', isAgent, async (req, res) => {
}
});
// Panel de "Mis Herramientas & Sets Asignados" para el Técnico / Agente
router.get('/herramientas', isAgent, async (req, res) => {
try {
const companyId = req.session.user.company_id;
const tecnicoId = req.session.user.id;
const asignaciones = await HerramientaAsignacion.findByTecnico(companyId, tecnicoId);
// Agrupar asignaciones activas e historial
const activas = asignaciones.filter(a => a.estado === 'asignado');
const historial = asignaciones.filter(a => a.estado !== 'asignado');
res.render('agent/herramientas', {
title: 'Mis Herramientas',
activas,
historial
});
} catch (error) {
console.error('Error al cargar herramientas del técnico:', error);
req.flash('error_msg', 'Error al consultar herramientas asignadas');
res.redirect('/agent/dashboard');
}
});
module.exports = router;