Praxissofttware/controllers/calendar.controller.js

258 lines
8.3 KiB
JavaScript

/**
* controllers/calendar.controller.js
*/
const db = require("../db");
const Holidays = require("date-holidays");
// ── Hilfsfunktionen ──────────────────────────────────────────────────────────
function pad(n) {
return String(n).padStart(2, "0");
}
function toISO(d) {
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
}
// ── Hauptseite (EJS rendern) ─────────────────────────────────────────────────
exports.index = async (req, res) => {
try {
// Alle aktiven Ärzte (users mit role = 'arzt')
const [doctors] = await db.promise().query(`
SELECT id, username AS name, doctor_color AS color
FROM users
WHERE role = 'arzt' AND active = 1
ORDER BY username
`);
const today = toISO(new Date());
return res.render("calendar/index", {
active: "calendar",
doctors,
today,
user: req.session.user,
});
} catch (err) {
console.error("❌ calendar.index:", err.message);
return res.status(500).send("Interner Serverfehler");
}
};
// ── API: Termine eines Tages ─────────────────────────────────────────────────
exports.getAppointments = async (req, res) => {
try {
const { date } = req.params; // YYYY-MM-DD
const [rows] = await db.promise().query(
`SELECT
a.id, a.doctor_id, a.date,
TIME_FORMAT(a.time, '%H:%i') AS time,
a.duration, a.patient_name, a.notes, a.status,
u.username AS doctor_name,
u.doctor_color AS doctor_color
FROM appointments a
JOIN users u ON u.id = a.doctor_id
WHERE a.date = ?
ORDER BY a.time, u.username`,
[date]
);
return res.json(rows);
} catch (err) {
console.error("❌ getAppointments:", err.message);
return res.status(500).json({ error: "Datenbankfehler" });
}
};
// ── API: Termin erstellen ────────────────────────────────────────────────────
exports.createAppointment = async (req, res) => {
try {
const { doctor_id, date, time, duration = 15, patient_name, notes = "" } =
req.body;
if (!doctor_id || !date || !time || !patient_name?.trim()) {
return res
.status(400)
.json({ error: "doctor_id, date, time und patient_name sind Pflicht" });
}
// Kollisionsprüfung
const [conflict] = await db.promise().query(
`SELECT id FROM appointments
WHERE doctor_id = ? AND date = ? AND time = ? AND status != 'cancelled'`,
[doctor_id, date, time]
);
if (conflict.length > 0) {
return res.status(409).json({ error: "Dieser Zeitslot ist bereits belegt" });
}
const [result] = await db.promise().query(
`INSERT INTO appointments (doctor_id, date, time, duration, patient_name, notes)
VALUES (?, ?, ?, ?, ?, ?)`,
[doctor_id, date, time, duration, patient_name.trim(), notes]
);
return res.status(201).json({ id: result.insertId });
} catch (err) {
console.error("❌ createAppointment:", err.message);
return res.status(500).json({ error: "Datenbankfehler" });
}
};
// ── API: Termin aktualisieren ────────────────────────────────────────────────
exports.updateAppointment = async (req, res) => {
try {
const { id } = req.params;
const { doctor_id, date, time, duration, patient_name, notes, status } =
req.body;
await db.promise().query(
`UPDATE appointments
SET doctor_id = ?, date = ?, time = ?, duration = ?,
patient_name = ?, notes = ?, status = ?
WHERE id = ?`,
[doctor_id, date, time, duration, patient_name, notes, status, id]
);
return res.json({ success: true });
} catch (err) {
console.error("❌ updateAppointment:", err.message);
return res.status(500).json({ error: "Datenbankfehler" });
}
};
// ── API: Termin löschen ──────────────────────────────────────────────────────
exports.deleteAppointment = async (req, res) => {
try {
await db.promise().query("DELETE FROM appointments WHERE id = ?", [
req.params.id,
]);
return res.json({ success: true });
} catch (err) {
console.error("❌ deleteAppointment:", err.message);
return res.status(500).json({ error: "Datenbankfehler" });
}
};
// ── API: Status ändern ───────────────────────────────────────────────────────
exports.patchStatus = async (req, res) => {
try {
const allowed = ["scheduled", "completed", "cancelled"];
const { status } = req.body;
if (!allowed.includes(status)) {
return res.status(400).json({ error: "Ungültiger Status" });
}
await db
.promise()
.query("UPDATE appointments SET status = ? WHERE id = ?", [
status,
req.params.id,
]);
return res.json({ success: true });
} catch (err) {
console.error("❌ patchStatus:", err.message);
return res.status(500).json({ error: "Datenbankfehler" });
}
};
// ── API: Feiertage eines Jahres ──────────────────────────────────────────────
exports.getHolidays = (req, res) => {
try {
const year = parseInt(req.params.year);
const country = (req.query.country || process.env.HOLIDAY_COUNTRY || "DE").toUpperCase();
const state = (req.query.state || process.env.HOLIDAY_STATE || "").toUpperCase();
if (isNaN(year) || year < 1900 || year > 2100) {
return res.status(400).json({ error: "Ungültiges Jahr" });
}
const hd = new Holidays();
const inited = state ? hd.init(country, state) : hd.init(country);
if (!inited) {
return res.status(400).json({ error: `Unbekanntes Land/Bundesland: ${country}/${state}` });
}
const holidays = hd
.getHolidays(year)
.filter((h) => ["public", "bank"].includes(h.type))
.map((h) => ({
date: h.date.substring(0, 10),
name: h.name,
type: h.type,
}));
return res.json({ country, state, year, holidays });
} catch (err) {
console.error("❌ getHolidays:", err.message);
return res.status(500).json({ error: "Fehler beim Laden der Feiertage" });
}
};
// ── API: Patienten-Suche (Autocomplete) ─────────────────────────────────────
exports.searchPatients = async (req, res) => {
try {
const q = (req.query.q || "").trim();
if (q.length < 1) return res.json([]);
const like = `%${q}%`;
const [rows] = await db.promise().query(
`SELECT
id,
firstname,
lastname,
birthdate,
CONCAT(firstname, ' ', lastname) AS full_name
FROM patients
WHERE active = 1
AND (
firstname LIKE ? OR
lastname LIKE ? OR
CONCAT(firstname, ' ', lastname) LIKE ?
)
ORDER BY lastname, firstname
LIMIT 10`,
[like, like, like]
);
return res.json(rows);
} catch (err) {
console.error("❌ searchPatients:", err.message);
return res.status(500).json({ error: "Datenbankfehler" });
}
};
// ── API: Arzt-Farbe speichern ────────────────────────────────────────────────
exports.updateDoctorColor = async (req, res) => {
try {
const { color } = req.body;
await db
.promise()
.query("UPDATE users SET doctor_color = ? WHERE id = ?", [
color,
req.params.id,
]);
return res.json({ success: true });
} catch (err) {
console.error("❌ updateDoctorColor:", err.message);
return res.status(500).json({ error: "Datenbankfehler" });
}
};