Actualizar server.js
This commit is contained in:
116
server.js
116
server.js
@@ -4432,6 +4432,122 @@ app.post("/webhook/stripe", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 🛡️ MÓDULO SAAS: PLANES DE PROTECCIÓN
|
||||
// ==========================================
|
||||
|
||||
// 1. DASHBOARD: Estadísticas
|
||||
app.get("/protection/dashboard", authMiddleware, async (req, res) => {
|
||||
const cid = req.user.accountId;
|
||||
try {
|
||||
const [statsQ, actQ, topQ] = await Promise.all([
|
||||
pool.query(`
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM protection_subscriptions WHERE company_id = $1) as total,
|
||||
(SELECT COALESCE(SUM(p.price), 0) FROM protection_subscriptions s JOIN protection_plans p ON s.plan_id = p.id WHERE s.company_id = $1 AND s.status = 'activo') as mrr,
|
||||
(SELECT COALESCE(SUM(urgencies_used), 0) FROM protection_subscriptions WHERE company_id = $1) as urgUsed,
|
||||
(SELECT COALESCE(SUM(bricos_used), 0) FROM protection_subscriptions WHERE company_id = $1) as briUsed,
|
||||
(SELECT COUNT(*) FROM protection_subscriptions WHERE company_id = $1 AND payment_status = 'impagado') as unpaid
|
||||
`, [cid]),
|
||||
pool.query("SELECT * FROM protection_activity WHERE company_id = $1 ORDER BY created_at DESC LIMIT 10", [cid]),
|
||||
pool.query(`
|
||||
SELECT p.*, COUNT(s.id) as users
|
||||
FROM protection_plans p
|
||||
LEFT JOIN protection_subscriptions s ON p.id = s.plan_id
|
||||
WHERE p.company_id = $1
|
||||
GROUP BY p.id
|
||||
`, [cid])
|
||||
]);
|
||||
|
||||
res.json({ ok: true, stats: statsQ.rows[0], activity: actQ.rows, topPlans: topQ.rows });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
// 2. PLANES
|
||||
app.get("/protection/plans", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const q = await pool.query("SELECT * FROM protection_plans WHERE company_id = $1 ORDER BY created_at DESC", [req.user.accountId]);
|
||||
res.json({ ok: true, plans: q.rows });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
app.post("/protection/plans", authMiddleware, async (req, res) => {
|
||||
const cid = req.user.accountId;
|
||||
const { name, type, price, renewal, urgencies, bricos, coverages } = req.body;
|
||||
try {
|
||||
await pool.query(
|
||||
"INSERT INTO protection_plans (company_id, name, type, price, renewal_price, urgencies_limit, bricos_limit, coverages) VALUES ($1,$2,$3,$4,$5,$6,$7,$8)",
|
||||
[cid, name, type, price, renewal, urgencies, bricos, coverages]
|
||||
);
|
||||
await pool.query("INSERT INTO protection_activity (company_id, type, description) VALUES ($1, 'alta', $2)", [cid, `Nuevo plan creado: ${name}`]);
|
||||
res.json({ ok: true });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
// 3. SUSCRIPTORES
|
||||
app.get("/protection/subscribers", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const q = await pool.query(`
|
||||
SELECT s.*, p.name as plan_name, p.price as plan_price, p.urgencies_limit, p.bricos_limit
|
||||
FROM protection_subscriptions s
|
||||
LEFT JOIN protection_plans p ON s.plan_id = p.id
|
||||
WHERE s.company_id = $1 ORDER BY s.created_at DESC
|
||||
`, [req.user.accountId]);
|
||||
res.json({ ok: true, subscribers: q.rows });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
app.post("/protection/subscribers", authMiddleware, async (req, res) => {
|
||||
const cid = req.user.accountId;
|
||||
const { plan_id, name, dni, phone, payment_status, status, renewal_date, bricos_used, urgencies_used } = req.body;
|
||||
|
||||
try {
|
||||
const d = renewal_date ? renewal_date : null;
|
||||
await pool.query(
|
||||
`INSERT INTO protection_subscriptions
|
||||
(company_id, plan_id, client_name, client_dni, client_phone, payment_status, status, renewal_date, bricos_used, urgencies_used)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)`,
|
||||
[cid, plan_id, name, dni, phone, payment_status, status, d, bricos_used, urgencies_used]
|
||||
);
|
||||
await pool.query("INSERT INTO protection_activity (company_id, type, description) VALUES ($1, 'alta', $2)", [cid, `Suscripción creada: ${name}`]);
|
||||
res.json({ ok: true });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
app.put("/protection/subscribers/:id/toggle", authMiddleware, async (req, res) => {
|
||||
const cid = req.user.accountId;
|
||||
const { id } = req.params;
|
||||
const { field, value } = req.body;
|
||||
try {
|
||||
if (!['payment_status', 'status'].includes(field)) throw new Error("Invalid field");
|
||||
await pool.query(`UPDATE protection_subscriptions SET ${field} = $1 WHERE id = $2 AND company_id = $3`, [value, id, cid]);
|
||||
await pool.query("INSERT INTO protection_activity (company_id, type, description) VALUES ($1, 'cobro', $2)", [cid, `Cambiado a ${value} en ID: ${id}`]);
|
||||
res.json({ ok: true });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
// 4. CONFIGURACIÓN
|
||||
app.get("/protection/config", authMiddleware, async (req, res) => {
|
||||
try {
|
||||
const q = await pool.query("SELECT * FROM protection_config WHERE company_id = $1", [req.user.accountId]);
|
||||
res.json({ ok: true, config: q.rows[0] || {} });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
app.post("/protection/config", authMiddleware, async (req, res) => {
|
||||
const cid = req.user.accountId;
|
||||
const { name, email, phone, auto_renew, pre_notice, billing_method, contract_text } = req.body;
|
||||
try {
|
||||
await pool.query(`
|
||||
INSERT INTO protection_config (company_id, name, email, phone, auto_renew, pre_notice, billing_method, contract_text)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT (company_id) DO UPDATE SET
|
||||
name=EXCLUDED.name, email=EXCLUDED.email, phone=EXCLUDED.phone, auto_renew=EXCLUDED.auto_renew,
|
||||
pre_notice=EXCLUDED.pre_notice, billing_method=EXCLUDED.billing_method, contract_text=EXCLUDED.contract_text
|
||||
`, [cid, name, email, phone, auto_renew, pre_notice, billing_method, contract_text]);
|
||||
res.json({ ok: true });
|
||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 🕒 EL RELOJ DEL SISTEMA (Ejecutar cada minuto)
|
||||
// ==========================================
|
||||
|
||||
Reference in New Issue
Block a user