295 lines
9.9 KiB
JavaScript
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);
|
|
});
|