From 1dd50bc820253dba7cd7410864792101ee8fc7f8 Mon Sep 17 00:00:00 2001 From: marsalva Date: Fri, 3 Apr 2026 10:04:05 +0000 Subject: [PATCH] Actualizar server.js --- server.js | 78 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/server.js b/server.js index 494cb19..29c62b2 100644 --- a/server.js +++ b/server.js @@ -4399,47 +4399,55 @@ app.post("/public/portal/:token/budget/:id/checkout", async (req, res) => { // B) WEBHOOK DE STRIPE (El chivatazo invisible que avisa cuando el cliente YA ha pagado) app.post("/webhook/stripe", async (req, res) => { try { - // 🛑 FIX: Como usamos express.json() globalmente arriba, el body YA es un objeto, no hay que parsearlo. const event = req.body; if (event.type === 'checkout.session.completed') { const session = event.data.object; - - const budgetId = session.metadata.budget_id; const ownerId = session.metadata.owner_id; const amountTotal = (session.amount_total / 100).toFixed(2); + const paymentType = session.metadata.type; // <-- NUEVO: Diferencia qué están pagando - console.log(`💰 [STRIPE WEBHOOK] ¡PAGO RECIBIDO! Presupuesto PRE-${budgetId} por ${amountTotal}€`); + if (paymentType === 'protection_plan') { + // 🟢 1. PAGO DE PLAN DE PROTECCIÓN (SEGURO) + const subId = session.metadata.subscription_id; + console.log(`💰 [STRIPE WEBHOOK] Pago de Seguro PREM-${subId} por ${amountTotal}€`); - // 1. 🟢 Lo marcamos con el estado puro 'paid' - await pool.query("UPDATE budgets SET status = 'paid' WHERE id = $1 AND owner_id = $2", [budgetId, ownerId]); + // Marcamos la suscripción como pagada y la activamos + await pool.query("UPDATE protection_subscriptions SET payment_status = 'pagado', status = 'activo' WHERE id = $1 AND company_id = $2", [subId, ownerId]); + await pool.query("INSERT INTO protection_activity (company_id, type, description) VALUES ($1, 'cobro', $2)", [ownerId, `Pago de suscripción inicial confirmado (${amountTotal}€)`]); - // 2. Si ya existía un servicio asociado, le inyectamos la variable "is_paid: true" - const sq = await pool.query("SELECT id, raw_data FROM scraped_services WHERE service_ref = $1 AND owner_id = $2", [`PRE-${budgetId}`, ownerId]); - if (sq.rowCount > 0) { - const serviceId = sq.rows[0].id; - let rawData = sq.rows[0].raw_data || {}; - - rawData.is_paid = true; // 🟢 Inyección limpia en el JSON de datos - - await pool.query("UPDATE scraped_services SET raw_data = $1 WHERE id = $2", [JSON.stringify(rawData), serviceId]); - - await pool.query(` - INSERT INTO service_financials (scraped_id, amount, payment_method, is_paid) - VALUES ($1, $2, 'Tarjeta (Stripe)', true) - ON CONFLICT (scraped_id) DO UPDATE SET is_paid = true, payment_method = 'Tarjeta (Stripe)' - `, [serviceId, amountTotal]); + } else { + // 🔵 2. PAGO DE PRESUPUESTO DE REPARACIÓN NORMAL + const budgetId = session.metadata.budget_id; + console.log(`💰 [STRIPE WEBHOOK] ¡PAGO RECIBIDO! Presupuesto PRE-${budgetId} por ${amountTotal}€`); - await pool.query("INSERT INTO scraped_service_logs (scraped_id, user_name, action, details) VALUES ($1, $2, $3, $4)", - [serviceId, "Stripe API", "Pago Confirmado", `El cliente ha abonado ${amountTotal}€ por pasarela segura.`] - ); - } + await pool.query("UPDATE budgets SET status = 'paid' WHERE id = $1 AND owner_id = $2", [budgetId, ownerId]); - // 4. ¡Avisar al jefe por WhatsApp! - const ownerQ = await pool.query("SELECT phone FROM users WHERE id = $1", [ownerId]); - if (ownerQ.rowCount > 0) { - const msgWa = `💰 *¡PAGO RECIBIDO (STRIPE)!*\n\nSe acaba de confirmar el pago con tarjeta del presupuesto *PRE-${budgetId}* por un importe de *${amountTotal}€*.\n\nEl sistema lo ha marcado como pagado automáticamente.`; - sendWhatsAppAuto(ownerQ.rows[0].phone, msgWa, `cliente_${ownerId}`, false).catch(console.error); + const sq = await pool.query("SELECT id, raw_data FROM scraped_services WHERE service_ref = $1 AND owner_id = $2", [`PRE-${budgetId}`, ownerId]); + if (sq.rowCount > 0) { + const serviceId = sq.rows[0].id; + let rawData = sq.rows[0].raw_data || {}; + rawData.is_paid = true; + + await pool.query("UPDATE scraped_services SET raw_data = $1 WHERE id = $2", [JSON.stringify(rawData), serviceId]); + + await pool.query(` + INSERT INTO service_financials (scraped_id, amount, payment_method, is_paid) + VALUES ($1, $2, 'Tarjeta (Stripe)', true) + ON CONFLICT (scraped_id) DO UPDATE SET is_paid = true, payment_method = 'Tarjeta (Stripe)' + `, [serviceId, amountTotal]); + + await pool.query("INSERT INTO scraped_service_logs (scraped_id, user_name, action, details) VALUES ($1, $2, $3, $4)", + [serviceId, "Stripe API", "Pago Confirmado", `El cliente ha abonado ${amountTotal}€ por pasarela segura.`] + ); + } + + // Avisar al jefe por WhatsApp + const ownerQ = await pool.query("SELECT phone FROM users WHERE id = $1", [ownerId]); + if (ownerQ.rowCount > 0) { + const msgWa = `💰 *¡PAGO RECIBIDO (STRIPE)!*\n\nSe acaba de confirmar el pago con tarjeta del presupuesto *PRE-${budgetId}* por un importe de *${amountTotal}€*.\n\nEl sistema lo ha marcado como pagado automáticamente.`; + sendWhatsAppAuto(ownerQ.rows[0].phone, msgWa, `cliente_${ownerId}`, false).catch(console.error); + } } } @@ -4624,7 +4632,7 @@ app.get("/public/portal/:token/protection", async (req, res) => { 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 + const { plan_id, signature, pdf_document } = req.body; // pdf_document trae el archivo firmado real // 1. Validar cliente const clientQ = await pool.query("SELECT * FROM clients WHERE portal_token = $1", [token]); @@ -4638,17 +4646,17 @@ app.post("/public/portal/:token/protection/subscribe", async (req, res) => { 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) + // 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', 'activo') + VALUES ($1, $2, $3, $4, $5, 'impagado', 'suspendido') 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]); + // 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