190 lines
9.6 KiB
JavaScript
190 lines
9.6 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const { getDb, logAudit } = require('../../db');
|
|
|
|
// ============ CLIENTS ============
|
|
|
|
router.get('/clients', (req, res) => {
|
|
const db = getDb();
|
|
const { status, search } = req.query;
|
|
let sql = `SELECT c.*,
|
|
(SELECT COUNT(*) FROM engagements e WHERE e.client_id = c.id) as engagement_count,
|
|
(SELECT MAX(a.created_at) FROM assessments a WHERE a.client_id = c.id) as last_assessment
|
|
FROM clients c WHERE 1=1`;
|
|
const params = [];
|
|
if (status) { sql += ' AND c.status = ?'; params.push(status); }
|
|
if (search) { sql += ' AND (c.name LIKE ? OR c.contact_name LIKE ? OR c.industry LIKE ?)'; params.push(`%${search}%`, `%${search}%`, `%${search}%`); }
|
|
sql += ' ORDER BY c.updated_at DESC';
|
|
res.json(db.prepare(sql).all(...params));
|
|
});
|
|
|
|
router.post('/clients', (req, res) => {
|
|
const db = getDb();
|
|
const { name, industry, website, contact_name, contact_email, contact_phone, status, source, notes } = req.body;
|
|
if (!name || !name.trim()) return res.status(400).json({ error: 'Bedrijfsnaam is verplicht' });
|
|
const result = db.prepare(`INSERT INTO clients (name, industry, website, contact_name, contact_email, contact_phone, status, source, notes)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(name, industry, website, contact_name, contact_email, contact_phone, status || 'lead', source, notes);
|
|
logAudit(req.session.userId, req.session.username, 'client_created', 'client', result.lastInsertRowid, `Client ${name} aangemaakt via SPA`);
|
|
res.status(201).json({ id: result.lastInsertRowid });
|
|
});
|
|
|
|
router.get('/clients/:id', (req, res) => {
|
|
const db = getDb();
|
|
const client = db.prepare('SELECT * FROM clients WHERE id = ?').get(req.params.id);
|
|
if (!client) return res.status(404).json({ error: 'Client niet gevonden' });
|
|
res.json({
|
|
client,
|
|
engagements: db.prepare('SELECT * FROM engagements WHERE client_id = ? ORDER BY created_at DESC').all(req.params.id),
|
|
assessments: db.prepare('SELECT id, client_id, engagement_id, created_at FROM assessments WHERE client_id = ? ORDER BY created_at DESC').all(req.params.id),
|
|
advice: db.prepare('SELECT * FROM advice_log WHERE client_id = ? AND dismissed = 0 ORDER BY created_at DESC').all(req.params.id),
|
|
diagrams: db.prepare('SELECT id, name, description, diagram_type, updated_at, created_at FROM data_diagrams WHERE client_id = ? ORDER BY updated_at DESC').all(req.params.id),
|
|
notes: db.prepare('SELECT * FROM client_notes WHERE client_id = ? ORDER BY created_at DESC').all(req.params.id),
|
|
files: db.prepare('SELECT id, client_id, original_name, mime_type, file_size, created_at FROM client_files WHERE client_id = ? ORDER BY created_at DESC').all(req.params.id),
|
|
timeEntries: db.prepare('SELECT t.*, u.username FROM time_entries t LEFT JOIN users u ON u.id = t.user_id WHERE t.client_id = ? ORDER BY t.date DESC').all(req.params.id),
|
|
invoices: db.prepare('SELECT * FROM invoices WHERE client_id = ? ORDER BY created_at DESC').all(req.params.id)
|
|
});
|
|
});
|
|
|
|
router.put('/clients/:id', (req, res) => {
|
|
const db = getDb();
|
|
const { name, industry, website, contact_name, contact_email, contact_phone, status, source, notes } = req.body;
|
|
if (!name || !name.trim()) return res.status(400).json({ error: 'Bedrijfsnaam is verplicht' });
|
|
db.prepare(`UPDATE clients SET name=?, industry=?, website=?, contact_name=?, contact_email=?, contact_phone=?, status=?, source=?, notes=?, updated_at=datetime('now') WHERE id=?`)
|
|
.run(name, industry, website, contact_name, contact_email, contact_phone, status, source, notes, req.params.id);
|
|
logAudit(req.session.userId, req.session.username, 'client_updated', 'client', req.params.id, `Client ${name} bijgewerkt via SPA`);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
router.delete('/clients/:id', (req, res) => {
|
|
const db = getDb();
|
|
db.prepare('DELETE FROM clients WHERE id = ?').run(req.params.id);
|
|
logAudit(req.session.userId, req.session.username, 'client_deleted', 'client', req.params.id, 'Client verwijderd via SPA');
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
router.post('/clients/:id/advice/:adviceId/dismiss', (req, res) => {
|
|
const db = getDb();
|
|
db.prepare('UPDATE advice_log SET dismissed = 1 WHERE id = ? AND client_id = ?').run(req.params.adviceId, req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
// ---- Client notes ----
|
|
router.post('/clients/:id/notes', (req, res) => {
|
|
const db = getDb();
|
|
const { content } = req.body;
|
|
if (!content || !content.trim()) return res.status(400).json({ error: 'Notitie is leeg' });
|
|
const result = db.prepare('INSERT INTO client_notes (client_id, content, created_by) VALUES (?, ?, ?)')
|
|
.run(req.params.id, content.trim(), req.session.username || '');
|
|
res.status(201).json({ id: result.lastInsertRowid });
|
|
});
|
|
|
|
router.delete('/clients/:id/notes/:noteId', (req, res) => {
|
|
const db = getDb();
|
|
db.prepare('DELETE FROM client_notes WHERE id = ? AND client_id = ?').run(req.params.noteId, req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
// ============ ENGAGEMENTS ============
|
|
|
|
router.get('/engagements', (req, res) => {
|
|
const db = getDb();
|
|
const { type, status, client_id } = req.query;
|
|
let sql = `SELECT e.*, c.name as client_name,
|
|
(SELECT COUNT(*) FROM tasks t WHERE t.engagement_id = e.id) as task_count
|
|
FROM engagements e JOIN clients c ON c.id = e.client_id WHERE 1=1`;
|
|
const params = [];
|
|
if (type) { sql += ' AND e.type = ?'; params.push(type); }
|
|
if (status) { sql += ' AND e.status = ?'; params.push(status); }
|
|
if (client_id) { sql += ' AND e.client_id = ?'; params.push(client_id); }
|
|
sql += ' ORDER BY e.created_at DESC';
|
|
res.json(db.prepare(sql).all(...params));
|
|
});
|
|
|
|
router.post('/engagements', (req, res) => {
|
|
const db = getDb();
|
|
const { client_id, type, title, description, start_date, end_date, status } = req.body;
|
|
if (!client_id || !type || !title) return res.status(400).json({ error: 'Client, type en titel zijn verplicht' });
|
|
const result = db.prepare(`INSERT INTO engagements (client_id, type, title, description, start_date, end_date, status)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(client_id, type, title, description, start_date, end_date, status || 'planned');
|
|
logAudit(req.session.userId, req.session.username, 'engagement_created', 'engagement', result.lastInsertRowid, `Engagement ${title} aangemaakt via SPA`);
|
|
res.status(201).json({ id: result.lastInsertRowid });
|
|
});
|
|
|
|
router.get('/engagements/:id', (req, res) => {
|
|
const db = getDb();
|
|
const engagement = db.prepare('SELECT e.*, c.name as client_name FROM engagements e JOIN clients c ON c.id = e.client_id WHERE e.id = ?').get(req.params.id);
|
|
if (!engagement) return res.status(404).json({ error: 'Engagement niet gevonden' });
|
|
res.json({
|
|
engagement,
|
|
tasks: db.prepare('SELECT * FROM tasks WHERE engagement_id = ? ORDER BY created_at DESC').all(req.params.id),
|
|
timeEntries: db.prepare('SELECT t.*, u.username FROM time_entries t LEFT JOIN users u ON u.id = t.user_id WHERE t.engagement_id = ? ORDER BY t.date DESC').all(req.params.id)
|
|
});
|
|
});
|
|
|
|
router.put('/engagements/:id', (req, res) => {
|
|
const db = getDb();
|
|
const { type, title, description, start_date, end_date, status, outcome } = req.body;
|
|
db.prepare(`UPDATE engagements SET type=?, title=?, description=?, start_date=?, end_date=?, status=?, outcome=?, updated_at=datetime('now') WHERE id=?`)
|
|
.run(type, title, description, start_date, end_date, status, outcome, req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
router.post('/engagements/:id/status', (req, res) => {
|
|
const db = getDb();
|
|
db.prepare("UPDATE engagements SET status=?, updated_at=datetime('now') WHERE id=?").run(req.body.status, req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
router.delete('/engagements/:id', (req, res) => {
|
|
const db = getDb();
|
|
db.prepare('DELETE FROM engagements WHERE id = ?').run(req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
// ============ TASKS ============
|
|
|
|
router.get('/tasks', (req, res) => {
|
|
const db = getDb();
|
|
const tasks = db.prepare(`
|
|
SELECT t.*, e.title as engagement_title, e.id as engagement_id, c.name as client_name, c.id as client_id
|
|
FROM tasks t
|
|
JOIN engagements e ON e.id = t.engagement_id
|
|
JOIN clients c ON c.id = e.client_id
|
|
ORDER BY CASE t.status WHEN 'in_progress' THEN 0 WHEN 'todo' THEN 1 WHEN 'done' THEN 2 ELSE 3 END,
|
|
CASE t.priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END,
|
|
t.due_date IS NULL, t.due_date
|
|
`).all();
|
|
res.json(tasks);
|
|
});
|
|
|
|
router.post('/tasks', (req, res) => {
|
|
const db = getDb();
|
|
const { engagement_id, title, description, priority, due_date, status } = req.body;
|
|
if (!engagement_id || !title) return res.status(400).json({ error: 'Engagement en titel zijn verplicht' });
|
|
const result = db.prepare('INSERT INTO tasks (engagement_id, title, description, priority, due_date, status) VALUES (?,?,?,?,?,?)')
|
|
.run(engagement_id, title, description || '', priority || 'medium', due_date || null, status || 'todo');
|
|
res.status(201).json({ id: result.lastInsertRowid });
|
|
});
|
|
|
|
router.post('/tasks/:id/status', (req, res) => {
|
|
const db = getDb();
|
|
db.prepare("UPDATE tasks SET status=?, updated_at=datetime('now') WHERE id=?").run(req.body.status, req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
router.put('/tasks/:id', (req, res) => {
|
|
const db = getDb();
|
|
const { title, description, priority, due_date, status } = req.body;
|
|
db.prepare("UPDATE tasks SET title=?, description=?, priority=?, due_date=?, status=?, updated_at=datetime('now') WHERE id=?")
|
|
.run(title, description, priority, due_date, status, req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
router.delete('/tasks/:id', (req, res) => {
|
|
const db = getDb();
|
|
db.prepare('DELETE FROM tasks WHERE id = ?').run(req.params.id);
|
|
res.json({ ok: true });
|
|
});
|
|
|
|
module.exports = router;
|