422 lines
12 KiB
TypeScript
422 lines
12 KiB
TypeScript
import { AufnahmeClient, BenutzerClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
|
|
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
|
|
import { getEmpfehlungen } from "#lib/XML/getEmpfehlungen.js";
|
|
import { Enums } from "@ibcornelsen/database/server";
|
|
import * as fs from "fs"
|
|
import moment from "moment";
|
|
import { PDFDocument, PDFFont, PDFImage, PDFName, PDFNumber, PDFPage, rgb, StandardFonts, TextAlignment } from "pdf-lib";
|
|
|
|
|
|
export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: UploadedGebaeudeBild[], user: BenutzerClient) {
|
|
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("./templates/GEG24_Nichtwohngebaeude.pdf", import.meta.url), "base64");
|
|
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
|
|
const pages = pdf.getPages()
|
|
|
|
// const template = VerbrauchsausweisWohnen2016Template as Template;
|
|
|
|
const berechnungen = await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis, aufnahme, objekt);
|
|
|
|
const empfehlungen = getEmpfehlungen(ausweis, aufnahme, objekt)
|
|
|
|
const height = pages[0].getHeight()
|
|
|
|
const font = await pdf.embedFont(StandardFonts.Helvetica)
|
|
const bold = await pdf.embedFont(StandardFonts.HelveticaBold)
|
|
|
|
const form = pdf.getForm()
|
|
form.updateFieldAppearances(font)
|
|
|
|
const fillFormField = (name: string, value: string, fontSize: number = 8, alignment: TextAlignment = TextAlignment.Left) => {
|
|
const field = form.getTextField(name)
|
|
field.setFontSize(fontSize)
|
|
field.setText(value)
|
|
field.setAlignment(alignment)
|
|
}
|
|
|
|
const toggleCheck = (name: string, checked: boolean = true) => {
|
|
const field = form.getCheckBox(name)
|
|
|
|
if (checked) {
|
|
field.check()
|
|
} else {
|
|
field.uncheck()
|
|
}
|
|
}
|
|
|
|
pages[0].drawText(aufnahme.gebaeudetyp || "", {
|
|
x: 211,
|
|
y: height - 166,
|
|
size: 10
|
|
})
|
|
|
|
pages[0].drawText(objekt.adresse || "", {
|
|
x: 211,
|
|
y: height - 194,
|
|
size: 10
|
|
})
|
|
|
|
pages[0].drawText(aufnahme.gebaeudeteil || "", {
|
|
x: 211,
|
|
y: height - 214.5,
|
|
size: 10
|
|
})
|
|
|
|
pages[0].drawText(aufnahme.baujahr_gebaeude?.toString() || "", {
|
|
x: 211,
|
|
y: height - 229.5,
|
|
size: 10
|
|
})
|
|
|
|
pages[0].drawText(aufnahme.baujahr_heizung?.toString() || "", {
|
|
x: 211,
|
|
y: height - 250,
|
|
size: 10
|
|
})
|
|
|
|
pages[0].drawText(aufnahme.nutzflaeche?.toString() || "", {
|
|
x: 211,
|
|
y: height - 271.5,
|
|
size: 10
|
|
})
|
|
|
|
pages[0].drawText(`${aufnahme.brennstoff_1}, ${aufnahme.brennstoff_2 || ""}`, {
|
|
x: 211,
|
|
y: height - 285,
|
|
size: 10
|
|
})
|
|
|
|
if (ausweis.warmwasser_enthalten) {
|
|
pages[0].drawText(`${aufnahme.brennstoff_1}, ${aufnahme.brennstoff_2 || ""}`, {
|
|
x: 211,
|
|
y: height - 299,
|
|
size: 10
|
|
})
|
|
}
|
|
|
|
function checkbox(page: PDFPage, x: number, y: number) {
|
|
page.drawSvgPath(`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/></svg>`, {
|
|
x,
|
|
y,
|
|
scale: 0.4,
|
|
color: rgb(0,0,0)
|
|
})
|
|
}
|
|
|
|
if (aufnahme.lueftung === Enums.Lueftungskonzept.Fensterlueftung) {
|
|
checkbox(pages[0], 213, height - 334)
|
|
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.Schachtlueftung) {
|
|
checkbox(pages[0], 213, height - 345)
|
|
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageMitWaermerueckgewinnung) {
|
|
checkbox(pages[0], 355, height - 334)
|
|
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageOhneWaermerueckgewinnung) {
|
|
checkbox(pages[0], 355, height - 345)
|
|
}
|
|
|
|
|
|
|
|
const gebaeudeBild = bilder.find(image => image.kategorie === Enums.BilderKategorie.Gebaeude);
|
|
|
|
if (gebaeudeBild) {
|
|
let image: PDFImage;
|
|
try {
|
|
image = await pdf.embedJpg(gebaeudeBild?.base64)
|
|
} catch(e) {
|
|
image = await pdf.embedPng(gebaeudeBild?.base64)
|
|
}
|
|
pages[0].drawImage(image, {
|
|
x: 460.5,
|
|
y: height - 289,
|
|
width: 111,
|
|
height: 138
|
|
})
|
|
}
|
|
|
|
|
|
// /* -------------------------------- Seite 2 -------------------------------- */
|
|
|
|
// const co2Emissionen = fillFormField("co2emissionen", berechnungen?.co2EmissionenGesamt.toString(), 8, TextAlignment.Center)
|
|
|
|
const addEnergieverbrauchSkalaPfeile = async (page: PDFPage) => {
|
|
const pfeilNachUnten = await pdf.embedPng(fs.readFileSync(new URL("../../../public/images/pfeil-nach-unten.png", import.meta.url), "base64"))
|
|
const pfeilNachOben = await pdf.embedPng(fs.readFileSync(new URL("../../../public/images/pfeil-nach-oben.png", import.meta.url), "base64"))
|
|
|
|
// Wir müssen den berechneten Wert zwischen 0 und 1000 als Wert zwischen 0 und 1 festlegen
|
|
const endenergieverbrauchTranslationPercentage = Math.min(1000, Math.max(0, berechnungen?.endEnergieVerbrauchGesamt || 0)) / 1000
|
|
const primaerenergieverbrauchTranslationPercentage = Math.min(1000, Math.max(0, berechnungen?.primaerEnergieVerbrauchGesamt || 0)) / 1000
|
|
|
|
const minTranslation = 120
|
|
const maxTranslation = 457
|
|
const endenergieverbrauchTranslationX = minTranslation + (maxTranslation - minTranslation) * endenergieverbrauchTranslationPercentage;
|
|
const primaerenergieverbrauchTranslationX = minTranslation + (maxTranslation - minTranslation) * primaerenergieverbrauchTranslationPercentage;
|
|
|
|
const pfeilWidth = 20
|
|
const margin = 5;
|
|
|
|
page.drawImage(pfeilNachUnten, {
|
|
x: endenergieverbrauchTranslationX,
|
|
y: height - 215,
|
|
width: pfeilWidth,
|
|
height: 30
|
|
})
|
|
|
|
const endEnergieVerbrauchGesamtText = `${berechnungen?.endEnergieVerbrauchGesamt.toString()}kWh/(m²a)`;
|
|
const primaerEnergieVerbrauchGesamtText = `${berechnungen?.primaerEnergieVerbrauchGesamt.toString()}kWh/(m²a)`;
|
|
|
|
if (endenergieverbrauchTranslationPercentage > 0.5) {
|
|
page.drawText("Endenergieverbrauch", {
|
|
x: endenergieverbrauchTranslationX - margin - font.widthOfTextAtSize("Endenergieverbrauch", 10),
|
|
y: height - 193,
|
|
size: 10
|
|
})
|
|
|
|
page.drawText(endEnergieVerbrauchGesamtText, {
|
|
x: endenergieverbrauchTranslationX - margin - bold.widthOfTextAtSize(endEnergieVerbrauchGesamtText, 10),
|
|
y: height - 207,
|
|
size: 10,
|
|
font: bold
|
|
})
|
|
} else {
|
|
page.drawText("Endenergieverbrauch", {
|
|
x: endenergieverbrauchTranslationX + pfeilWidth + margin,
|
|
y: height - 193,
|
|
size: 10
|
|
})
|
|
page.drawText(endEnergieVerbrauchGesamtText, {
|
|
x: endenergieverbrauchTranslationX + pfeilWidth + margin,
|
|
y: height - 207,
|
|
size: 10,
|
|
font: bold
|
|
})
|
|
}
|
|
|
|
page.drawImage(pfeilNachOben, {
|
|
x: primaerenergieverbrauchTranslationX,
|
|
y: height - 298,
|
|
width: pfeilWidth,
|
|
height: 30
|
|
})
|
|
|
|
if (endenergieverbrauchTranslationPercentage > 0.5) {
|
|
page.drawText("Primärenergieverbrauch", {
|
|
x: primaerenergieverbrauchTranslationX - margin - font.widthOfTextAtSize("Primärenergieverbrauch", 10),
|
|
y: height - 280,
|
|
size: 10
|
|
})
|
|
|
|
page.drawText(primaerEnergieVerbrauchGesamtText, {
|
|
x: primaerenergieverbrauchTranslationX - margin - bold.widthOfTextAtSize(primaerEnergieVerbrauchGesamtText, 10),
|
|
y: height - 294,
|
|
size: 10,
|
|
font: bold
|
|
})
|
|
} else {
|
|
page.drawText("Primärenergieverbrauch", {
|
|
x: primaerenergieverbrauchTranslationX + pfeilWidth + margin,
|
|
y: height - 280,
|
|
size: 10
|
|
})
|
|
page.drawText(primaerEnergieVerbrauchGesamtText, {
|
|
x: primaerenergieverbrauchTranslationX + pfeilWidth + margin,
|
|
y: height - 294,
|
|
size: 10,
|
|
font: bold
|
|
})
|
|
}
|
|
}
|
|
|
|
addEnergieverbrauchSkalaPfeile(pages[1])
|
|
addEnergieverbrauchSkalaPfeile(pages[2])
|
|
|
|
// const primaerenergiebedarfIst = fillFormField("primaerenergiebedarf_ist", berechnungen?.primaerEnergieVerbrauchGesamt.toString())
|
|
|
|
|
|
/* -------------------------------- Seite 3 -------------------------------- */
|
|
|
|
// Verbräuche
|
|
|
|
const addVerbrauchGenerator = () => {
|
|
let i = 0;
|
|
let yOffset = 14.6;
|
|
const initialHeight = 435
|
|
const initialXOffset = 36;
|
|
return (zeitraum_von?: string, zeitraum_bis?: string, energietraeger?: string, primaerfaktor?: string, energieverbrauch?: string, anteil_warmwasser?: string, anteil_heizung?: string, klimafaktor?: string) => {
|
|
pages[2].drawText(zeitraum_von || "", {
|
|
x: initialXOffset,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[2].drawText(zeitraum_bis || "", {
|
|
x: initialXOffset + 47,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[2].drawText(energietraeger || "", {
|
|
x: initialXOffset + 94,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[2].drawText(primaerfaktor || "", {
|
|
x: initialXOffset + 317,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[2].drawText(energieverbrauch || "", {
|
|
x: initialXOffset + 351,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[2].drawText(anteil_warmwasser || "", {
|
|
x: initialXOffset + 402,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[2].drawText(anteil_heizung || "", {
|
|
x: initialXOffset + 453,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[2].drawText(klimafaktor || "", {
|
|
x: initialXOffset + 504,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
i++;
|
|
}
|
|
}
|
|
|
|
const addVerbrauch = addVerbrauchGenerator();
|
|
|
|
if (!ausweis.warmwasser_enthalten) {
|
|
// Mit Warmwasserzuschlag
|
|
addVerbrauch(
|
|
moment(ausweis.startdatum).format("MM.YYYY"),
|
|
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
|
|
aufnahme.brennstoff_1 || "",
|
|
berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
|
|
Math.round(berechnungen?.energieVerbrauchGesamt_1 || 0).toString(),
|
|
"0",
|
|
Math.round(berechnungen?.energieVerbrauchHeizung_1 || 0).toString(),
|
|
berechnungen?.durchschnittsKlimafaktor.toString()
|
|
);
|
|
} else {
|
|
// Ohne Warmwasserzuschlag
|
|
addVerbrauch(
|
|
moment(ausweis.startdatum).format("MM.YYYY"),
|
|
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
|
|
aufnahme.brennstoff_1 || "",
|
|
berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
|
|
Math.round(berechnungen?.energieVerbrauchGesamt_1 || 0).toString(),
|
|
Math.round(berechnungen?.energieVerbrauchWarmwasser_1 || 0).toString(),
|
|
Math.round(berechnungen?.energieVerbrauchHeizung_1 || 0).toString(),
|
|
berechnungen?.durchschnittsKlimafaktor.toString()
|
|
);
|
|
}
|
|
|
|
if (ausweis.zusaetzliche_heizquelle) {
|
|
addVerbrauch(
|
|
moment(ausweis.startdatum).format("MM.YYYY"),
|
|
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
|
|
aufnahme.brennstoff_2 || "",
|
|
berechnungen?.brennstoff_2.primaerenergiefaktor.toString(),
|
|
Math.round(berechnungen?.energieVerbrauchGesamt_2 || 0).toString(),
|
|
Math.round(berechnungen?.energieVerbrauchWarmwasser_2 || 0).toString(),
|
|
Math.round(berechnungen?.energieVerbrauchHeizung_2 || 0).toString(),
|
|
berechnungen?.durchschnittsKlimafaktor.toString()
|
|
);
|
|
}
|
|
|
|
/* -------------------------------- Seite 4 -------------------------------- */
|
|
|
|
const splitToSize = (text: string, size: number, font: PDFFont, fontSize: number) => {
|
|
const lines = []
|
|
|
|
let currentLine = ""
|
|
for (const char of text) {
|
|
if (font.widthOfTextAtSize(currentLine + char, fontSize) <= size) {
|
|
currentLine += char;
|
|
} else {
|
|
lines.push(currentLine)
|
|
currentLine = char;
|
|
}
|
|
}
|
|
|
|
lines.push(currentLine)
|
|
|
|
return lines.join("\n")
|
|
}
|
|
|
|
const addEmpfehlungenGenerator = () => {
|
|
let i = 0;
|
|
let yOffset = 43;
|
|
const initialHeight = 562
|
|
const initialXOffset = 36;
|
|
return (bauteil?: string, beschreibung?: string, alsEinzelmassnahme?: boolean, amortisationszeit?: string, kosten?: string) => {
|
|
pages[3].drawText((i + 1).toString(), {
|
|
x: initialXOffset,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[3].drawText(splitToSize(bauteil || "", 70, font, 8), {
|
|
x: initialXOffset + 25,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font,
|
|
lineHeight: 10
|
|
})
|
|
|
|
pages[3].drawText(splitToSize(beschreibung || "", 230, font, 8), {
|
|
x: initialXOffset + 98,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font,
|
|
lineHeight: 10
|
|
})
|
|
|
|
|
|
|
|
pages[3].drawText(amortisationszeit || "", {
|
|
x: initialXOffset + 403,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
|
|
pages[3].drawText(kosten || "", {
|
|
x: initialXOffset + 451,
|
|
y: initialHeight - (i * yOffset),
|
|
size: 8,
|
|
font
|
|
})
|
|
i++;
|
|
}
|
|
}
|
|
|
|
const addEmpfehlung = addEmpfehlungenGenerator()
|
|
|
|
for (const empfehlung of empfehlungen) {
|
|
addEmpfehlung(empfehlung.anlagenteil, empfehlung.description, true, empfehlung.amortisationszeit, empfehlung.kosten)
|
|
}
|
|
|
|
|
|
|
|
// pdf.getForm().flatten()
|
|
|
|
return pdf.save();
|
|
} |