0f8475ce87
- /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.
207 lines
6.1 KiB
JavaScript
207 lines
6.1 KiB
JavaScript
const express = require('express');
|
|
const { Pool } = require('pg');
|
|
const { v4: uuidv4 } = require('uuid');
|
|
|
|
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/customers - Alle Kunden
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
const { search, limit = 100 } = req.query;
|
|
|
|
let query = `
|
|
SELECT k.*,
|
|
(SELECT COUNT(*) FROM rechnungen WHERE kunde = k.name) as rechnungen_count,
|
|
(SELECT COALESCE(SUM(betrag), 0) FROM rechnungen WHERE kunde = k.name AND status = 'bezahlt') as total_umsatz
|
|
FROM kunden k
|
|
`;
|
|
const values = [];
|
|
|
|
if (search) {
|
|
query += ` WHERE k.name ILIKE $1 OR k.email ILIKE $1 OR k.adresse ILIKE $1`;
|
|
values.push(`%${search}%`);
|
|
}
|
|
|
|
query += ` ORDER BY k.name ASC LIMIT $${values.length + 1}`;
|
|
values.push(limit);
|
|
|
|
const result = await pool.query(query, values);
|
|
|
|
res.json({
|
|
success: true,
|
|
customers: result.rows.map(row => ({
|
|
...row,
|
|
rechnungen_count: parseInt(row.rechnungen_count) || 0,
|
|
total_umsatz: parseFloat(row.total_umsatz) || 0
|
|
}))
|
|
});
|
|
} catch (error) {
|
|
console.error('Customers List Error:', error);
|
|
res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
});
|
|
|
|
// GET /api/customers/:id - Einzelner Kunde
|
|
router.get('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
// Kunde + Rechnungen
|
|
const [kundeResult, rechnungenResult] = await Promise.all([
|
|
pool.query('SELECT * FROM kunden WHERE id = $1', [id]),
|
|
pool.query(`
|
|
SELECT * FROM rechnungen
|
|
WHERE kunde = (SELECT name FROM kunden WHERE id = $1)
|
|
ORDER BY datum DESC
|
|
`, [id])
|
|
]);
|
|
|
|
if (kundeResult.rows.length === 0) {
|
|
return res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
|
|
}
|
|
|
|
const kunde = kundeResult.rows[0];
|
|
const rechnungen = rechnungenResult.rows;
|
|
|
|
// Zusammenfassung
|
|
const totalUmsatz = rechnungen.reduce((sum, r) => sum + parseFloat(r.betrag || 0), 0);
|
|
const paidUmsatz = rechnungen
|
|
.filter(r => r.status === 'bezahlt')
|
|
.reduce((sum, r) => sum + parseFloat(r.betrag || 0), 0);
|
|
const openUmsatz = rechnungen
|
|
.filter(r => r.status === 'offen')
|
|
.reduce((sum, r) => sum + parseFloat(r.betrag || 0), 0);
|
|
|
|
res.json({
|
|
success: true,
|
|
customer: {
|
|
...kunde,
|
|
rechnungen,
|
|
summary: {
|
|
total_rechnungen: rechnungen.length,
|
|
total_umsatz: totalUmsatz,
|
|
paid_umsatz: paidUmsatz,
|
|
open_umsatz: openUmsatz
|
|
}
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('Customer Detail Error:', error);
|
|
res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
});
|
|
|
|
// POST /api/customers - Kunde erstellen
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const { name, adresse, plz, ort, email, telefon, notizen } = req.body;
|
|
|
|
if (!name) {
|
|
return res.status(400).json({ success: false, error: 'Name ist erforderlich' });
|
|
}
|
|
|
|
const query = `
|
|
INSERT INTO kunden (id, name, adresse, plz, ort, email, telefon, notizen, created_at, updated_at)
|
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
|
|
RETURNING *
|
|
`;
|
|
const values = [uuidv4(), name, adresse || null, plz || null, ort || null, email || null, telefon || null, notizen || null];
|
|
|
|
const result = await pool.query(query, values);
|
|
|
|
res.status(201).json({
|
|
success: true,
|
|
customer: result.rows[0]
|
|
});
|
|
} catch (error) {
|
|
console.error('Customer Create Error:', error);
|
|
if (error.code === '23505') {
|
|
return res.status(409).json({ success: false, error: 'Kunde mit diesem Namen existiert bereits' });
|
|
}
|
|
res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
});
|
|
|
|
// PUT /api/customers/:id - Kunde aktualisieren
|
|
router.put('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { name, adresse, plz, ort, email, telefon, notizen } = req.body;
|
|
|
|
const query = `
|
|
UPDATE kunden
|
|
SET
|
|
name = COALESCE($1, name),
|
|
adresse = COALESCE($2, adresse),
|
|
plz = COALESCE($3, plz),
|
|
ort = COALESCE($4, ort),
|
|
email = COALESCE($5, email),
|
|
telefon = COALESCE($6, telefon),
|
|
notizen = COALESCE($7, notizen),
|
|
updated_at = NOW()
|
|
WHERE id = $8
|
|
RETURNING *
|
|
`;
|
|
const values = [name, adresse, plz, ort, email, telefon, notizen, id];
|
|
|
|
const result = await pool.query(query, values);
|
|
|
|
if (result.rows.length === 0) {
|
|
return res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
|
|
}
|
|
|
|
res.json({
|
|
success: true,
|
|
customer: result.rows[0]
|
|
});
|
|
} catch (error) {
|
|
console.error('Customer Update Error:', error);
|
|
res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
});
|
|
|
|
// DELETE /api/customers/:id - Kunde löschen
|
|
router.delete('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
// Prüfe ob Kunde Rechnungen hat
|
|
const checkResult = await pool.query(`
|
|
SELECT COUNT(*) as count FROM rechnungen
|
|
WHERE kunde = (SELECT name FROM kunden WHERE id = $1)
|
|
`, [id]);
|
|
|
|
if (parseInt(checkResult.rows[0].count) > 0) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
error: 'Kunde kann nicht gelöscht werden - es existieren Rechnungen'
|
|
});
|
|
}
|
|
|
|
const result = await pool.query('DELETE FROM kunden WHERE id = $1 RETURNING *', [id]);
|
|
|
|
if (result.rows.length === 0) {
|
|
return res.status(404).json({ success: false, error: 'Kunde nicht gefunden' });
|
|
}
|
|
|
|
res.json({
|
|
success: true,
|
|
message: 'Kunde erfolgreich gelöscht',
|
|
deleted: result.rows[0]
|
|
});
|
|
} catch (error) {
|
|
console.error('Customer Delete Error:', error);
|
|
res.status(500).json({ success: false, error: error.message });
|
|
}
|
|
});
|
|
|
|
module.exports = router; |