Files
root 0f8475ce87 Backend: Neue API-Endpunkte hinzugefügt
- /api/dashboard/* - Dashboard Übersicht, Cashflow, Steuer-Preview
- /api/customers/* - Kunden CRUD API
- /api/invoices/* - Rechnungen CRUD API + Zahlungen

Server.js angepasst um neue Routen einzubinden.
2026-05-07 13:11:10 +00:00

220 lines
6.7 KiB
JavaScript

const express = require('express');
const { Pool } = require('pg');
const router = express.Router();
// Database pool
const pool = new Pool({
host: process.env.DB_HOST || 'db',
port: process.env.DB_PORT || 5432,
database: process.env.DB_NAME || 'steuer',
user: process.env.DB_USER || 'app',
password: process.env.DB_PASSWORD || 'app123',
});
// GET /api/dashboard/summary
router.get('/summary', async (req, res) => {
try {
const currentYear = new Date().getFullYear();
// Gesamtübersichten parallel abfragen
const [
rechnungenResult,
belegeResult,
krediteResult,
stundenResult,
kundenResult
] = await Promise.all([
// Rechnungen dieses Jahr
pool.query(`
SELECT
COUNT(*) as total_count,
COALESCE(SUM(CASE WHEN status = 'bezahlt' THEN betrag ELSE 0 END), 0) as paid_total,
COALESCE(SUM(CASE WHEN status = 'offen' THEN betrag ELSE 0 END), 0) as open_total,
COALESCE(SUM(betrag), 0) as total
FROM rechnungen
WHERE EXTRACT(YEAR FROM datum) = $1
`, [currentYear]),
// Belege/Ausgaben dieses Jahr
pool.query(`
SELECT
COUNT(*) as total_count,
COALESCE(SUM(betrag), 0) as total
FROM belege
WHERE EXTRACT(YEAR FROM date) = $1
`, [currentYear]),
// Kredite
pool.query(`
SELECT
COUNT(*) as total_count,
COUNT(CASE WHEN status = 'aktiv' THEN 1 END) as active_count,
COALESCE(SUM(CASE WHEN status = 'aktiv' THEN restschuld ELSE 0 END), 0) as total_restschuld,
COALESCE(SUM(CASE WHEN status = 'aktiv' THEN monatsrate ELSE 0 END), 0) as total_rate
FROM kredite
`),
// Stunden dieses Jahr
pool.query(`
SELECT
COUNT(*) as total_count,
COALESCE(SUM(stunden), 0) as total_stunden,
COALESCE(SUM(betrag), 0) as total_umsatz
FROM stunden
WHERE EXTRACT(YEAR FROM datum) = $1
`, [currentYear]),
// Kunden
pool.query(`
SELECT COUNT(*) as total_count FROM kunden
`)
]);
const rechnungen = rechnungenResult.rows[0];
const belege = belegeResult.rows[0];
const kredite = krediteResult.rows[0];
const stunden = stundenResult.rows[0];
const kunden = kundenResult.rows[0];
res.json({
success: true,
year: currentYear,
summary: {
einnahmen: {
total: parseFloat(rechnungen.total) || 0,
paid: parseFloat(rechnungen.paid_total) || 0,
open: parseFloat(rechnungen.open_total) || 0,
count: parseInt(rechnungen.total_count) || 0
},
ausgaben: {
total: parseFloat(belege.total) || 0,
count: parseInt(belege.total_count) || 0
},
kredite: {
total: parseInt(kredite.total_count) || 0,
active: parseInt(kredite.active_count) || 0,
restschuld: parseFloat(kredite.total_restschuld) || 0,
monatsrate: parseFloat(kredite.total_rate) || 0
},
stunden: {
total: parseFloat(stunden.total_stunden) || 0,
umsatz: parseFloat(stunden.total_umsatz) || 0,
count: parseInt(stunden.total_count) || 0
},
kunden: {
total: parseInt(kunden.total_count) || 0
},
gewinn: (parseFloat(rechnungen.total) || 0) - (parseFloat(belege.total) || 0)
}
});
} catch (error) {
console.error('Dashboard Summary Error:', error);
res.status(500).json({ success: false, error: error.message });
}
});
// GET /api/dashboard/cashflow
router.get('/cashflow', async (req, res) => {
try {
const { months = 6 } = req.query;
// Monatliche Cashflow-Daten
const cashflowData = [];
for (let i = months - 1; i >= 0; i--) {
const date = new Date();
date.setMonth(date.getMonth() - i);
const year = date.getFullYear();
const month = date.getMonth() + 1;
const [einnahmenResult, ausgabenResult] = await Promise.all([
pool.query(`
SELECT COALESCE(SUM(betrag), 0) as total
FROM rechnungen
WHERE EXTRACT(YEAR FROM datum) = $1 AND EXTRACT(MONTH FROM datum) = $2
AND status = 'bezahlt'
`, [year, month]),
pool.query(`
SELECT COALESCE(SUM(betrag), 0) as total
FROM belege
WHERE EXTRACT(YEAR FROM date) = $1 AND EXTRACT(MONTH FROM date) = $2
`, [year, month])
]);
const einnahmen = parseFloat(einnahmenResult.rows[0].total) || 0;
const ausgaben = parseFloat(ausgabenResult.rows[0].total) || 0;
cashflowData.push({
year,
month,
monthName: date.toLocaleString('de-DE', { month: 'short' }),
einnahmen,
ausgaben,
saldo: einnahmen - ausgaben
});
}
res.json({
success: true,
cashflow: cashflowData
});
} catch (error) {
console.error('Dashboard Cashflow Error:', error);
res.status(500).json({ success: false, error: error.message });
}
});
// GET /api/dashboard/tax-preview
router.get('/tax-preview', async (req, res) => {
try {
const { year = new Date().getFullYear() } = req.query;
const [einnahmenResult, ausgabenResult, stundenResult] = await Promise.all([
pool.query(`
SELECT COALESCE(SUM(betrag), 0) as total
FROM rechnungen
WHERE EXTRACT(YEAR FROM datum) = $1 AND status = 'bezahlt'
`, [year]),
pool.query(`
SELECT COALESCE(SUM(betrag), 0) as total
FROM belege
WHERE EXTRACT(YEAR FROM date) = $1
`, [year]),
pool.query(`
SELECT COALESCE(SUM(betrag), 0) as total
FROM stunden
WHERE EXTRACT(YEAR FROM datum) = $1 AND status = 'bezahlt'
`, [year])
]);
const einnahmen = parseFloat(einnahmenResult.rows[0].total) || 0;
const ausgaben = parseFloat(ausgabenResult.rows[0].total) || 0;
const stundenEinnahmen = parseFloat(stundenResult.rows[0].total) || 0;
const gesamtEinnahmen = einnahmen + stundenEinnahmen;
const gewinn = gesamtEinnahmen - ausgaben;
// Vereinfachte Steuerberechnung (nür Hinweis)
const estVorschuss = gewinn > 0 ? gewinn * 0.25 : 0; // ca. 25% ESt
res.json({
success: true,
year: parseInt(year),
preview: {
einnahmen: {
rechnungen: einnahmen,
stunden: stundenEinnahmen,
gesamt: gesamtEinnahmen
},
ausgaben,
gewinn,
estVorschuss: Math.max(0, estVorschuss)
}
});
} catch (error) {
console.error('Dashboard Tax Preview Error:', error);
res.status(500).json({ success: false, error: error.message });
}
});
module.exports = router;