Working times and tenant profiles

This commit is contained in:
2025-10-13 21:33:28 +02:00
parent ef0af906ff
commit e0ed8f41bb
2 changed files with 216 additions and 4 deletions

View File

@@ -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)
}
})
}

View File

@@ -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" });