57 lines
1.8 KiB
TypeScript
57 lines
1.8 KiB
TypeScript
import { Prisma } from "@prisma/client";
|
|
import { UserFacingError } from "./action-error";
|
|
import { getNotdienstDays } from "./notdienst-days";
|
|
import { todayKey } from "./staff/calculations";
|
|
|
|
export async function loadNotdienstDays(
|
|
db: Pick<Prisma.TransactionClient, "termin">,
|
|
kitaId: string,
|
|
year: number,
|
|
month: number,
|
|
) {
|
|
const closures = await db.termin.findMany({
|
|
where: {
|
|
kitaId,
|
|
status: "CONFIRMED",
|
|
type: { in: ["SCHLIESSTAG", "TEAMTAG"] },
|
|
// Include closures crossing the month boundary and Berlin midnight.
|
|
startDate: { lt: new Date(Date.UTC(year, month, 1)) },
|
|
endDate: { gte: new Date(Date.UTC(year, month - 1, 1) - 86400000) },
|
|
},
|
|
select: { startDate: true, endDate: true },
|
|
});
|
|
return getNotdienstDays(year, month, closures);
|
|
}
|
|
|
|
export async function assertChildrenRemovable(
|
|
tx: Prisma.TransactionClient,
|
|
kitaId: string,
|
|
familyId: string,
|
|
childIds: string[],
|
|
) {
|
|
if (childIds.length === 0) return;
|
|
// Coordinate with the FK locks taken by concurrent assignment writes.
|
|
await tx.$queryRaw`SELECT id FROM children WHERE "kitaId" = ${kitaId}
|
|
AND "familyId" = ${familyId} AND id IN (${Prisma.join(childIds)}) ORDER BY id FOR UPDATE`;
|
|
const obligation = await tx.notdienstAssignment.findFirst({
|
|
where: {
|
|
kitaId,
|
|
childId: { in: childIds },
|
|
child: { kitaId, familyId },
|
|
OR: [
|
|
{
|
|
date: { gte: new Date(`${todayKey()}T00:00:00Z`) },
|
|
plan: { kitaId, status: "PUBLISHED" },
|
|
},
|
|
{ alarms: { some: { kitaId, activeAssignmentId: { not: null } } } },
|
|
],
|
|
},
|
|
select: { id: true },
|
|
});
|
|
if (obligation) {
|
|
throw new UserFacingError(
|
|
"Das Kind kann nicht entfernt werden, solange veröffentlichte Notdienste oder aktive Alarme bestehen. Bitte zuerst die Einteilung mit der Koordination klären.",
|
|
);
|
|
}
|
|
}
|