diff --git a/config/setup.js b/config/setup.js index 259e7b8..e6eace0 100644 --- a/config/setup.js +++ b/config/setup.js @@ -27,23 +27,37 @@ async function setup() { ) `); - // Ensure demo company exists FIRST (before migrations reference it) - const [existing] = await conn.query('SELECT id FROM companies WHERE slug = ?', ['demo']); - let companyId; - if (existing.length === 0) { - await conn.query( - 'INSERT INTO companies (name, slug, plan, max_users, max_tickets) VALUES (?, ?, ?, ?, ?)', - ['Demo Company', 'demo', 'enterprise', 100, 10000] - ); - companyId = 1; - console.log('+ Empresa demo creada'); - } else { - companyId = existing[0].id; - console.log('~ Empresa demo ya existe (id=' + companyId + ')'); + // Ensure official ecosystem companies exist: Telcotronics, XSYSTEM, DOMUS + // Migrate legacy demo / testcorp / nuevaemp if present + await conn.query(`UPDATE companies SET name = 'Telcotronics', slug = 'telcotronics', plan = 'enterprise', max_users = 100, max_tickets = 10000 WHERE slug = 'demo' OR id = 1`); + await conn.query(`UPDATE companies SET name = 'XSYSTEM', slug = 'xsystem', plan = 'enterprise', max_users = 100, max_tickets = 10000 WHERE slug = 'testcorp' OR id = 2`); + await conn.query(`UPDATE companies SET name = 'DOMUS', slug = 'domus', plan = 'enterprise', max_users = 100, max_tickets = 10000 WHERE slug = 'nuevaemp' OR id = 3`); + + const ecosystemCompanies = [ + { id: 1, name: 'Telcotronics', slug: 'telcotronics', plan: 'enterprise', max_users: 100, max_tickets: 10000 }, + { id: 2, name: 'XSYSTEM', slug: 'xsystem', plan: 'enterprise', max_users: 100, max_tickets: 10000 }, + { id: 3, name: 'DOMUS', slug: 'domus', plan: 'enterprise', max_users: 100, max_tickets: 10000 } + ]; + + for (const ec of ecosystemCompanies) { + const [found] = await conn.query('SELECT id FROM companies WHERE slug = ? OR id = ?', [ec.slug, ec.id]); + if (found.length === 0) { + await conn.query( + 'INSERT INTO companies (id, name, slug, plan, max_users, max_tickets) VALUES (?, ?, ?, ?, ?, ?)', + [ec.id, ec.name, ec.slug, ec.plan, ec.max_users, ec.max_tickets] + ); + console.log(`+ Empresa ${ec.name} creada (id=${ec.id})`); + } else { + await conn.query( + 'UPDATE companies SET name = ?, slug = ?, plan = ?, max_users = ?, max_tickets = ? WHERE id = ?', + [ec.name, ec.slug, ec.plan, ec.max_users, ec.max_tickets, found[0].id] + ); + console.log(`~ Empresa ${ec.name} sincronizada (id=${found[0].id})`); + } } - // Ensure company_id default value references existing company - const defCompanyId = companyId; + const companyId = 1; + const defCompanyId = 1; // Migrate existing tables const migrateColumn = async (table, column, definition) => { @@ -129,21 +143,23 @@ async function setup() { ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; `); - // Seed departments - const [depts] = await conn.query('SELECT COUNT(*) as c FROM departments WHERE company_id = ?', [companyId]); - if (depts[0].c === 0) { - await conn.query( - 'INSERT INTO departments (company_id, nombre, descripcion) VALUES ?', - [[ - [companyId, 'Soporte Técnico', 'Problemas técnicos y de software'], - [companyId, 'Facturación', 'Problemas de facturación y pagos'], - [companyId, 'Ventas', 'Consultas sobre ventas y productos'], - [companyId, 'General', 'Consultas generales'] - ]] - ); - console.log('+ Departamentos seed insertados'); - } else { - console.log('~ Departamentos ya existen'); + // Seed departments for all ecosystem companies + for (const ec of ecosystemCompanies) { + const [depts] = await conn.query('SELECT COUNT(*) as c FROM departments WHERE company_id = ?', [ec.id]); + if (depts[0].c === 0) { + await conn.query( + 'INSERT INTO departments (company_id, nombre, descripcion) VALUES ?', + [[ + [ec.id, 'Soporte Técnico', 'Problemas técnicos y de software'], + [ec.id, 'Facturación', 'Problemas de facturación y pagos'], + [ec.id, 'Ventas', 'Consultas sobre ventas y productos'], + [ec.id, 'General', 'Consultas generales'] + ]] + ); + console.log(`+ Departamentos seed insertados para ${ec.name}`); + } else { + console.log(`~ Departamentos ya existen para ${ec.name}`); + } } // Seed users diff --git a/middleware/auth.js b/middleware/auth.js index b5741c8..45a2e59 100644 --- a/middleware/auth.js +++ b/middleware/auth.js @@ -25,6 +25,9 @@ module.exports = { if (req.session.user && req.session.user.company_id) { const company = await Company.findById(req.session.user.company_id); res.locals.company = company; + if (req.session.user.rol === 'superadmin') { + res.locals.allCompanies = await Company.findAll(); + } } next(); }, diff --git a/models/Company.js b/models/Company.js index 5aabe19..bcb71b4 100644 --- a/models/Company.js +++ b/models/Company.js @@ -2,7 +2,7 @@ const db = require('../config/db'); const Company = { findAll: async () => { - const [rows] = await db.query('SELECT * FROM companies ORDER BY created_at DESC'); + const [rows] = await db.query('SELECT * FROM companies ORDER BY id ASC'); return rows; }, findById: async (id) => { diff --git a/public/css/style.css b/public/css/style.css index 32372d5..933a05b 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -60,6 +60,20 @@ body { color: #e2e8f0; } +.company-nav-pill.dropdown-toggle::after { + display: none !important; +} + +.company-nav-pill.dropdown-toggle { + cursor: pointer; + transition: all 0.2s ease; +} + +.company-nav-pill.dropdown-toggle:hover { + background: rgba(255, 255, 255, 0.14) !important; + border-color: rgba(255, 255, 255, 0.28) !important; +} + .company-plan-badge { background: linear-gradient(135deg, #0284c7 0%, #38bdf8 100%); color: #ffffff; diff --git a/routes/saas.js b/routes/saas.js index 7bb8c69..97d1776 100644 --- a/routes/saas.js +++ b/routes/saas.js @@ -69,4 +69,32 @@ router.post('/companies/update/:id', isSuperAdmin, async (req, res) => { } }); +router.get('/switch/:id', isSuperAdmin, async (req, res) => { + try { + const targetId = parseInt(req.params.id); + const company = await Company.findById(targetId); + if (!company) { + req.flash('error_msg', 'Empresa no encontrada'); + return res.redirect('/saas/companies'); + } + + req.session.user.company_id = company.id; + if (req.session.user.id) { + await User.update(req.session.user.id, { company_id: company.id }); + } + + req.flash('success_msg', `Cambiaste de entorno a: ${company.name}`); + const referrer = req.get('Referrer'); + // Redirigir de forma segura al referrer o al dashboard + if (referrer && !referrer.includes('/login') && !referrer.includes('/logout')) { + return res.redirect(referrer); + } + res.redirect('/admin/dashboard'); + } catch (error) { + console.error('Error switching company:', error); + req.flash('error_msg', 'Error al cambiar de empresa'); + res.redirect('/saas/companies'); + } +}); + module.exports = router; diff --git a/views/partials/navbar.ejs b/views/partials/navbar.ejs index 968674e..5d7510e 100644 --- a/views/partials/navbar.ejs +++ b/views/partials/navbar.ejs @@ -15,11 +15,43 @@ <% if (typeof company !== 'undefined' && company) { %> -