Actualizar server.js

This commit is contained in:
2026-04-03 21:23:52 +00:00
parent c8312f0aae
commit 9c538f7a7a

124
server.js
View File

@@ -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) => { app.post("/public/portal/:token/protection/subscribe", async (req, res) => {
try { try {
const { token } = req.params; const { token } = req.params;
const { plan_id, signature, pdf_document, dni } = req.body; const { plan_id, signature, pdf_document, dni } = req.body;
// 1. Validar cliente const clientQ = await pool.query(
const clientQ = await pool.query("SELECT * FROM clients WHERE portal_token = $1", [token]); "SELECT * FROM clients WHERE portal_token = $1",
if (clientQ.rowCount === 0) return res.status(404).json({ ok: false, error: "Token inválido" }); [token]
);
if (clientQ.rowCount === 0) {
return res.status(404).json({ ok: false, error: "Token inválido" });
}
const client = clientQ.rows[0]; const client = clientQ.rows[0];
const ownerId = client.owner_id; const ownerId = client.owner_id;
// 2. Validar Plan const planQ = await pool.query(
const planQ = await pool.query("SELECT * FROM protection_plans WHERE id = $1 AND company_id = $2", [plan_id, ownerId]); "SELECT * FROM protection_plans WHERE id = $1 AND company_id = $2",
if (planQ.rowCount === 0) return res.status(404).json({ ok: false, error: "El plan seleccionado no existe" }); [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]; const plan = planQ.rows[0];
// 3. Crear suscripción en la BD (Estado: Impagado hasta que Stripe confirme) const ownerConfigQ = await pool.query(
const subInsert = await pool.query(` "SELECT billing_settings FROM users WHERE id = $1",
INSERT INTO protection_subscriptions (company_id, plan_id, client_name, client_dni, client_phone, payment_status, status) [ownerId]
VALUES ($1, $2, $3, $4, $5, 'impagado', 'suspendido') );
RETURNING id let billingSettings = ownerConfigQ.rows[0]?.billing_settings || {};
`, [ownerId, plan.id, client.full_name, dni || null, client.phone]); if (typeof billingSettings === "string") {
try { billingSettings = JSON.parse(billingSettings); } catch (_) { billingSettings = {}; }
const subscriptionId = subInsert.rows[0].id; }
// 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) { if (!billingSettings.stripe_enabled || !billingSettings.stripe_sk) {
return res.status(400).json({ ok: false, error: "La empresa no tiene habilitados los pagos con tarjeta." }); 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 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({ const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'], payment_method_types: ["card"],
mode: "subscription",
line_items: [{ line_items: [{
price_data: { price_data: {
currency: 'eur', currency: "eur",
product_data: { name: `Plan de Protección: ${plan.name}`, description: `Suscripción ${plan.type}` }, product_data: {
unit_amount: Math.round(plan.price * 100), 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: {
metadata: { subscription_id: subscriptionId, owner_id: ownerId, type: 'protection_plan' }, 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}`, success_url: `https://portal.integrarepara.es/pago_exito.html?sub_id=${subscriptionId}`,
cancel_url: `https://portal.integrarepara.es/plan-tranquilidad.html?token=${token}`, 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 }); res.json({ ok: true, checkout_url: session.url });
} catch (e) { } catch (e) {