Functions Time Eval and PDF
This commit is contained in:
128
src/modules/time/evaluation.service.ts
Normal file
128
src/modules/time/evaluation.service.ts
Normal 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user