diff --git a/server.js b/server.js index 07c200d..4974b45 100644 --- a/server.js +++ b/server.js @@ -29,14 +29,14 @@ const pool = new Pool({ }); // ========================================== -// 🧠 AUTO-ACTUALIZACIÓN DB +// 🧠 AUTO-ACTUALIZACIÓN DB (REPARADOR DEEP) // ========================================== async function autoUpdateDB() { const client = await pool.connect(); try { console.log("🔄 Verificando salud de la base de datos..."); - // 1. CREAR TABLAS (Estructura Base) + // 1. DEFINICIÓN BASE (Para instalaciones nuevas) await client.query(` CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, @@ -106,8 +106,8 @@ async function autoUpdateDB() { owner_id INT REFERENCES users(id) ON DELETE CASCADE, client_id INT REFERENCES clients(id) ON DELETE SET NULL, status_id INT REFERENCES service_statuses(id) ON DELETE SET NULL, - guild_id INT REFERENCES guilds(id) ON DELETE SET NULL, -- NUEVO - assigned_to INT REFERENCES users(id) ON DELETE SET NULL, -- NUEVO + guild_id INT REFERENCES guilds(id) ON DELETE SET NULL, + assigned_to INT REFERENCES users(id) ON DELETE SET NULL, title TEXT, description TEXT, contact_phone TEXT, @@ -137,40 +137,94 @@ async function autoUpdateDB() { ); `); - // 2. PARCHE DE REPARACIÓN + // 2. PARCHE DE REPARACIÓN MANUAL (AQUÍ ESTÁ LA SOLUCIÓN) + // Este bloque fuerza la creación de columnas si no existen await client.query(` DO $$ BEGIN - -- Nuevas columnas Asignación - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='guild_id') THEN ALTER TABLE services ADD COLUMN guild_id INT REFERENCES guilds(id) ON DELETE SET NULL; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='assigned_to') THEN ALTER TABLE services ADD COLUMN assigned_to INT REFERENCES users(id) ON DELETE SET NULL; END IF; + -- Client ID + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_id') THEN + ALTER TABLE services ADD COLUMN client_id INT REFERENCES clients(id) ON DELETE SET NULL; + END IF; - -- Reparaciones anteriores - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='email') THEN ALTER TABLE services ADD COLUMN email TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='address') THEN ALTER TABLE services ADD COLUMN address TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='description') THEN ALTER TABLE services ADD COLUMN description TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='title') THEN ALTER TABLE services ADD COLUMN title TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_id') THEN ALTER TABLE services ADD COLUMN client_id INT REFERENCES clients(id) ON DELETE SET NULL; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='status_id') THEN ALTER TABLE services ADD COLUMN status_id INT REFERENCES service_statuses(id) ON DELETE SET NULL; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_phone') THEN ALTER TABLE services ADD COLUMN contact_phone TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_name') THEN ALTER TABLE services ADD COLUMN contact_name TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_date') THEN ALTER TABLE services ADD COLUMN scheduled_date DATE DEFAULT CURRENT_DATE; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_time') THEN ALTER TABLE services ADD COLUMN scheduled_time TIME DEFAULT CURRENT_TIME; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='duration_minutes') THEN ALTER TABLE services ADD COLUMN duration_minutes INT DEFAULT 30; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_id') THEN ALTER TABLE services ADD COLUMN company_id INT REFERENCES companies(id) ON DELETE SET NULL; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_company') THEN ALTER TABLE services ADD COLUMN is_company BOOLEAN DEFAULT FALSE; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_ref') THEN ALTER TABLE services ADD COLUMN company_ref TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='internal_notes') THEN ALTER TABLE services ADD COLUMN internal_notes TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_notes') THEN ALTER TABLE services ADD COLUMN client_notes TEXT; END IF; - IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_urgent') THEN ALTER TABLE services ADD COLUMN is_urgent BOOLEAN DEFAULT FALSE; END IF; + -- Status ID + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='status_id') THEN + ALTER TABLE services ADD COLUMN status_id INT REFERENCES service_statuses(id) ON DELETE SET NULL; + END IF; + -- Guild ID & Assigned To + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='guild_id') THEN + ALTER TABLE services ADD COLUMN guild_id INT REFERENCES guilds(id) ON DELETE SET NULL; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='assigned_to') THEN + ALTER TABLE services ADD COLUMN assigned_to INT REFERENCES users(id) ON DELETE SET NULL; + END IF; + + -- Contact Info + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_phone') THEN + ALTER TABLE services ADD COLUMN contact_phone TEXT; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='contact_name') THEN + ALTER TABLE services ADD COLUMN contact_name TEXT; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='address') THEN + ALTER TABLE services ADD COLUMN address TEXT; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='email') THEN + ALTER TABLE services ADD COLUMN email TEXT; + END IF; + + -- Details + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='title') THEN + ALTER TABLE services ADD COLUMN title TEXT; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='description') THEN + ALTER TABLE services ADD COLUMN description TEXT; + END IF; + + -- Scheduling + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_date') THEN + ALTER TABLE services ADD COLUMN scheduled_date DATE DEFAULT CURRENT_DATE; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='scheduled_time') THEN + ALTER TABLE services ADD COLUMN scheduled_time TIME DEFAULT CURRENT_TIME; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='duration_minutes') THEN + ALTER TABLE services ADD COLUMN duration_minutes INT DEFAULT 30; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_urgent') THEN + ALTER TABLE services ADD COLUMN is_urgent BOOLEAN DEFAULT FALSE; + END IF; + + -- Company & Notes + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_id') THEN + ALTER TABLE services ADD COLUMN company_id INT REFERENCES companies(id) ON DELETE SET NULL; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='is_company') THEN + ALTER TABLE services ADD COLUMN is_company BOOLEAN DEFAULT FALSE; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='company_ref') THEN + ALTER TABLE services ADD COLUMN company_ref TEXT; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='internal_notes') THEN + ALTER TABLE services ADD COLUMN internal_notes TEXT; + END IF; + IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='services' AND column_name='client_notes') THEN + ALTER TABLE services ADD COLUMN client_notes TEXT; + END IF; + + -- Clean up old constraints BEGIN ALTER TABLE users DROP CONSTRAINT IF EXISTS users_phone_key; EXCEPTION WHEN OTHERS THEN NULL; END; BEGIN ALTER TABLE users DROP CONSTRAINT IF EXISTS users_email_key; EXCEPTION WHEN OTHERS THEN NULL; END; END $$; `); - console.log("✅ DB Lista."); - } catch (e) { console.error("❌ Error DB:", e); } finally { client.release(); } + console.log("✅ DB Sincronizada y Reparada Exitosamente."); + } catch (e) { + console.error("❌ Error DB:", e); + } finally { + client.release(); + } } // HELPERS @@ -247,16 +301,11 @@ app.get("/clients/search", authMiddleware, async (req, res) => { app.get("/companies", authMiddleware, async (req, res) => { try { const q = await pool.query("SELECT * FROM companies WHERE owner_id=$1 ORDER BY name ASC", [req.user.accountId]); res.json({ ok: true, companies: q.rows }); } catch (e) { res.status(500).json({ ok: false }); } }); app.post("/companies", authMiddleware, async (req, res) => { try { const { name } = req.body; await pool.query("INSERT INTO companies (name, owner_id) VALUES ($1, $2)", [name, req.user.accountId]); res.json({ ok: true }); } catch (e) { res.status(500).json({ ok: false }); } }); -// NUEVO: OBTENER OPERARIOS FILTRADOS POR GREMIO +// OBTENER OPERARIOS POR GREMIO app.get("/operators", authMiddleware, async (req, res) => { try { const { guild_id } = req.query; - let query = ` - SELECT u.id, u.full_name - FROM users u - JOIN user_guilds ug ON u.id = ug.user_id - WHERE u.owner_id = $1 AND u.role = 'operario' - `; + let query = `SELECT u.id, u.full_name FROM users u JOIN user_guilds ug ON u.id = ug.user_id WHERE u.owner_id = $1 AND u.role = 'operario'`; const params = [req.user.accountId]; if (guild_id) { query += ` AND ug.guild_id = $2`; params.push(guild_id); } query += ` GROUP BY u.id ORDER BY u.full_name ASC`; @@ -307,14 +356,7 @@ app.put("/services/:id/status", authMiddleware, async (req, res) => { app.post("/services", authMiddleware, async (req, res) => { const client = await pool.connect(); try { - const { - phone, name, address, email, description, - scheduled_date, scheduled_time, duration, is_urgent, - is_company, company_id, company_ref, - internal_notes, client_notes, status_id, - guild_id, assigned_to // NUEVOS CAMPOS - } = req.body; - + const { phone, name, address, email, description, scheduled_date, scheduled_time, duration, is_urgent, is_company, company_id, company_ref, internal_notes, client_notes, status_id, guild_id, assigned_to } = req.body; const p = normalizePhone(phone); await client.query('BEGIN'); @@ -357,7 +399,6 @@ app.post("/services", authMiddleware, async (req, res) => { } catch (e) { await client.query('ROLLBACK'); console.error(e); res.status(500).json({ ok: false, error: e.message }); } finally { client.release(); } }); -// EDITAR (Con asignación) app.put("/services/:id", authMiddleware, async (req, res) => { const client = await pool.connect(); try { @@ -366,7 +407,7 @@ app.put("/services/:id", authMiddleware, async (req, res) => { scheduled_date, scheduled_time, duration, is_urgent, is_company, company_id, company_ref, internal_notes, client_notes, - guild_id, assigned_to // NUEVOS CAMPOS + guild_id, assigned_to } = req.body; await client.query('BEGIN');