Actualizar server.js

This commit is contained in:
2026-04-02 21:38:25 +00:00
parent 13604ddc39
commit d297404c32

119
server.js
View File

@@ -4566,6 +4566,125 @@ app.post("/protection/config", authMiddleware, async (req, res) => {
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
});
// ==========================================
// 🛡️ RUTAS PÚBLICAS: CONTRATACIÓN DE PLANES
// ==========================================
// 1. Obtener la información pública de la empresa, planes y comprobar si YA tiene seguro
app.get("/public/portal/:token/protection", async (req, res) => {
try {
const { token } = req.params;
// Identificar al cliente y sacar el ID de la empresa dueña
const clientQ = await pool.query("SELECT id, full_name, phone, owner_id FROM clients WHERE portal_token = $1", [token]);
if (clientQ.rowCount === 0) return res.status(404).json({ ok: false, error: "Token inválido" });
const client = clientQ.rows[0];
const ownerId = client.owner_id;
// Comprobar si el cliente YA tiene un plan activo
let cleanPhone = String(client.phone || "").replace(/[^0-9]/g, "");
if (cleanPhone.length > 9) cleanPhone = cleanPhone.slice(-9);
const subQ = await pool.query(`
SELECT s.status, p.name as plan_name
FROM protection_subscriptions s
JOIN protection_plans p ON s.plan_id = p.id
WHERE s.company_id = $1 AND s.client_phone LIKE $2 AND s.status != 'expirado'
ORDER BY s.created_at DESC LIMIT 1
`, [ownerId, `%${cleanPhone}%`]);
const hasActivePlan = subQ.rowCount > 0;
const activePlanDetails = hasActivePlan ? subQ.rows[0] : null;
// Extraer datos de la empresa, configuración y planes
const [companyQ, configQ, plansQ] = await Promise.all([
pool.query("SELECT full_name FROM users WHERE id = $1", [ownerId]),
pool.query("SELECT contract_text FROM protection_config WHERE company_id = $1", [ownerId]),
pool.query("SELECT * FROM protection_plans WHERE company_id = $1 ORDER BY price DESC", [ownerId])
]);
res.json({
ok: true,
client: { name: client.full_name },
company: { name: companyQ.rows[0]?.full_name || "Empresa" },
config: configQ.rows[0] || {},
plans: plansQ.rows,
hasActivePlan: hasActivePlan,
activePlanDetails: activePlanDetails
});
} catch (e) {
console.error("Error cargando portal protección:", e);
res.status(500).json({ ok: false, error: "Error interno del servidor" });
}
});
// 2. Firmar contrato, generar suscripción y redirigir a Stripe
app.post("/public/portal/:token/protection/subscribe", async (req, res) => {
try {
const { token } = req.params;
const { plan_id, signature, pdf_document } = req.body; // pdf_document viene en Base64
// 1. Validar cliente
const clientQ = await pool.query("SELECT * FROM clients WHERE portal_token = $1", [token]);
if (clientQ.rowCount === 0) return res.status(404).json({ ok: false, error: "Token inválido" });
const client = clientQ.rows[0];
const ownerId = client.owner_id;
// 2. Validar Plan
const planQ = await pool.query("SELECT * FROM protection_plans WHERE id = $1 AND company_id = $2", [plan_id, ownerId]);
if (planQ.rowCount === 0) return res.status(404).json({ ok: false, error: "El plan seleccionado no existe" });
const plan = planQ.rows[0];
// 3. Crear suscripción en la Base de Datos (Estado: Impagado hasta que Stripe confirme)
const subInsert = await pool.query(`
INSERT INTO protection_subscriptions (company_id, plan_id, client_name, client_dni, client_phone, payment_status, status)
VALUES ($1, $2, $3, $4, $5, 'impagado', 'activo')
RETURNING id
`, [ownerId, plan.id, client.full_name, null, client.phone]);
const subscriptionId = subInsert.rows[0].id;
// 4. Guardamos la firma y el registro
await pool.query("UPDATE protection_subscriptions SET contract_pdf_url = $1 WHERE id = $2", ['PDF_FIRMADO_BASE64', subscriptionId]);
await pool.query("INSERT INTO protection_activity (company_id, type, description) VALUES ($1, 'alta', $2)", [ownerId, `Suscripción iniciada vía Web: ${client.full_name} (${plan.name})`]);
// 5. Integración con Stripe
const ownerConfigQ = await pool.query("SELECT billing_settings FROM users WHERE id = $1", [ownerId]);
const billingSettings = ownerConfigQ.rows[0]?.billing_settings || {};
if (!billingSettings.stripe_enabled || !billingSettings.stripe_sk) {
return res.status(400).json({ ok: false, error: "La empresa no tiene habilitados los pagos con tarjeta." });
}
const stripe = new Stripe(billingSettings.stripe_sk, { apiVersion: "2023-10-16" });
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: [{
price_data: {
currency: 'eur',
product_data: { name: `Plan de Protección: ${plan.name}`, description: `Suscripción ${plan.type}` },
unit_amount: Math.round(plan.price * 100),
},
quantity: 1,
}],
mode: 'payment',
metadata: { subscription_id: subscriptionId, owner_id: ownerId, type: 'protection_plan' },
success_url: `https://portal.integrarepara.es/pago_exito.html?sub_id=${subscriptionId}`,
cancel_url: `https://portal.integrarepara.es/plan-tranquilidad.html?token=${token}`,
});
res.json({ ok: true, checkout_url: session.url });
} catch (e) {
console.error("Error al procesar firma de plan:", e);
res.status(500).json({ ok: false, error: "Error al generar la suscripción." });
}
});
// ==========================================
// 🕒 EL RELOJ DEL SISTEMA (Ejecutar cada minuto)
// ==========================================