Functions Time Eval and PDF
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import {createInvoicePDF} from "../utils/pdf";
|
||||
import {createInvoicePDF, createTimeSheetPDF} from "../utils/pdf";
|
||||
import {useNextNumberRangeNumber} from "../utils/functions";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@@ -10,6 +10,7 @@ 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";
|
||||
import {generateTimesEvaluation} from "../modules/time/evaluation.service";
|
||||
dayjs.extend(customParseFormat)
|
||||
dayjs.extend(isoWeek)
|
||||
dayjs.extend(isBetween)
|
||||
@@ -19,19 +20,35 @@ dayjs.extend(duration)
|
||||
dayjs.extend(timezone)
|
||||
|
||||
export default async function functionRoutes(server: FastifyInstance) {
|
||||
server.post("/functions/createinvoicepdf", async (req, reply) => {
|
||||
server.post("/functions/pdf/:type", async (req, reply) => {
|
||||
const body = req.body as {
|
||||
invoiceData: any
|
||||
data: any
|
||||
backgroundPath?: string
|
||||
}
|
||||
const {type} = req.params as {type:string}
|
||||
|
||||
|
||||
try {
|
||||
const pdf = await createInvoicePDF(
|
||||
server,
|
||||
"base64",
|
||||
body.invoiceData,
|
||||
body.backgroundPath
|
||||
)
|
||||
|
||||
let pdf = null
|
||||
|
||||
if(type === "createdDocument") {
|
||||
pdf = await createInvoicePDF(
|
||||
server,
|
||||
"base64",
|
||||
body.data,
|
||||
body.backgroundPath
|
||||
)
|
||||
} else if(type === "timesheet") {
|
||||
pdf = await createTimeSheetPDF(
|
||||
server,
|
||||
"base64",
|
||||
body.data,
|
||||
body.backgroundPath
|
||||
)
|
||||
}
|
||||
|
||||
console.log(pdf)
|
||||
|
||||
reply.send(pdf) // Fastify wandelt automatisch in JSON
|
||||
} catch (err) {
|
||||
@@ -53,186 +70,83 @@ export default async function functionRoutes(server: FastifyInstance) {
|
||||
}
|
||||
})
|
||||
|
||||
server.get("/functions/workingtimeevaluation/:profile_id", async (req, reply) => {
|
||||
/**
|
||||
* @route GET /functions/workingtimeevaluation/:user_id
|
||||
* @query start_date=YYYY-MM-DD
|
||||
* @query end_date=YYYY-MM-DD
|
||||
*/
|
||||
server.get("/functions/timeevaluation/:user_id", async (req, reply) => {
|
||||
const { user_id } = req.params as { user_id: string }
|
||||
const { start_date, end_date } = req.query as { start_date: string; end_date: string }
|
||||
const { tenant_id } = req.user
|
||||
|
||||
const { profile_id } = req.params as { profile_id: string };
|
||||
const { start_date, end_date } = req.query as { start_date: string, end_date: string };
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
// 🔒 Sicherheitscheck: andere User nur bei Berechtigung
|
||||
if (user_id !== req.user.user_id && !req.hasPermission("staff.time.read_all")) {
|
||||
return reply.code(403).send({ error: "Not allowed to view other users." })
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
reply.send(await generateWorkingTimesEvaluationValues(profile_id,start_date,end_date))
|
||||
} catch(error) {
|
||||
console.log(error)
|
||||
const result = await generateTimesEvaluation(server, user_id, tenant_id, start_date, end_date)
|
||||
reply.send(result)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
reply.code(500).send({ error: error.message })
|
||||
}
|
||||
})
|
||||
|
||||
server.get('/functions/check-zip/:zip', async (req, reply) => {
|
||||
const { zip } = req.params as { zip: string }
|
||||
|
||||
if (!zip) {
|
||||
return reply.code(400).send({ error: 'ZIP is required' })
|
||||
}
|
||||
|
||||
try {
|
||||
const { data, error } = await server.supabase
|
||||
.from('citys')
|
||||
.select()
|
||||
.eq('zip', zip)
|
||||
.maybeSingle()
|
||||
|
||||
if (error) {
|
||||
console.log(error)
|
||||
return reply.code(500).send({ error: 'Database error' })
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return reply.code(404).send({ error: 'ZIP not found' })
|
||||
}
|
||||
|
||||
//districtMap
|
||||
const bundeslaender = [
|
||||
{ code: 'DE-BW', name: 'Baden-Württemberg' },
|
||||
{ code: 'DE-BY', name: 'Bayern' },
|
||||
{ code: 'DE-BE', name: 'Berlin' },
|
||||
{ code: 'DE-BB', name: 'Brandenburg' },
|
||||
{ code: 'DE-HB', name: 'Bremen' },
|
||||
{ code: 'DE-HH', name: 'Hamburg' },
|
||||
{ code: 'DE-HE', name: 'Hessen' },
|
||||
{ code: 'DE-MV', name: 'Mecklenburg-Vorpommern' },
|
||||
{ code: 'DE-NI', name: 'Niedersachsen' },
|
||||
{ code: 'DE-NW', name: 'Nordrhein-Westfalen' },
|
||||
{ code: 'DE-RP', name: 'Rheinland-Pfalz' },
|
||||
{ code: 'DE-SL', name: 'Saarland' },
|
||||
{ code: 'DE-SN', name: 'Sachsen' },
|
||||
{ code: 'DE-ST', name: 'Sachsen-Anhalt' },
|
||||
{ code: 'DE-SH', name: 'Schleswig-Holstein' },
|
||||
{ code: 'DE-TH', name: 'Thüringen' }
|
||||
]
|
||||
|
||||
|
||||
|
||||
return reply.send({
|
||||
...data,
|
||||
state_code: bundeslaender.find(i => i.name === data.countryName)
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return reply.code(500).send({ error: 'Internal server error' })
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user