Initial commit - Stand 26.04.2026
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
#!/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);
|
||||
});
|
||||
Reference in New Issue
Block a user