Working times and tenant profiles
This commit is contained in:
@@ -1,6 +1,22 @@
|
|||||||
import { FastifyInstance } from "fastify";
|
import { FastifyInstance } from "fastify";
|
||||||
import {createInvoicePDF} from "../utils/pdf";
|
import {createInvoicePDF} from "../utils/pdf";
|
||||||
import {useNextNumberRangeNumber} from "../utils/functions";
|
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) {
|
export default async function functionRoutes(server: FastifyInstance) {
|
||||||
server.post("/functions/createinvoicepdf", async (req, reply) => {
|
server.post("/functions/createinvoicepdf", async (req, reply) => {
|
||||||
@@ -24,9 +40,7 @@ export default async function functionRoutes(server: FastifyInstance) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
server.get(
|
server.get("/functions/usenextnumber/:numberrange", async (req, reply) => {
|
||||||
"/functions/usenextnumber/:numberrange",
|
|
||||||
async (req, reply) => {
|
|
||||||
const { numberrange } = req.params as { numberrange: string };
|
const { numberrange } = req.params as { numberrange: string };
|
||||||
const tenant = (req as any).user.tenant_id
|
const tenant = (req as any).user.tenant_id
|
||||||
|
|
||||||
@@ -37,6 +51,182 @@ export default async function functionRoutes(server: FastifyInstance) {
|
|||||||
req.log.error(err)
|
req.log.error(err)
|
||||||
reply.code(500).send({ error: "Failed to generate next number" })
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -98,6 +98,28 @@ export default async function routes(server: FastifyInstance) {
|
|||||||
return { tenant_id, users: correctedData };
|
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) => {
|
server.put("/tenant/numberrange/:numberrange", async (req, reply) => {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return reply.code(401).send({ error: "Unauthorized" });
|
return reply.code(401).send({ error: "Unauthorized" });
|
||||||
|
|||||||
Reference in New Issue
Block a user