Files
online-energieausweis/src/lib/pdf/pdfVerbrauchsausweisGewerbe.ts
2025-02-19 11:11:24 +11:00

566 lines
16 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, RotationTypes, StandardFonts, TextAlignment } from "pdf-lib";
import { addCheckMark } from "./utils/checkbox.js";
import { addText } from "./utils/text.js";
import { addAnsichtsausweisLabel, addDatumGEG } from "./utils/helpers.js";
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
})
const erneuerbareEnergienVerwendung = []
if (ausweis.alternative_heizung) {
erneuerbareEnergienVerwendung.push("Heizung")
}
if (ausweis.alternative_kuehlung) {
erneuerbareEnergienVerwendung.push("Kühlung")
}
if (ausweis.alternative_lueftung) {
erneuerbareEnergienVerwendung.push("Lüftung")
}
if (ausweis.alternative_warmwasser) {
erneuerbareEnergienVerwendung.push("Warmwasser")
}
pages[0].drawText(erneuerbareEnergienVerwendung.join(", "), {
x: 358,
y: height - 325,
size: 8
})
if (ausweis.warmwasser_enthalten) {
pages[0].drawText(`${aufnahme.brennstoff_1}, ${aufnahme.brennstoff_2 || ""}`, {
x: 211,
y: height - 299,
size: 10
})
}
if (aufnahme.lueftung === Enums.Lueftungskonzept.Fensterlueftung) {
addCheckMark(pages[0], 213, height - 334)
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.Schachtlueftung) {
addCheckMark(pages[0], 213, height - 345)
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageMitWaermerueckgewinnung) {
addCheckMark(pages[0], 355, height - 334)
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageOhneWaermerueckgewinnung) {
addCheckMark(pages[0], 355, height - 345)
}
// Kühlung
if (ausweis.wird_gekuehlt) {
addCheckMark(pages[0], 213, height - 362.5)
} else {
addCheckMark(pages[0], 355, height - 373.5)
}
if (ausweis.ausstellgrund === Enums.Ausstellgrund.Neubau) {
addCheckMark(pages[0], 213, height - 406)
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Vermietung) {
addCheckMark(pages[0], 213, height - 417)
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Modernisierung) {
addCheckMark(pages[0], 344.5, height - 406)
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Sonstiges) {
addCheckMark(pages[0], 463, height - 417)
}
// Aushangpflicht
// addCheckMark(pages[0], 463, height - 406)
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
})
}
// Checkmark Angabe energetische Qualität des Gebäudes.
addCheckMark(pages[0], 40, height - 550)
// Datenerhebung durch Eigentümer
addCheckMark(pages[0], 295, height - 580)
// Ausstellungsdatum
pages[0].drawText(moment().format("DD.MM.YYYY"), {
font,
size: 10,
x: 508,
y: height - 752
})
// Gültig bis
pages[0].drawText(moment().add(10, "years").format("DD.MM.YYYY"), {
font: bold,
size: 10,
x: 90,
y: height - 113
})
// Stempel und Unterschrift
if (ausweis.ausgestellt) {
const stempel = await pdf.embedPng(fs.readFileSync(new URL("./images/stempel-unterschrift.png", import.meta.url), "base64"));
const stempelHeight = 60
pages[0].drawImage(stempel, {
x: 450,
y: height - 750,
height: stempelHeight,
width: stempel.width / (stempel.height / stempelHeight)
})
}
// Aussteller
const aussteller = await pdf.embedPng(fs.readFileSync(new URL("./images/aussteller.png", import.meta.url), "base64"));
pages[0].drawImage(aussteller, {
x: 40,
y: height - 750,
width: 100,
height: 50
})
// /* -------------------------------- 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"))
// 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 stromVerbrauchTranslationPercentage = Math.min(1000, Math.max(0, berechnungen?.endEnergieVerbrauchStrom || 0)) / 1000
const minTranslation = 78
const maxTranslation = 512
const endenergieverbrauchTranslationX = minTranslation + (maxTranslation - minTranslation) * endenergieverbrauchTranslationPercentage;
const stromVerbrauchTranslationX = minTranslation + (maxTranslation - minTranslation) * stromVerbrauchTranslationPercentage;
const pfeilWidth = 20
const margin = 5;
page.drawImage(pfeilNachUnten, {
x: endenergieverbrauchTranslationX,
y: height - 210,
width: pfeilWidth,
height: 30
})
const endEnergieVerbrauchGesamtText = `${berechnungen?.endEnergieVerbrauchGesamt.toString()}kWh/(m²a)`;
const stromVerbrauchGesamtText = `${berechnungen?.endEnergieVerbrauchStrom.toString()}kWh/(m²a)`;
if (endenergieverbrauchTranslationPercentage > 0.5) {
page.drawText("Endenergieverbrauch Wärme", {
x: endenergieverbrauchTranslationX - margin - font.widthOfTextAtSize("Endenergieverbrauch", 10),
y: height - 191,
size: 10
})
page.drawText(endEnergieVerbrauchGesamtText, {
x: endenergieverbrauchTranslationX - margin - bold.widthOfTextAtSize(endEnergieVerbrauchGesamtText, 10),
y: height - 205,
size: 10,
font: bold
})
} else {
page.drawText("Endenergieverbrauch Wärme", {
x: endenergieverbrauchTranslationX + pfeilWidth + margin,
y: height - 191,
size: 10
})
page.drawText(endEnergieVerbrauchGesamtText, {
x: endenergieverbrauchTranslationX + pfeilWidth + margin,
y: height - 205,
size: 10,
font: bold
})
}
page.drawImage(pfeilNachUnten, {
x: stromVerbrauchTranslationX,
y: height - 354,
width: pfeilWidth,
height: 30
})
if (endenergieverbrauchTranslationPercentage > 0.5) {
page.drawText("Endenergieverbrauch Strom", {
x: stromVerbrauchTranslationX - margin - font.widthOfTextAtSize("Primärenergieverbrauch", 10),
y: height - 335,
size: 10
})
page.drawText(stromVerbrauchGesamtText, {
x: stromVerbrauchTranslationX - margin - bold.widthOfTextAtSize(stromVerbrauchGesamtText, 10),
y: height - 349,
size: 10,
font: bold
})
} else {
page.drawText("Endenergieverbrauch Strom", {
x: stromVerbrauchTranslationX + pfeilWidth + margin,
y: height - 335,
size: 10
})
page.drawText(stromVerbrauchGesamtText, {
x: stromVerbrauchTranslationX + pfeilWidth + margin,
y: height - 349,
size: 10,
font: bold
})
}
}
addEnergieverbrauchSkalaPfeile(pages[2])
if (ausweis.warmwasser_enthalten) {
addCheckMark(pages[2], 41, height - 269)
}
if (ausweis.kuehlung_enthalten) {
addCheckMark(pages[2], 41, height - 281)
}
if (ausweis.stromverbrauch_enthaelt_heizung) {
addCheckMark(pages[2], 41, height - 456)
}
if (ausweis.stromverbrauch_enthaelt_warmwasser) {
addCheckMark(pages[2], 131, height - 456)
}
if (ausweis.stromverbrauch_enthaelt_lueftung) {
addCheckMark(pages[2], 218, height - 456)
}
if (ausweis.stromverbrauch_enthaelt_beleuchtung) {
addCheckMark(pages[2], 281, height - 456)
}
if (ausweis.stromverbrauch_enthaelt_kuehlung) {
addCheckMark(pages[2], 422, height - 456)
}
if (ausweis.stromverbrauch_enthaelt_sonstige) {
addCheckMark(pages[2], 492, height - 456)
}
addText(pages[2], berechnungen?.primaerEnergieVerbrauchGesamt.toString() || "", 475, height - 614, 10, font)
addText(pages[2], berechnungen?.co2EmissionenGesamt.toString() || "", 475, height - 633, 10, font)
// const primaerenergiebedarfIst = fillFormField("primaerenergiebedarf_ist", berechnungen?.primaerEnergieVerbrauchGesamt.toString())
/* -------------------------------- Seite 3 -------------------------------- */
// Verbräuche
const addVerbrauchGenerator = () => {
let i = 0;
let yOffset = 14.6;
const initialHeight = 297
const initialXOffset = 36;
return (zeitraum_von?: string, zeitraum_bis?: string, energietraeger?: string, primaerfaktor?: string, energieverbrauch?: string, anteil_warmwasser?: string, anteil_kaelte?: number, anteil_heizung?: string, klimafaktor?: string, strom?: number) => {
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 + 232,
y: initialHeight - (i * yOffset),
size: 8,
font
})
pages[2].drawText(energieverbrauch || "", {
x: initialXOffset + 275,
y: initialHeight - (i * yOffset),
size: 8,
font
})
pages[2].drawText(anteil_warmwasser || "", {
x: initialXOffset + 325,
y: initialHeight - (i * yOffset),
size: 8,
font
})
pages[2].drawText(anteil_kaelte?.toString() || "", {
x: initialXOffset + 378,
y: initialHeight - (i * yOffset),
size: 8,
font
})
pages[2].drawText(anteil_heizung || "", {
x: initialXOffset + 430,
y: initialHeight - (i * yOffset),
size: 8,
font
})
pages[2].drawText(klimafaktor || "", {
x: initialXOffset + 464,
y: initialHeight - (i * yOffset),
size: 8,
font
})
pages[2].drawText(strom?.toString() || "", {
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",
berechnungen?.endEnergieVerbrauchKuehlungsZuschlag_1,
Math.round(berechnungen?.energieVerbrauchHeizung_1 || 0).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
berechnungen?.energieVerbrauchStrom
);
} 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(),
berechnungen?.endEnergieVerbrauchKuehlungsZuschlag_1,
Math.round(berechnungen?.energieVerbrauchHeizung_1 || 0).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
berechnungen?.energieVerbrauchStrom
);
}
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(),
berechnungen?.endEnergieVerbrauchKuehlungsZuschlag_2,
Math.round(berechnungen?.energieVerbrauchHeizung_2 || 0).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
0
);
}
/* -------------------------------- 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)
}
for (const page of pages) {
addAnsichtsausweisLabel(page, font)
addDatumGEG(page, font)
}
// pdf.getForm().flatten()
return pdf.save();
}