diff --git a/src/routes/functions.ts b/src/routes/functions.ts index b3618c0..8e24f85 100644 --- a/src/routes/functions.ts +++ b/src/routes/functions.ts @@ -1,6 +1,22 @@ import { FastifyInstance } from "fastify"; import {createInvoicePDF} from "../utils/pdf"; import {useNextNumberRangeNumber} from "../utils/functions"; +import dayjs from "dayjs"; + +import customParseFormat from "dayjs/plugin/customParseFormat.js"; +import isoWeek from "dayjs/plugin/isoWeek.js"; +import isBetween from "dayjs/plugin/isBetween.js"; +import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js" +import isSameOrBefore from "dayjs/plugin/isSameOrBefore.js" +import duration from "dayjs/plugin/duration.js"; +import timezone from "dayjs/plugin/timezone.js"; +dayjs.extend(customParseFormat) +dayjs.extend(isoWeek) +dayjs.extend(isBetween) +dayjs.extend(isSameOrAfter) +dayjs.extend(isSameOrBefore) +dayjs.extend(duration) +dayjs.extend(timezone) export default async function functionRoutes(server: FastifyInstance) { server.post("/functions/createinvoicepdf", async (req, reply) => { @@ -24,9 +40,7 @@ export default async function functionRoutes(server: FastifyInstance) { } }) - server.get( - "/functions/usenextnumber/:numberrange", - async (req, reply) => { + server.get("/functions/usenextnumber/:numberrange", async (req, reply) => { const { numberrange } = req.params as { numberrange: string }; const tenant = (req as any).user.tenant_id @@ -37,6 +51,182 @@ export default async function functionRoutes(server: FastifyInstance) { req.log.error(err) reply.code(500).send({ error: "Failed to generate next number" }) } + }) + + server.get("/functions/workingtimeevaluation/:profile_id", async (req, reply) => { + + async function generateWorkingTimesEvaluationValues(profile_id,startDateInput,endDateInput) { + + console.log(dayjs(startDateInput)) + console.log(dayjs(endDateInput)) + + let startDate = dayjs(startDateInput) + let endDate = dayjs(endDateInput) + //console.log(startDate) + //console.log(endDate) + + const {data:profile} = await server.supabase.from("auth_profiles").select().eq("old_profile_id",profile_id).single() + + console.log(profile) + + let {data:times,error:timesError} = await server.supabase.from("workingtimes").select().eq("profile", profile.old_profile_id).order("startDate",{ascending: false}) + const {data:absencerequests, error: timesAbsenceRequestsError} = await server.supabase.from("absencerequests").select().eq("profile",profile.old_profile_id).order("startDate",{ascending: false}) + + times = times.filter(i => dayjs(i.startDate).isSameOrAfter(startDate) && dayjs(i.endDate).subtract(1,"day").isSameOrBefore(endDate)) + + console.log(times) + + let weekFactor = 4.33 + //let monthlyWorkingMinutes = profile.weeklyWorkingHours * weekFactor * 60 + + //Get Every Day to Calc + let days = [] + let minuteSum = 0 + let dayCount = dayjs(endDate).add(1,"day").diff(startDate,"days") + for (let count = 0; count < dayCount; count++) { + let date = dayjs(startDate).add(count,"days") + minuteSum += (profile.weekly_regular_working_hours[date.day()] || 0)*60 + } + let timeSpanWorkingMinutes = minuteSum + + + + + let workingMinutesTarget = Math.ceil(Number((Number(dayjs(endDate).add(1,"days").diff(dayjs(startDate),'month',true).toFixed(2)) * 4.33 * profile.weeklyWorkingHours * 60).toFixed(2))) + + //Eingreicht + let sumWorkingMinutesEingereicht = 0 + times.forEach(time => { + const minutes = dayjs(time.endDate).diff(dayjs(time.startDate),'minutes') + sumWorkingMinutesEingereicht = sumWorkingMinutesEingereicht + minutes + }) + + //BestÃĪtigt + let sumWorkingMinutesApproved = 0 + times.filter(i => i.approved).forEach(time => { + const minutes = dayjs(time.endDate).diff(dayjs(time.startDate),'minutes') + sumWorkingMinutesApproved = sumWorkingMinutesApproved + minutes + }) + + let recreationDays = ["2025-01-01","2025-04-18","2025-04-21","2025-05-01","2025-05-29","2025-06-09","2024-10-03","2024-10-31","2024-12-25","2024-12-26"] + + //Feiertagsausgleich + let sumWorkingMinutesRecreationDays = 0 + let sumRecreationDays = 0 + if(profile.recreationDaysCompensation) { + recreationDays.filter(i => dayjs(i).isSameOrAfter(startDate) && dayjs(i).isSameOrBefore(endDate)).forEach(day => { + let compensationTime = profile.weekly_regular_working_hours[dayjs(day).day()] || 0 + sumWorkingMinutesRecreationDays += compensationTime * 60 + sumRecreationDays++ + }) + } + + + let isBetween = (date,start,end) => { + return dayjs(date).isSameOrAfter(start) && dayjs(date).isSameOrBefore(end) + } + + //Urlaubsausgleich + let sumWorkingMinutesVacationDays = 0 + let sumVacationDays = 0 + + absencerequests.filter(i => (dayjs(i.startDate).isBetween(dayjs(startDate),dayjs(endDate),"day","[]") || dayjs(i.endDate).isBetween(dayjs(startDate),dayjs(endDate),"day","[]")) && (i.reason === "Urlaub" || i.reason === "Berufsschule") && i.approved === "Genehmigt").forEach(absenceRequest => { + let durationInDays = 0 + + let durationStartDate = null + + if(isBetween(absenceRequest.startDate,startDate,endDate) && isBetween(absenceRequest.endDate,startDate,endDate)) { + //Full in Range + durationInDays = dayjs(absenceRequest.endDate).diff(absenceRequest.startDate, "days") + 1 + durationStartDate = absenceRequest.startDate + } else if(isBetween(absenceRequest.startDate,startDate,endDate) && !isBetween(absenceRequest.endDate,startDate,endDate)) { + //Start in Range + durationInDays = dayjs(endDate).diff(absenceRequest.startDate, "days") + 1 + durationStartDate = absenceRequest.startDate + } else if(!isBetween(absenceRequest.startDate,startDate,endDate) && isBetween(absenceRequest.endDate,startDate,endDate)) { + //End in Range + durationInDays = dayjs(absenceRequest.endDate).diff(startDate, "days") + 1 + durationStartDate = startDate + + } + + let minuteSum = 0 + + for (let count = 0; count < durationInDays; count++) { + let date = dayjs(durationStartDate).add(count,"days") + minuteSum += (profile.weekly_regular_working_hours[date.day()] || 0)*60 + } + sumVacationDays += durationInDays + sumWorkingMinutesVacationDays += minuteSum + }) + + //Krankheitsausgleich + let sumWorkingMinutesSickDays = 0 + let sumSickDays = 0 + + absencerequests.filter(i => (dayjs(i.startDate).isBetween(dayjs(startDate),dayjs(endDate)) || dayjs(i.endDate).isBetween(dayjs(startDate),dayjs(endDate)) ) && (i.reason === "Krankheit" || i.reason === "Krankheit ab 1 Tag (mit Attest)" || i.reason === "Krankheit ab 2. Tag (mit Attest)") && i.approved === "Genehmigt").forEach(absenceRequest => { + let durationInDays = 0 + + let durationStartDate = null + + if(isBetween(absenceRequest.startDate,startDate,endDate) && isBetween(absenceRequest.endDate,startDate,endDate)) { + //Full in Range + console.log("FULL") + durationInDays = dayjs(absenceRequest.endDate).diff(absenceRequest.startDate, "days") + 1 + durationStartDate = absenceRequest.startDate + } else if(isBetween(absenceRequest.startDate,startDate,endDate) && !isBetween(absenceRequest.endDate,startDate,endDate)) { + //Start in Range + console.log("Start") + durationInDays = dayjs(endDate).diff(absenceRequest.startDate, "days") + 1 + durationStartDate = absenceRequest.startDate + } else if(!isBetween(absenceRequest.startDate,startDate,endDate) && isBetween(absenceRequest.endDate,startDate,endDate)) { + //End in Range + console.log("End") + durationInDays = dayjs(absenceRequest.endDate).diff(startDate, "days") + 1 + durationStartDate = startDate + + } + + let minuteSum = 0 + + for (let count = 0; count < durationInDays; count++) { + let date = dayjs(durationStartDate).add(count,"days") + minuteSum += (profile.weekly_regular_working_hours[date.day()] || 0)*60 + } + + sumSickDays += durationInDays + sumWorkingMinutesSickDays += minuteSum + }) + + //Saldo + let saldo = (sumWorkingMinutesApproved + sumWorkingMinutesRecreationDays + sumWorkingMinutesVacationDays + sumWorkingMinutesSickDays - timeSpanWorkingMinutes).toFixed(2) + let saldoInOfficial = (sumWorkingMinutesEingereicht + sumWorkingMinutesRecreationDays + sumWorkingMinutesVacationDays + sumWorkingMinutesSickDays - timeSpanWorkingMinutes).toFixed(2) + + return { + timeSpanWorkingMinutes, + workingMinutesTarget, + sumWorkingMinutesEingereicht, + sumWorkingMinutesApproved, + sumWorkingMinutesRecreationDays, + sumRecreationDays, + sumWorkingMinutesVacationDays, + sumVacationDays, + sumWorkingMinutesSickDays, + sumSickDays, + saldo, + saldoInOfficial, + times + } } - ) + + try { + reply.send(await generateWorkingTimesEvaluationValues(req.params.profile_id,req.query.start_date,req.query.end_date)) + } catch(error) { + console.log(error) + } + + + + }) + } \ No newline at end of file diff --git a/src/routes/tenant.ts b/src/routes/tenant.ts index ef02a5d..36634ab 100644 --- a/src/routes/tenant.ts +++ b/src/routes/tenant.ts @@ -98,6 +98,28 @@ export default async function routes(server: FastifyInstance) { return { tenant_id, users: correctedData }; }); + server.get("/tenant/profiles", async (req, reply) => { + const { tenant_id } = req.params as { tenant_id: string }; + const authUser = req.user // kommt aus JWT (user_id + tenant_id) + + if (!authUser) { + return reply.code(401).send({ error: "Unauthorized" }) + } + + const { data, error } = await server.supabase + .from("auth_profiles") + .select() + .eq("tenant_id", authUser.tenant_id); + + if (error) { + console.log(error); + return reply.code(400).send({ error: error.message }); + } + + + return { data }; + }); + server.put("/tenant/numberrange/:numberrange", async (req, reply) => { if (!req.user) { return reply.code(401).send({ error: "Unauthorized" });