diff --git a/pitch-deck/app/api/admin/fp-patch/route.ts b/pitch-deck/app/api/admin/fp-patch/route.ts index 779fe2e..ff87109 100644 --- a/pitch-deck/app/api/admin/fp-patch/route.ts +++ b/pitch-deck/app/api/admin/fp-patch/route.ts @@ -1,30 +1,17 @@ -import { NextResponse } from 'next/server' +import { NextRequest, NextResponse } from 'next/server' +import { requireAdmin } from '@/lib/admin-auth' import pool from '@/lib/db' import { computeFinanzplan } from '@/lib/finanzplan/engine' -export async function POST() { - const WD = 'c0000000-0000-0000-0000-000000000200' - const results: string[] = [] +/** Admin-only: recompute a Finanzplan scenario. */ +export async function POST(request: NextRequest) { + const guard = await requireAdmin(request) + if (guard.kind === 'response') return guard.response - // Check what KFZ labels exist - const { rows } = await pool.query(`SELECT id, row_label, category, (values->>'m8')::numeric as m8, (values->>'m12')::numeric as m12, (values->>'m24')::numeric as m24, (values->>'m25')::numeric as m25 FROM fp_betriebliche_aufwendungen WHERE scenario_id=$1 AND (row_label ILIKE '%KFZ%' OR row_label ILIKE '%Fahrzeug%' OR row_label ILIKE '%Kraftstoff%') ORDER BY sort_order`, [WD]) - results.push(JSON.stringify(rows)) + const body = await request.json().catch(() => ({})) + const scenarioId = body.scenarioId || (await pool.query("SELECT id FROM fp_scenarios WHERE is_default = true LIMIT 1")).rows[0]?.id + if (!scenarioId) return NextResponse.json({ error: 'No scenario found' }, { status: 404 }) - // Force clear m1-m24 for ALL KFZ-related rows - const removeKeys = Array.from({length:24},(_,i)=>`m${i+1}`) - for (const r of rows) { - let sql = `UPDATE fp_betriebliche_aufwendungen SET values = values` - for (const k of removeKeys) sql += ` - '${k}'` - sql += ` WHERE id=$1` - await pool.query(sql, [r.id]) - results.push(`CLEARED ${r.row_label} (id=${r.id})`) - } - - // Also remove the old formula rows if they still exist - await pool.query(`DELETE FROM fp_betriebliche_aufwendungen WHERE scenario_id=$1 AND row_label IN ('KFZ-Steuern (F)', 'KFZ-Versicherung (F)', 'Fahrzeugkosten (F)')`, [WD]) - - const result = await computeFinanzplan(pool, WD) - results.push(`cash_m60=${result.liquiditaet?.endstand?.m60}`) - - return NextResponse.json({ ok: true, results }) + const result = await computeFinanzplan(pool, scenarioId) + return NextResponse.json({ success: true, scenarioId, cash_m60: result.liquiditaet?.endstand?.m60 }) } diff --git a/pitch-deck/lib/finanzplan/engine.ts b/pitch-deck/lib/finanzplan/engine.ts index e2a078c..721559b 100644 --- a/pitch-deck/lib/finanzplan/engine.ts +++ b/pitch-deck/lib/finanzplan/engine.ts @@ -254,9 +254,7 @@ export async function computeFinanzplan(pool: Pool, scenarioId: string): Promise // Formula-based rows: derive from headcount (excl. founders) or customers const formulaRows: { label: string; perUnit: number; source: MonthlyValues }[] = [ { label: 'Fort-/Weiterbildungskosten (F)', perUnit: 300, source: hcWithoutFounders }, - { label: 'Fahrzeugkosten (F)', perUnit: 200, source: hcWithoutFounders }, - { label: 'KFZ-Steuern (F)', perUnit: 25, source: hcWithoutFounders }, - { label: 'KFZ-Versicherung (F)', perUnit: 150, source: hcWithoutFounders }, + // KFZ costs are manual (from Jan 2028), not formula-based { label: 'Reisekosten (F)', perUnit: 75, source: headcount }, { label: 'Bewirtungskosten (F)', perUnit: 50, source: totalBestandskunden }, { label: 'Internet/Mobilfunk (F)', perUnit: 50, source: headcount }, diff --git a/pitch-deck/middleware.ts b/pitch-deck/middleware.ts index fc6dfe4..2cfd3ba 100644 --- a/pitch-deck/middleware.ts +++ b/pitch-deck/middleware.ts @@ -6,7 +6,6 @@ const PUBLIC_PATHS = [ '/auth', // investor login pages '/api/auth', // investor auth API '/api/health', - '/api/admin/fp-patch', '/api/admin-auth', // admin login API '/pitch-admin/login', // admin login page '/_next',