Functions Time Eval and PDF

This commit is contained in:
2025-11-08 18:59:47 +01:00
parent 6d0b764ee2
commit 29bebe6149
3 changed files with 444 additions and 186 deletions

View File

@@ -0,0 +1,128 @@
import {FastifyInstance} from "fastify";
export async function generateTimesEvaluation(
server: FastifyInstance,
user_id: string,
tenant_id: number,
startDateInput: string,
endDateInput: string
) {
const startDate = server.dayjs(startDateInput)
const endDate = server.dayjs(endDateInput)
// 🧾 Profil laden (Arbeitszeiten + Bundesland)
const { data: profile, error: profileError } = await server.supabase
.from("auth_profiles")
.select("*")
.eq("user_id", user_id)
.eq("tenant_id", tenant_id)
.maybeSingle()
if (profileError || !profile) throw new Error("Profil konnte nicht geladen werden.")
// 🕒 Arbeitszeiten abrufen
const { data: times, error: timeError } = await server.supabase
.from("staff_time_entries")
.select("*")
.eq("tenant_id", tenant_id)
.eq("user_id", user_id)
.gte("started_at", startDate.toISOString())
.lte("started_at", endDate.toISOString())
.order("started_at", { ascending: true })
if (timeError) throw new Error("Fehler beim Laden der Arbeitszeiten: " + timeError.message)
// 📅 Feiertage aus Tabelle für Bundesland + DE
const { data: holidays, error: holidaysError } = await server.supabase
.from("holidays")
.select("date")
.in("state_code", [profile.state_code, "DE"])
.gte("date", startDate.format("YYYY-MM-DD"))
.lte("date", endDate.format("YYYY-MM-DD"))
if (holidaysError) throw new Error("Fehler beim Laden der Feiertage: " + holidaysError.message)
// 🗓️ Sollzeit berechnen
let timeSpanWorkingMinutes = 0
const totalDays = endDate.add(1, "day").diff(startDate, "days")
for (let i = 0; i < totalDays; i++) {
const date = startDate.add(i, "days")
const weekday = date.day()
timeSpanWorkingMinutes += (profile.weekly_regular_working_hours?.[weekday] || 0) * 60
}
// 🧮 Eingereicht & genehmigt
const calcMinutes = (start: string, end: string | null) =>
server.dayjs(end || new Date()).diff(server.dayjs(start), "minutes")
let sumWorkingMinutesEingereicht = 0
let sumWorkingMinutesApproved = 0
for (const t of times) {
const minutes = calcMinutes(t.started_at, t.stopped_at)
if(["submitted","approved"].includes(t.state))sumWorkingMinutesEingereicht += minutes
if (t.state === "approved") sumWorkingMinutesApproved += minutes
}
// 🎉 Feiertagsausgleich
let sumWorkingMinutesRecreationDays = 0
let sumRecreationDays = 0
if (profile.recreationDaysCompensation && holidays?.length) {
holidays.forEach(({ date }) => {
const weekday = server.dayjs(date).day()
const hours = profile.weekly_regular_working_hours?.[weekday] || 0
sumWorkingMinutesRecreationDays += hours * 60
sumRecreationDays++
})
}
// 🏖️ Urlaub & Krankheit (über Typ)
const sumWorkingMinutesVacationDays = times
.filter((t) => t.type === "vacation")
.reduce((sum, t) => sum + calcMinutes(t.started_at, t.stopped_at), 0)
const sumWorkingMinutesSickDays = times
.filter((t) => t.type === "sick")
.reduce((sum, t) => sum + calcMinutes(t.started_at, t.stopped_at), 0)
const sumVacationDays = times.filter((t) => t.type === "vacation").length
const sumSickDays = times.filter((t) => t.type === "sick").length
// 💰 Salden
const saldo =
sumWorkingMinutesApproved +
sumWorkingMinutesRecreationDays +
sumWorkingMinutesVacationDays +
sumWorkingMinutesSickDays -
timeSpanWorkingMinutes
const saldoInOfficial =
sumWorkingMinutesEingereicht +
sumWorkingMinutesRecreationDays +
sumWorkingMinutesVacationDays +
sumWorkingMinutesSickDays -
timeSpanWorkingMinutes
// 📦 Rückgabe (kompatibel zur alten Struktur)
return {
user_id,
tenant_id,
from: startDate.format("YYYY-MM-DD"),
to: endDate.format("YYYY-MM-DD"),
timeSpanWorkingMinutes,
sumWorkingMinutesEingereicht,
sumWorkingMinutesApproved,
sumWorkingMinutesRecreationDays,
sumRecreationDays,
sumWorkingMinutesVacationDays,
sumVacationDays,
sumWorkingMinutesSickDays,
sumSickDays,
saldo,
saldoInOfficial,
times
}
}