Actualizar server.js
This commit is contained in:
122
server.js
122
server.js
@@ -5086,40 +5086,40 @@ 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." });
|
||||||
@@ -5127,22 +5127,84 @@ app.post("/public/portal/:token/protection/subscribe", async (req, res) => {
|
|||||||
|
|
||||||
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}`
|
||||||
},
|
},
|
||||||
quantity: 1,
|
unit_amount: Math.round(Number(plan.price || 0) * 100),
|
||||||
|
recurring: {
|
||||||
|
interval,
|
||||||
|
interval_count: intervalCount
|
||||||
|
}
|
||||||
|
},
|
||||||
|
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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user