From 4abba965154064340b3ac53a6414d04eb73a4601 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Tue, 21 Apr 2026 18:51:04 +0200 Subject: [PATCH] =?UTF-8?q?chore:=20fp-patch=20=E2=80=94=20copy=20missing?= =?UTF-8?q?=20umsatz/kunden/material=20to=20WD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pitch-deck/app/api/admin/fp-patch/route.ts | 77 +++++++++++++++------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/pitch-deck/app/api/admin/fp-patch/route.ts b/pitch-deck/app/api/admin/fp-patch/route.ts index 950a9af..095a124 100644 --- a/pitch-deck/app/api/admin/fp-patch/route.ts +++ b/pitch-deck/app/api/admin/fp-patch/route.ts @@ -4,34 +4,61 @@ import { computeFinanzplan } from '@/lib/finanzplan/engine' export async function POST() { const WD = 'c0000000-0000-0000-0000-000000000200' + const results: string[] = [] - // Diagnose - const { rows: guv } = await pool.query( - `SELECT row_label, values FROM fp_guv WHERE scenario_id = $1 AND row_label ILIKE '%Umsatz%'`, [WD]) - const { rows: liq } = await pool.query( - `SELECT row_label, values FROM fp_liquiditaet WHERE scenario_id = $1 AND row_label ILIKE '%Umsatz%' AND row_label NOT LIKE '%steuer%'`, [WD]) - const { rows: rev } = await pool.query( - `SELECT row_label, section, values FROM fp_umsatzerloese WHERE scenario_id = $1 AND row_label = 'GESAMTUMSATZ'`, [WD]) - const { rows: qty } = await pool.query( - `SELECT row_label, section, (values->>'m12')::numeric as m12, (values->>'m24')::numeric as m24 FROM fp_umsatzerloese WHERE scenario_id = $1 AND section = 'quantity' ORDER BY row_label`, [WD]) + // Check which tables are missing data for WD + const tables = ['fp_kunden', 'fp_umsatzerloese', 'fp_materialaufwand', 'fp_betriebliche_aufwendungen', 'fp_investitionen', 'fp_liquiditaet', 'fp_guv', 'fp_personalkosten'] + const BASE = (await pool.query("SELECT id FROM fp_scenarios WHERE is_default = true LIMIT 1")).rows[0].id - // Recompute + for (const t of tables) { + const { rows: [wdCount] } = await pool.query(`SELECT COUNT(*) as c FROM ${t} WHERE scenario_id = $1`, [WD]) + const { rows: [baseCount] } = await pool.query(`SELECT COUNT(*) as c FROM ${t} WHERE scenario_id = $1`, [BASE]) + results.push(`${t}: WD=${wdCount.c} BASE=${baseCount.c}`) + } + + // Copy missing umsatzerloese rows from Base to WD (prices + quantities) + const { rows: wdUmsatz } = await pool.query(`SELECT COUNT(*) as c FROM fp_umsatzerloese WHERE scenario_id = $1 AND section = 'quantity'`, [WD]) + if (parseInt(wdUmsatz[0].c) === 0) { + // Copy ALL umsatzerloese from Base to WD (replacing existing) + await pool.query(`DELETE FROM fp_umsatzerloese WHERE scenario_id = $1`, [WD]) + const { rowCount } = await pool.query(` + INSERT INTO fp_umsatzerloese (scenario_id, section, row_label, row_index, is_editable, values, excel_row, sort_order) + SELECT $1, section, row_label, row_index, is_editable, values, excel_row, sort_order + FROM fp_umsatzerloese WHERE scenario_id = $2 + `, [WD, BASE]) + results.push(`COPIED umsatzerloese: ${rowCount} rows`) + } + + // Copy missing kunden rows + const { rows: wdKunden } = await pool.query(`SELECT COUNT(*) as c FROM fp_kunden WHERE scenario_id = $1`, [WD]) + if (parseInt(wdKunden[0].c) === 0) { + const { rowCount } = await pool.query(` + INSERT INTO fp_kunden (scenario_id, segment_name, segment_index, row_label, row_index, percentage, formula_type, is_editable, values, excel_row, sort_order) + SELECT $1, segment_name, segment_index, row_label, row_index, percentage, formula_type, is_editable, values, excel_row, sort_order + FROM fp_kunden WHERE scenario_id = $2 + `, [WD, BASE]) + results.push(`COPIED kunden: ${rowCount} rows`) + } + + // Copy missing materialaufwand rows + const { rows: wdMat } = await pool.query(`SELECT COUNT(*) as c FROM fp_materialaufwand WHERE scenario_id = $1`, [WD]) + if (parseInt(wdMat[0].c) === 0) { + const { rowCount } = await pool.query(` + INSERT INTO fp_materialaufwand (scenario_id, section, row_label, row_index, is_editable, values, excel_row, sort_order) + SELECT $1, section, row_label, row_index, is_editable, values, excel_row, sort_order + FROM fp_materialaufwand WHERE scenario_id = $2 + `, [WD, BASE]) + results.push(`COPIED materialaufwand: ${rowCount} rows`) + } + + // Recompute WD const r = await computeFinanzplan(pool, WD) + results.push(`COMPUTED WD: cash_m60=${r.liquiditaet?.endstand?.m60}`) - // Re-check after compute - const { rows: guvAfter } = await pool.query( - `SELECT row_label, (values->>'y2026')::numeric as y2026, (values->>'y2027')::numeric as y2027 FROM fp_guv WHERE scenario_id = $1 AND row_label ILIKE '%Umsatz%'`, [WD]) - const { rows: liqAfter } = await pool.query( - `SELECT row_label, (values->>'m12')::numeric as m12, (values->>'m24')::numeric as m24 FROM fp_liquiditaet WHERE scenario_id = $1 AND row_label = 'Umsatzerlöse'`, [WD]) + // Verify + const { rows: guvCheck } = await pool.query( + `SELECT (values->>'y2026')::numeric as y2026, (values->>'y2027')::numeric as y2027 FROM fp_guv WHERE scenario_id = $1 AND row_label = 'Umsatzerlöse'`, [WD]) + results.push(`GuV Umsatz after: y2026=${guvCheck[0]?.y2026}, y2027=${guvCheck[0]?.y2027}`) - return NextResponse.json({ - before: { - guv: guv.map(r => ({ label: r.row_label, y2026: r.values?.y2026, y2027: r.values?.y2027 })), - liq: liq.map(r => ({ label: r.row_label, m12: r.values?.m12, m24: r.values?.m24 })), - gesamtumsatz: rev.map(r => ({ m12: r.values?.m12, m24: r.values?.m24 })), - quantities: qty, - }, - after: { guv: guvAfter, liq: liqAfter }, - cash_m60: r.liquiditaet?.endstand?.m60, - }) + return NextResponse.json({ ok: true, results }) }