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