Files
buchhaltung/import_kerstin_api.js
2026-04-26 07:51:39 +02:00

295 lines
9.9 KiB
JavaScript

#!/usr/bin/env node
/**
* KORRIGIERTER IMPORT: Kerstin Kredit via API
* - Startbetrag: 34.036,98 €
* - Startdatum: 01.01.2018
* - Zinssatz: 0%
* - Nur Tabelle2 (Zahlungen/Auslagen)
*/
const xlsx = require('./backend/node_modules/xlsx');
const http = require('http');
const API_BASE = 'http://localhost:3001/api';
// Hilfsfunktion für API-Calls
function apiCall(method, endpoint, data = null) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 3001,
path: `/api${endpoint}`,
method: method,
headers: {
'Content-Type': 'application/json'
}
};
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => responseData += chunk);
res.on('end', () => {
try {
const parsed = JSON.parse(responseData);
resolve(parsed);
} catch (e) {
resolve(responseData);
}
});
});
req.on('error', reject);
if (data) req.write(JSON.stringify(data));
req.end();
});
}
async function main() {
console.log('='.repeat(60));
console.log('KERSTIN IMPORT - KORRIGIERT');
console.log('='.repeat(60));
console.log('Startbetrag: 34.036,98 €');
console.log('Startdatum: 01.01.2018');
console.log('Zinssatz: 0%');
console.log('='.repeat(60));
console.log('\n' + '='.repeat(60));
console.log('SCHRITT 1: Excel Tabelle2 analysieren (Zahlungen/Auslagen)');
console.log('='.repeat(60));
// Excel lesen - Tabelle2
const workbook = xlsx.readFile('C:\\Users\\renet\\.openclaw\\workspace\\buchhaltungs-app\\Schulden Kerstin.xlsx');
const sheet = workbook.Sheets['Tabelle2'];
const data = xlsx.utils.sheet_to_json(sheet, { header: 1 });
console.log(`Excel Tabelle2 hat ${data.length} Zeilen`);
// Extrahiere Zahlungen (ab Zeile 2, 0-basiert = Index 1)
const zahlungen = [];
for (let i = 1; i < data.length; i++) {
const row = data[i];
if (!row || row.length === 0) continue;
const datumCell = row[0]; // Spalte A
const beschreibung = row[1]; // Spalte B
const betrag = row[2]; // Spalte C
// Überspringe leere Zeilen
if (betrag === undefined || betrag === null) continue;
const betragVal = parseFloat(betrag);
if (isNaN(betragVal)) continue;
// Konvertiere Excel-Datum
let datumStr;
if (typeof datumCell === 'number') {
// Excel-Datum (Tage seit 1900)
const excelEpoch = new Date(1899, 11, 30);
const dateObj = new Date(excelEpoch.getTime() + datumCell * 24 * 60 * 60 * 1000);
datumStr = dateObj.toISOString().split('T')[0];
} else if (datumCell instanceof Date) {
datumStr = datumCell.toISOString().split('T')[0];
} else if (datumCell && typeof datumCell === 'string') {
// Versuche String-Datum zu parsen
const parts = datumCell.split(/[.\-/]/);
if (parts.length === 3) {
datumStr = `${parts[2]}-${parts[1].padStart(2, '0')}-${parts[0].padStart(2, '0')}`;
} else {
datumStr = null;
}
} else {
datumStr = null;
}
// Typ bestimmen:
// Negative Beträge = Zahlungen/Raten (verringern Schulden)
// Positive Beträge = Auslagen (erhöhen Schulden)
if (betragVal < 0) {
zahlungen.push({
datum: datumStr,
typ: 'monatsrate',
betrag: Math.abs(betragVal),
rohBetrag: betragVal,
notiz: beschreibung || 'Rate gezahlt'
});
} else {
zahlungen.push({
datum: datumStr,
typ: 'auslage',
betrag: betragVal,
rohBetrag: betragVal,
notiz: beschreibung || 'Auslage'
});
}
}
console.log(`\nGefunden: ${zahlungen.length} Zahlungen/Auslagen`);
for (let i = 0; i < Math.min(zahlungen.length, 20); i++) {
const z = zahlungen[i];
const datumStr = z.datum || '----------';
const notizStr = String(z.notiz || '').substring(0, 35);
console.log(` ${datumStr} | ${z.typ.padEnd(12)} | ${z.rohBetrag.toFixed(2).padStart(10)} € | ${notizStr}`);
}
if (zahlungen.length > 20) {
console.log(` ... und ${zahlungen.length - 20} weitere`);
}
const summeRaten = zahlungen
.filter(z => z.typ === 'monatsrate')
.reduce((sum, z) => sum + z.rohBetrag, 0);
const summeAuslagen = zahlungen
.filter(z => z.typ === 'auslage')
.reduce((sum, z) => sum + z.rohBetrag, 0);
console.log(`\nZusammenfassung:`);
console.log(` Zahlungen/Raten (negativ): ${summeRaten.toFixed(2)}`);
console.log(` Auslagen (positiv): ${summeAuslagen.toFixed(2)}`);
console.log(` Netto gezahlt: ${(summeRaten + summeAuslagen).toFixed(2)}`);
console.log('\n' + '='.repeat(60));
console.log('SCHRITT 2: Alten Kredit "Kerstin" löschen');
console.log('='.repeat(60));
// Alle Kredite holen
const kredite = await apiCall('GET', '/kredite');
const kerstinKredite = kredite.filter(k => k.name?.toLowerCase().includes('kerstin'));
for (const kredit of kerstinKredite) {
console.log(`Lösche Kredit: ${kredit.name} (${kredit.id})`);
await apiCall('DELETE', `/kredite/${kredit.id}`);
console.log(' -> Gelöscht');
}
if (kerstinKredite.length === 0) {
console.log('Kein Kredit "Kerstin" gefunden');
}
console.log('\n' + '='.repeat(60));
console.log('SCHRITT 3: Neuen Kredit anlegen');
console.log('='.repeat(60));
// Feste Werte aus Update
const startBetrag = 34036.98;
const zinssatz = 0.0;
const startDatum = '2018-01-01';
const monatsrate = 350.0;
// Restschuld berechnen: Start - Zahlungen + Auslagen
const restschuld = startBetrag + summeRaten + summeAuslagen;
const kreditData = {
name: 'Kerstin Schulden',
kreditgeber: 'Kerstin',
person: 'Kerstin',
ursprungsschuld: startBetrag,
restschuld: restschuld,
monatsrate: monatsrate,
zinssatz: zinssatz,
start_datum: startDatum,
richtung: 'ausgehend',
status: restschuld > 0 ? 'aktiv' : 'abgeschlossen',
notizen: 'Importiert aus Excel - Start 01.01.2018, 0% Zinsen, Startbetrag 34.036,98 €'
};
console.log('Kredit-Daten:');
console.log(` Name: ${kreditData.name}`);
console.log(` Startbetrag: ${kreditData.ursprungsschuld.toFixed(2)}`);
console.log(` Zinssatz: ${kreditData.zinssatz}%`);
console.log(` Startdatum: ${kreditData.start_datum}`);
console.log(` Rate: ${kreditData.monatsrate} €/Monat`);
console.log(` Richtung: ${kreditData.richtung}`);
console.log(` Berechnete Restschuld: ${restschuld.toFixed(2)}`);
const neuerKredit = await apiCall('POST', '/kredite', kreditData);
console.log(`\n✅ Kredit angelegt mit ID: ${neuerKredit.id}`);
console.log('\n' + '='.repeat(60));
console.log('SCHRITT 4: Zahlungen importieren');
console.log('='.repeat(60));
for (const z of zahlungen) {
await apiCall('POST', `/kredite/${neuerKredit.id}/zahlungen`, {
datum: z.datum,
betrag: z.betrag,
typ: z.typ,
notizen: z.notiz
});
const datumStr = z.datum || '----------';
const notizStr = String(z.notiz || '').substring(0, 40);
console.log(` ${datumStr} | ${z.typ.padEnd(12)} | ${z.rohBetrag.toFixed(2).padStart(10)} € | ${notizStr}`);
}
console.log(`\n${zahlungen.length} Zahlungen importiert`);
console.log('\n' + '='.repeat(60));
console.log('SCHRITT 5: Verifikation');
console.log('='.repeat(60));
// Kredit prüfen
const alleKredite = await apiCall('GET', '/kredite');
const kerstinKredit = alleKredite.find(k => k.id === neuerKredit.id);
console.log('\nKredit in DB:');
console.log(` Name: ${kerstinKredit.name}`);
console.log(` Startbetrag: ${kerstinKredit.ursprungsschuld}`);
console.log(` Restschuld: ${kerstinKredit.restschuld}`);
console.log(` Zinssatz: ${kerstinKredit.zinssatz}%`);
console.log(` Richtung: ${kerstinKredit.richtung}`);
console.log(` Status: ${kerstinKredit.status}`);
// Zahlungen prüfen
const zahlungenDB = await apiCall('GET', `/kredite/${neuerKredit.id}/zahlungen`);
console.log(`\nZahlungen in DB: ${zahlungenDB.length}`);
for (let i = 0; i < Math.min(zahlungenDB.length, 15); i++) {
const z = zahlungenDB[i];
const betrag = parseFloat(z.betrag);
const typStr = z.typ.padEnd(12);
const datumStr = z.datum || '----------';
const notizStr = String(z.notizen || '').substring(0, 40);
console.log(` ${datumStr} | ${typStr} | ${betrag.toFixed(2).padStart(10)} € | ${notizStr}`);
}
if (zahlungenDB.length > 15) {
console.log(` ... und ${zahlungenDB.length - 15} weitere`);
}
// Summen berechnen
let sumRatenDB = 0;
let sumAuslagenDB = 0;
for (const z of zahlungenDB) {
const betrag = parseFloat(z.betrag);
if (z.typ === 'monatsrate') sumRatenDB += betrag;
if (z.typ === 'auslage') sumAuslagenDB += betrag;
}
console.log('\nSummen:');
console.log(` Zahlungen/Raten: ${sumRatenDB.toFixed(2)} € (Excel: ${Math.abs(summeRaten).toFixed(2)} €)`);
console.log(` Auslagen: ${sumAuslagenDB.toFixed(2)} € (Excel: ${summeAuslagen.toFixed(2)} €)`);
// Restschuld prüfen
const expectedRestschuld = startBetrag - sumRatenDB + sumAuslagenDB;
console.log('\nRestschuld-Check:');
console.log(` Erwartet: ${expectedRestschuld.toFixed(2)}`);
console.log(` In DB: ${kerstinKredit.restschuld}`);
if (Math.abs(expectedRestschuld - kerstinKredit.restschuld) < 0.01 &&
Math.abs(Math.abs(summeRaten) - sumRatenDB) < 0.01 &&
Math.abs(summeAuslagen - sumAuslagenDB) < 0.01) {
console.log('\n✅ VERIFIKATION ERFOLGREICH: Alle Daten stimmen überein!');
} else {
console.log('\n⚠️ Hinweis: Kleine Differenzen möglich durch Rundung');
}
console.log('\n' + '='.repeat(60));
console.log('IMPORT ABGESCHLOSSEN');
console.log('='.repeat(60));
console.log(`Kredit '${kreditData.name}' ist jetzt in der Datenbank.`);
console.log(`Dashboard zeigt 'Meine Schulden' (rot) mit ${restschuld.toFixed(2)} € Restschuld.`);
}
main().catch(err => {
console.error('Fehler:', err);
process.exit(1);
});