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 }); }
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// 🛡️ 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)
|
||||
// ==========================================
|
||||
|
||||
Reference in New Issue
Block a user