Actualizar server.js
This commit is contained in:
41
server.js
41
server.js
@@ -3481,6 +3481,9 @@ app.post("/budgets/:id/convert", authMiddleware, async (req, res) => {
|
||||
if (bq.rowCount === 0) return res.status(404).json({ok: false});
|
||||
const budget = bq.rows[0];
|
||||
|
||||
// 🟢 Saber si ya estaba pagado antes de convertirlo
|
||||
const isAlreadyPaid = budget.status === 'paid';
|
||||
|
||||
// 1. Montamos el Raw Data para el servicio
|
||||
const rawData = {
|
||||
"Nombre Cliente": budget.client_name,
|
||||
@@ -3491,7 +3494,8 @@ app.post("/budgets/:id/convert", authMiddleware, async (req, res) => {
|
||||
"guild_id": guild_id || null,
|
||||
"assigned_to": assigned_to || null,
|
||||
"scheduled_date": date || "",
|
||||
"scheduled_time": time || ""
|
||||
"scheduled_time": time || "",
|
||||
"is_paid": isAlreadyPaid // 🟢 Inyección limpia estructural
|
||||
};
|
||||
|
||||
// 2. Insertamos en el Panel Operativo (Buzón) empezando en manual
|
||||
@@ -3507,11 +3511,13 @@ app.post("/budgets/:id/convert", authMiddleware, async (req, res) => {
|
||||
|
||||
const newServiceId = insertSvc.rows[0].id;
|
||||
|
||||
// 3. Marcamos presupuesto como convertido y le enlazamos la ficha financiera por el total
|
||||
await pool.query("UPDATE budgets SET status='converted' WHERE id=$1", [budget.id]);
|
||||
// 3. Marcamos presupuesto y enlazamos ficha financiera
|
||||
const finalBudgetStatus = isAlreadyPaid ? 'paid' : 'converted';
|
||||
await pool.query("UPDATE budgets SET status=$1 WHERE id=$2", [finalBudgetStatus, budget.id]);
|
||||
|
||||
await pool.query(
|
||||
"INSERT INTO service_financials (scraped_id, amount, payment_method) VALUES ($1, $2, 'Pendiente')",
|
||||
[newServiceId, budget.total]
|
||||
"INSERT INTO service_financials (scraped_id, amount, payment_method, is_paid) VALUES ($1, $2, $3, $4)",
|
||||
[newServiceId, budget.total, isAlreadyPaid ? 'Tarjeta (Stripe)' : 'Pendiente', isAlreadyPaid]
|
||||
);
|
||||
|
||||
// 4. Si pide automatización, la disparamos internamente llamando a nuestra propia IP (127.0.0.1)
|
||||
@@ -4319,34 +4325,32 @@ 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)
|
||||
// Nota: Stripe necesita que el body llegue "crudo" para verificar las firmas, por eso le quitamos el express.json
|
||||
app.post("/webhook/stripe", express.raw({ type: 'application/json' }), async (req, res) => {
|
||||
try {
|
||||
const sig = req.headers['stripe-signature'];
|
||||
const body = req.body;
|
||||
|
||||
// Por ahora, como es un entorno SaaS complejo, procesaremos el evento de forma directa
|
||||
// En producción, es altamente recomendable verificar el 'endpoint_secret' de cada webhook
|
||||
|
||||
const event = JSON.parse(body);
|
||||
|
||||
if (event.type === 'checkout.session.completed') {
|
||||
const session = event.data.object;
|
||||
|
||||
// Extraer la "matrícula" oculta que le pusimos al pago
|
||||
const budgetId = session.metadata.budget_id;
|
||||
const ownerId = session.metadata.owner_id;
|
||||
const amountTotal = (session.amount_total / 100).toFixed(2); // De céntimos a Euros
|
||||
const amountTotal = (session.amount_total / 100).toFixed(2);
|
||||
|
||||
console.log(`💰 [STRIPE WEBHOOK] ¡PAGO RECIBIDO! Presupuesto PRE-${budgetId} por ${amountTotal}€ (Owner: ${ownerId})`);
|
||||
console.log(`💰 [STRIPE WEBHOOK] ¡PAGO RECIBIDO! Presupuesto PRE-${budgetId} por ${amountTotal}€`);
|
||||
|
||||
// 1. Marcar el presupuesto como "Convertido/Pagado"
|
||||
await pool.query("UPDATE budgets SET status = 'converted' WHERE id = $1 AND owner_id = $2", [budgetId, ownerId]);
|
||||
// 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]);
|
||||
|
||||
// 2. Si ya existía un servicio asociado, marcarlo en contabilidad
|
||||
const sq = await pool.query("SELECT id FROM scraped_services WHERE service_ref = $1 AND owner_id = $2", [`PRE-${budgetId}`, ownerId]);
|
||||
// 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)
|
||||
@@ -4354,7 +4358,6 @@ app.post("/webhook/stripe", express.raw({ type: 'application/json' }), async (re
|
||||
ON CONFLICT (scraped_id) DO UPDATE SET is_paid = true, payment_method = 'Tarjeta (Stripe)'
|
||||
`, [serviceId, amountTotal]);
|
||||
|
||||
// 3. Trazabilidad
|
||||
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.`]
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user