import { NextRequest, NextResponse } from 'next/server'; import { withAuth } from '@/lib/api-guards'; import { setupLogRedaction } from '@/lib/log-redactor'; setupLogRedaction(); export const POST = withAuth(async (req, { session, prisma }) => { try { const body = await req.json(); const { period, simulateOnly } = body; if (!period || !/^\d{4}-\d{2}$/.test(period)) { return NextResponse.json( { error: 'El período es obligatorio y debe tener formato YYYY-MM.' }, { status: 400 } ); } const isDev = process.env.IS_E2E_TEST === 'true' || process.env.NODE_ENV === 'development'; const signature = isDev ? (process.env.N8N_WEBHOOK_SECRET_DEV || 'qUHuPqPjA65psdtwQU7zgp/DVkvd1xXk2WP/vzbnEdc=') : (process.env.N8N_WEBHOOK_SECRET || 'Ecjb2s33tHJppNBDJ/DxXEjHWKow8bNWmsQrk1sQKyQ='); // Local bypass for E2E tests to prevent cloud n8n routing back to localhost if (process.env.IS_E2E_TEST === 'true') { console.log('E2E Test Mode: Running calculation locally via n8n endpoints...'); const localPort = process.env.PORT || '3015'; const localBase = `http://localhost:${localPort}`; // 1. Fetch calculation data locally const fetchRes = await fetch(`${localBase}/api/n8n/fetch-calculation-data?period=${period}`, { headers: { 'x-n8n-signature': signature } }); if (!fetchRes.ok) { throw new Error(`Fetch calculation data failed: ${await fetchRes.text()}`); } const data = await fetchRes.json(); // 2. Process formula locally const processRes = await fetch(`${localBase}/api/n8n/process-formula`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-n8n-signature': signature }, body: JSON.stringify({ period, simulateOnly, ...data }) }); if (!processRes.ok) { throw new Error(`Process formula failed: ${await processRes.text()}`); } const processData = await processRes.json(); // 3. Save settlements locally (if not simulated) if (!simulateOnly) { const saveRes = await fetch(`${localBase}/api/n8n/save-settlements`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-n8n-signature': signature }, body: JSON.stringify({ period, simulateOnly: false, results: processData.results, uploaderId: session.userId }) }); if (!saveRes.ok) { throw new Error(`Save settlements failed: ${await saveRes.text()}`); } } return NextResponse.json({ success: true, code: 'SETTLEMENTS_CALCULATED', metadata: processData.metadata, simulated: processData.results }, { status: 201 }); } // Determine target n8n webhook URL for dev/prod environment const webhookBase = process.env.N8N_API_URL || 'https://n8n.gaboggamer.online'; const webhookPath = isDev ? 'webhook-test/calculate-settlements' : 'webhook/calculate-settlements'; const webhookUrl = `${webhookBase}/${webhookPath}`; console.log(`Triggering n8n settlement calculation webhook at ${webhookUrl}...`); const n8nRes = await fetch(webhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-n8n-signature': signature }, body: JSON.stringify({ period, simulateOnly, uploaderId: session.userId }) }); if (!n8nRes.ok) { const errText = await n8nRes.text(); console.error(`n8n webhook calculation failed with status ${n8nRes.status}:`, errText); return NextResponse.json( { error: `Error del motor de cálculo externo (n8n): ${n8nRes.status}` }, { status: 502 } ); } const n8nData = await n8nRes.json(); return NextResponse.json(n8nData, { status: 201 }); } catch (err: any) { console.error('Settlement calculation trigger error:', err); return NextResponse.json( { error: err.message || 'Error al calcular las liquidaciones.' }, { status: 500 } ); } }, ['admin', 'analyst']);