Add cleaning-calendar and cleaning-absences endpoints
This commit is contained in:
parent
dbf670a0b3
commit
9c99d3b631
@ -160,3 +160,121 @@ cleaningTasksRouter.patch(
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// KALENDERÜBERSICHT (Putz-Zuständigkeiten + Abwesenheiten)
|
||||
//
|
||||
// Wer wann für welchen Bereich zuständig ist, ist eine gemeinschaftliche
|
||||
// Organisationsinfo und daher für ALLE eingeloggten Nutzer (auch Mieter)
|
||||
// sichtbar — anders als z. B. Miethöhe oder private Zimmer-Tickets.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
const ABSENCE_SELECT = {
|
||||
id: true,
|
||||
startDate: true,
|
||||
endDate: true,
|
||||
note: true,
|
||||
user: { select: { id: true, fullName: true } },
|
||||
};
|
||||
|
||||
// GET /cleaning-calendar?from=YYYY-MM-DD&to=YYYY-MM-DD
|
||||
// Liefert alle Putzaufgaben + alle Abwesenheiten im Zeitraum (für alle Rollen sichtbar).
|
||||
cleaningTasksRouter.get(
|
||||
'/cleaning-calendar',
|
||||
requireAuth,
|
||||
async (req: AuthedRequest, res: Response) => {
|
||||
const { from, to } = req.query;
|
||||
const fromDate = typeof from === 'string' && !Number.isNaN(Date.parse(from)) ? new Date(from) : undefined;
|
||||
const toDate = typeof to === 'string' && !Number.isNaN(Date.parse(to)) ? new Date(to) : undefined;
|
||||
|
||||
const taskWhere: Record<string, unknown> = {};
|
||||
if (fromDate || toDate) {
|
||||
taskWhere.dueDate = {
|
||||
...(fromDate ? { gte: fromDate } : {}),
|
||||
...(toDate ? { lte: toDate } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
const absenceWhere: Record<string, unknown> = {};
|
||||
if (fromDate || toDate) {
|
||||
// Überlappung: Abwesenheit endet nicht vor "from" und beginnt nicht nach "to"
|
||||
absenceWhere.AND = [
|
||||
fromDate ? { endDate: { gte: fromDate } } : {},
|
||||
toDate ? { startDate: { lte: toDate } } : {},
|
||||
];
|
||||
}
|
||||
|
||||
const [tasks, absences] = await Promise.all([
|
||||
prisma.cleaningTask.findMany({
|
||||
where: taskWhere,
|
||||
orderBy: [{ dueDate: 'asc' }],
|
||||
select: TASK_SELECT,
|
||||
}),
|
||||
prisma.cleaningAbsence.findMany({
|
||||
where: absenceWhere,
|
||||
orderBy: [{ startDate: 'asc' }],
|
||||
select: ABSENCE_SELECT,
|
||||
}),
|
||||
]);
|
||||
|
||||
res.status(200).json({ tasks, absences });
|
||||
},
|
||||
);
|
||||
|
||||
// POST /cleaning-absences — Mieter trägt eigene Abwesenheit ein (Urlaub, "kann nicht" ...).
|
||||
// Vermieter/Admin können Abwesenheiten für jeden Mieter anlegen (z. B. auf Zuruf).
|
||||
cleaningTasksRouter.post(
|
||||
'/cleaning-absences',
|
||||
requireAuth,
|
||||
async (req: AuthedRequest, res: Response) => {
|
||||
const isLandlord = req.user!.role === 'LANDLORD' || req.user!.role === 'ADMIN';
|
||||
const { startDate, endDate, note } = req.body || {};
|
||||
let { userId } = req.body || {};
|
||||
|
||||
if (!isLandlord) {
|
||||
userId = req.user!.id; // Mieter dürfen nur für sich selbst eintragen
|
||||
} else if (!userId || typeof userId !== 'string') {
|
||||
return res.status(400).json({ error: 'userId ist erforderlich' });
|
||||
}
|
||||
|
||||
if (!startDate || Number.isNaN(Date.parse(startDate))) {
|
||||
return res.status(400).json({ error: 'startDate (Datum) ist erforderlich' });
|
||||
}
|
||||
if (!endDate || Number.isNaN(Date.parse(endDate))) {
|
||||
return res.status(400).json({ error: 'endDate (Datum) ist erforderlich' });
|
||||
}
|
||||
if (new Date(endDate) < new Date(startDate)) {
|
||||
return res.status(400).json({ error: 'endDate darf nicht vor startDate liegen' });
|
||||
}
|
||||
|
||||
const absence = await prisma.cleaningAbsence.create({
|
||||
data: {
|
||||
userId,
|
||||
startDate: new Date(startDate),
|
||||
endDate: new Date(endDate),
|
||||
note: typeof note === 'string' && note.trim() ? note.trim().slice(0, 280) : null,
|
||||
},
|
||||
select: ABSENCE_SELECT,
|
||||
});
|
||||
|
||||
res.status(201).json({ absence });
|
||||
},
|
||||
);
|
||||
|
||||
// DELETE /cleaning-absences/:id — eigener Eintrag löschbar, oder Vermieter/Admin jederzeit.
|
||||
cleaningTasksRouter.delete(
|
||||
'/cleaning-absences/:id',
|
||||
requireAuth,
|
||||
async (req: AuthedRequest, res: Response) => {
|
||||
const absence = await prisma.cleaningAbsence.findUnique({ where: { id: req.params.id } });
|
||||
if (!absence) return res.status(404).json({ error: 'Abwesenheit nicht gefunden' });
|
||||
|
||||
const isLandlord = req.user!.role === 'LANDLORD' || req.user!.role === 'ADMIN';
|
||||
if (!isLandlord && absence.userId !== req.user!.id) {
|
||||
return res.status(403).json({ error: 'Du kannst nur deine eigenen Abwesenheiten löschen' });
|
||||
}
|
||||
|
||||
await prisma.cleaningAbsence.delete({ where: { id: req.params.id } });
|
||||
res.status(204).send();
|
||||
},
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user