From 9c538f7a7a1a677287f627994140fe4ac939774f Mon Sep 17 00:00:00 2001 From: marsalva Date: Fri, 3 Apr 2026 21:23:52 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 124 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 31 deletions(-) diff --git a/server.js b/server.js index c9634bf..e07adb8 100644 --- a/server.js +++ b/server.js @@ -5086,63 +5086,125 @@ app.get("/public/portal/:token/protection", async (req, res) => { } }); -// 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, dni } = req.body; - // 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 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 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 BD (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', 'suspendido') - RETURNING id - `, [ownerId, plan.id, client.full_name, dni || null, client.phone]); - - const subscriptionId = subInsert.rows[0].id; + const ownerConfigQ = await pool.query( + "SELECT billing_settings FROM users WHERE id = $1", + [ownerId] + ); + let billingSettings = ownerConfigQ.rows[0]?.billing_settings || {}; + if (typeof billingSettings === "string") { + try { billingSettings = JSON.parse(billingSettings); } catch (_) { billingSettings = {}; } + } - // 4. Guardamos la firma REAL y el registro - await pool.query("UPDATE protection_subscriptions SET contract_pdf_url = $1 WHERE id = $2", [pdf_document, 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 interval = + String(plan.billing_interval || "").toLowerCase() === "year" || + String(plan.type || "").toLowerCase().includes("anual") + ? "year" + : "month"; + + const intervalCount = Number(plan.billing_interval_count || 1); + + const subInsert = await pool.query(` + INSERT INTO protection_subscriptions ( + company_id, + plan_id, + client_name, + client_dni, + client_phone, + payment_status, + status, + contract_pdf_url + ) + VALUES ($1, $2, $3, $4, $5, 'impagado', 'pendiente_pago', $6) + RETURNING id + `, [ + ownerId, + plan.id, + client.full_name, + dni || null, + client.phone, + pdf_document || null + ]); + + const subscriptionId = subInsert.rows[0].id; + + 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})`] + ); + const session = await stripe.checkout.sessions.create({ - payment_method_types: ['card'], + payment_method_types: ["card"], + mode: "subscription", 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), + currency: "eur", + product_data: { + name: `Plan de Protección: ${plan.name}`, + description: `Suscripción ${plan.type || interval}` + }, + unit_amount: Math.round(Number(plan.price || 0) * 100), + recurring: { + interval, + interval_count: intervalCount + } }, - quantity: 1, + quantity: 1 }], - mode: 'payment', - metadata: { subscription_id: subscriptionId, owner_id: ownerId, type: 'protection_plan' }, + metadata: { + subscription_id: String(subscriptionId), + owner_id: String(ownerId), + plan_id: String(plan.id), + type: "protection_plan" + }, + customer_email: client.email || undefined, success_url: `https://portal.integrarepara.es/pago_exito.html?sub_id=${subscriptionId}`, cancel_url: `https://portal.integrarepara.es/plan-tranquilidad.html?token=${token}`, }); + await pool.query(` + UPDATE protection_subscriptions + SET stripe_session_id = $1, + stripe_price_id = $2, + updated_at = NOW() + WHERE id = $3 + `, [ + session.id, + null, + subscriptionId + ]); + res.json({ ok: true, checkout_url: session.url }); } catch (e) {