Actualizar server.js
This commit is contained in:
119
server.js
119
server.js
@@ -4566,6 +4566,125 @@ app.post("/protection/config", authMiddleware, async (req, res) => {
|
|||||||
} catch (e) { res.status(500).json({ ok: false, error: e.message }); }
|
} 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)
|
// 🕒 EL RELOJ DEL SISTEMA (Ejecutar cada minuto)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|||||||
Reference in New Issue
Block a user