221 lines
8.0 KiB
TypeScript
221 lines
8.0 KiB
TypeScript
import { FastifyInstance } from "fastify";
|
||
import {createInvoicePDF, createTimeSheetPDF} from "../utils/pdf";
|
||
//import {encodeBase64ToNiimbot, generateLabel, useNextNumberRangeNumber} from "../utils/functions";
|
||
import dayjs from "dayjs";
|
||
//import { ready as zplReady } from 'zpl-renderer-js'
|
||
//import { renderZPL } from "zpl-image";
|
||
|
||
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";
|
||
import {generateTimesEvaluation} from "../modules/time/evaluation.service";
|
||
import {citys} from "../../db/schema";
|
||
import {eq} from "drizzle-orm";
|
||
import {useNextNumberRangeNumber} from "../utils/functions";
|
||
import {executeManualGeneration, finishManualGeneration} from "../modules/serialexecution.service";
|
||
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/pdf/:type", async (req, reply) => {
|
||
const body = req.body as {
|
||
data: any
|
||
backgroundPath?: string
|
||
}
|
||
const {type} = req.params as {type:string}
|
||
|
||
|
||
try {
|
||
|
||
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
|
||
)
|
||
}
|
||
|
||
return pdf // Fastify wandelt automatisch in JSON
|
||
} catch (err) {
|
||
console.log(err)
|
||
reply.code(500).send({ error: "Failed to create PDF" })
|
||
}
|
||
})
|
||
|
||
server.get("/functions/usenextnumber/:numberrange", async (req, reply) => {
|
||
const { numberrange } = req.params as { numberrange: string };
|
||
const tenant = (req as any).user.tenant_id
|
||
|
||
try {
|
||
const result = await useNextNumberRangeNumber(server,tenant, numberrange)
|
||
reply.send(result) // JSON automatisch
|
||
} catch (err) {
|
||
req.log.error(err)
|
||
reply.code(500).send({ error: "Failed to generate next number" })
|
||
}
|
||
})
|
||
|
||
/**
|
||
* @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
|
||
|
||
// 🔒 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 {
|
||
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 }
|
||
const normalizedZip = String(zip || "").replace(/\D/g, "")
|
||
|
||
if (normalizedZip.length !== 5) {
|
||
return reply.code(400).send({ error: 'ZIP must contain exactly 5 digits' })
|
||
}
|
||
|
||
try {
|
||
const data = await server.db
|
||
.select()
|
||
.from(citys)
|
||
.where(eq(citys.zip, Number(normalizedZip)))
|
||
|
||
|
||
if (!data.length) {
|
||
return reply.code(404).send({ error: 'ZIP not found' })
|
||
}
|
||
|
||
const city = data[0]
|
||
|
||
//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({
|
||
...city,
|
||
state_code: bundeslaender.find(i => i.name === city.countryName)?.code || null
|
||
})
|
||
} catch (err) {
|
||
console.log(err)
|
||
return reply.code(500).send({ error: 'Internal server error' })
|
||
}
|
||
})
|
||
|
||
server.post('/functions/serial/start', async (req, reply) => {
|
||
console.log(req.body)
|
||
const {executionDate,templateIds,tenantId} = req.body as {executionDate:string,templateIds:Number[],tenantId:Number}
|
||
await executeManualGeneration(server,executionDate,templateIds,tenantId,req.user.user_id)
|
||
})
|
||
|
||
server.post('/functions/serial/finish/:execution_id', async (req, reply) => {
|
||
const {execution_id} = req.params as { execution_id: string }
|
||
//@ts-ignore
|
||
await finishManualGeneration(server,execution_id)
|
||
})
|
||
|
||
server.post('/functions/services/bankstatementsync', async (req, reply) => {
|
||
await server.services.bankStatements.run(req.user.tenant_id);
|
||
})
|
||
|
||
server.post('/functions/services/prepareincominginvoices', async (req, reply) => {
|
||
|
||
await server.services.prepareIncomingInvoices.run(req.user.tenant_id)
|
||
})
|
||
|
||
server.post('/functions/services/syncdokubox', async (req, reply) => {
|
||
|
||
await server.services.dokuboxSync.run()
|
||
})
|
||
|
||
|
||
/*server.post('/print/zpl/preview', async (req, reply) => {
|
||
const { zpl, widthMm = 50, heightMm = 30, dpmm = 8, asBase64 = false } = req.body as {zpl:string,widthMm:number,heightMm:number,dpmm:number,asBase64:string}
|
||
|
||
console.log(widthMm,heightMm,dpmm)
|
||
|
||
if (!zpl) {
|
||
return reply.code(400).send({ error: 'Missing ZPL string' })
|
||
}
|
||
|
||
try {
|
||
// 1️⃣ Renderer initialisieren
|
||
const { api } = await zplReady
|
||
|
||
// 2️⃣ Rendern (liefert base64-encoded PNG)
|
||
const base64Png = await api.zplToBase64Async(zpl, widthMm, heightMm, dpmm)
|
||
|
||
return await encodeBase64ToNiimbot(base64Png, 'top')
|
||
} catch (err) {
|
||
console.error('[ZPL Preview Error]', err)
|
||
return reply.code(500).send({ error: err.message || 'Failed to render ZPL' })
|
||
}
|
||
})
|
||
|
||
server.post('/print/label', async (req, reply) => {
|
||
const { context, width=584, heigth=354 } = req.body as {context:any,width:number,heigth:number}
|
||
|
||
try {
|
||
const base64 = await generateLabel(context,width,heigth)
|
||
|
||
return {
|
||
encoded: await encodeBase64ToNiimbot(base64, 'top'),
|
||
base64: base64
|
||
}
|
||
} catch (err) {
|
||
console.error('[ZPL Preview Error]', err)
|
||
return reply.code(500).send({ error: err.message || 'Failed to render ZPL' })
|
||
}
|
||
})*/
|
||
|
||
}
|