Merge pull request #4 from IBCornelsen/main

UMBE updaten
This commit is contained in:
UMBENOMENA
2024-03-14 16:06:40 +01:00
committed by GitHub
23 changed files with 683 additions and 124 deletions

View File

@@ -0,0 +1,19 @@
# Ausweis Erstellung
Wenn ein neuer Nutzer auf unsere Seite kommt und einen Ausweis erstellen möchte muss er sich nicht unbedingt sofort registrieren. Um den Kunden ein reibungsloses Erlebnis zu bieten versuchen wir den Nutzer automatisch anzulegen, allerdings kann es sein, dass der Ausweis nicht weiter bearbeitet wird. In diesem Fall müssen wir den Ausweis nach einer Zeit wieder löschen, damit er nicht für immer in unserer Datenbank bleibt.
```tefcha
Nutzer Kommt auf unsere Seite
if Nutzer ist eingeloggt
Ausweis wird erstellt und Nutzer zugewiesen
else
Ausweis erstellen
-> Schritt 2
if Nutzer registriert sich
Ausweis wird verknüpft
else
Ausweis nach einer Woche gelöscht
usw...
```

View File

@@ -5,9 +5,7 @@ import {
UploadedGebaeudeBild, UploadedGebaeudeBild,
VerbrauchsausweisWohnenClient, VerbrauchsausweisWohnenClient,
} from "#components/Ausweis/types"; } from "#components/Ausweis/types";
import { dialogs } from "svelte-dialogs";
import { validateAccessTokenClient } from "./validateAccessToken";
import LoginDialog from "#components/LoginDialog.svelte";
import { exclude } from "#lib/exclude"; import { exclude } from "#lib/exclude";
import { client } from "src/trpc"; import { client } from "src/trpc";
import { bilderHochladen } from "./bilderHochladen"; import { bilderHochladen } from "./bilderHochladen";
@@ -20,48 +18,28 @@ export async function verbrauchsausweisWohnenSpeichern(
images: (UploadedGebaeudeBild & { base64?: string })[], images: (UploadedGebaeudeBild & { base64?: string })[],
user: BenutzerClient user: BenutzerClient
) { ) {
// Um einen Ausweis zu speichern müssen wir eingeloggt sein, andernfalls wird die API den call ablehnen.
// Wir prüfen also ob wir eingeloggt sind und leiten den Nutzer ggf. auf die Login Seite weiter.
if (!(await validateAccessTokenClient())) {
// TOOD: Auf Dialog umstellen.
const loggedIn = await dialogs.modal(LoginDialog);
if (!loggedIn) {
return false;
}
}
if (ausweis.uid) { if (ausweis.uid) {
// Anscheinend wurde der Ausweis bereits erstellt und hat eine UID. // Anscheinend wurde der Ausweis bereits erstellt und hat eine UID.
// Jetzt müssen wir ihn nun nur noch abspeichern. // Jetzt müssen wir ihn nun nur noch abspeichern.
try { try {
const gebaeudeBilderEntfernt = exclude(gebaeude, [
"gebaeude_bilder",
]);
const gebaeudeAufnahmeGeneratedFieldsEntfernt = exclude(
gebaeude_aufnahme_allgemein,
["erstellungsdatum", "events"]
);
const ausweisGeneratedFieldsEntfernt = exclude(ausweis, [
"rechnungen",
"erstellungsdatum",
]);
await client.v1.verbrauchsausweisWohnen[2016].speichern.mutate({ await client.v1.verbrauchsausweisWohnen[2016].speichern.mutate({
...ausweisGeneratedFieldsEntfernt, ...ausweis,
gebaeude_aufnahme_allgemein: { gebaeude_aufnahme_allgemein: {
...gebaeudeAufnahmeGeneratedFieldsEntfernt, ...exclude(
gebaeude_aufnahme_allgemein,
["erstellungsdatum", "events", "ausstellungsdatum", "rechnungen"]
),
gebaeude_stammdaten: { gebaeude_stammdaten: {
...gebaeudeBilderEntfernt, ...exclude(gebaeude, [
"gebaeude_bilder",
]),
}, },
}, },
}); });
console.log(ausweisGeneratedFieldsEntfernt);
images = await bilderHochladen(images, gebaeude); images = await bilderHochladen(images, gebaeude);
return true; return { uid: ausweis.uid, gebaeude_uid: gebaeude.uid, gebaeude_aufnahme_uid: gebaeude_aufnahme_allgemein.uid };
} catch (e) { } catch (e) {
// TODO: Ticket mit Fehldermeldung abschicken. // TODO: Ticket mit Fehldermeldung abschicken.
} }
@@ -78,13 +56,10 @@ export async function verbrauchsausweisWohnenSpeichern(
}, },
}, },
}); });
ausweis.uid = response.uid;
gebaeude.uid = response.gebaeude_uid;
gebaeude_aufnahme_allgemein.uid = response.gebaeude_aufnahme_uid;
images = await bilderHochladen(images, gebaeude); images = await bilderHochladen(images, gebaeude);
return true; return response;
} catch (e: any) { } catch (e: any) {
await client.v1.tickets.erstellen.mutate({ await client.v1.tickets.erstellen.mutate({
titel: "Ausweis konnte nicht gespeichert werden", titel: "Ausweis konnte nicht gespeichert werden",
@@ -107,5 +82,5 @@ export async function verbrauchsausweisWohnenSpeichern(
timeout: 6000, timeout: 6000,
type: "error", type: "error",
}); });
return false; return null;
} }

View File

@@ -13,10 +13,8 @@
VerbrauchsausweisWohnenClient, VerbrauchsausweisWohnenClient,
} from "./types"; } from "./types";
export let ausweis: export let ausweis: VerbrauchsausweisWohnenClient;
| VerbrauchsausweisWohnenClient;
export let gebaeude: GebaeudeClient; export let gebaeude: GebaeudeClient;
export let images: UploadedGebaeudeBild[] = []; export let images: UploadedGebaeudeBild[] = [];
</script> </script>

View File

@@ -5,10 +5,6 @@
import DaemmungImage from "./DaemmungImage.svelte"; import DaemmungImage from "./DaemmungImage.svelte";
import FensterImage from "./FensterImage.svelte"; import FensterImage from "./FensterImage.svelte";
import Label from "../Label.svelte"; import Label from "../Label.svelte";
import type {
BedarfsausweisWohnen,
VerbrauchsausweisGewerbe,
} from "@ibcornelsen/database/client";
import { import {
GebaeudeAufnahmeClient, GebaeudeAufnahmeClient,
GebaeudeClient, GebaeudeClient,
@@ -18,10 +14,7 @@
export let gebaeude: GebaeudeClient; export let gebaeude: GebaeudeClient;
export let gebaeude_aufnahme_allgemein: GebaeudeAufnahmeClient; export let gebaeude_aufnahme_allgemein: GebaeudeAufnahmeClient;
export let ausweis: export let ausweis: VerbrauchsausweisWohnenClient
| VerbrauchsausweisWohnenClient
| VerbrauchsausweisGewerbe
| BedarfsausweisWohnen;
export let images: UploadedGebaeudeBild[]; export let images: UploadedGebaeudeBild[];
</script> </script>
@@ -388,4 +381,4 @@
als PDF anschauen</Label als PDF anschauen</Label
> >
<AusweisPreviewContainer {ausweis} {gebaeude} /> <AusweisPreviewContainer bind:images bind:ausweis bind:gebaeude />

View File

@@ -1,17 +1,31 @@
<script lang="ts"> <script lang="ts">
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016"; import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016";
import ThickArrowDown from "radix-svelte-icons/src/lib/icons/ThickArrowDown.svelte"; import ThickArrowDown from "radix-svelte-icons/src/lib/icons/ThickArrowDown.svelte";
import { BedarfsausweisWohnenClient, GebaeudeAufnahmeClient, GebaeudeClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./types"; import {
BedarfsausweisWohnenClient,
GebaeudeAufnahmeClient,
GebaeudeClient,
VerbrauchsausweisGewerbeClient,
VerbrauchsausweisWohnenClient,
} from "./types";
import ThickArrowUp from "radix-svelte-icons/src/lib/icons/ThickArrowUp.svelte"; import ThickArrowUp from "radix-svelte-icons/src/lib/icons/ThickArrowUp.svelte";
export let ausweis: VerbrauchsausweisWohnenClient; export let ausweis: VerbrauchsausweisWohnenClient;
export let gebaeude_aufnahme_allgemein: GebaeudeAufnahmeClient;
export let gebaeude: GebaeudeClient;
let maxPerformance = 250; let maxPerformance = 250;
/** /**
* We use linear interpolation to scale the value between the given boundaries. * We use linear interpolation to scale the value between the given boundaries.
*/ */
function centerValueBetweenBoundaries(value: number, newMinimum: number, newMaximum: number, oldMinimum: number = 0, oldMaximum: number = 100): number { function centerValueBetweenBoundaries(
value: number,
newMinimum: number,
newMaximum: number,
oldMinimum: number = 0,
oldMaximum: number = 100
): number {
// Calculate the center point of the current range // Calculate the center point of the current range
const center = (oldMinimum + oldMaximum) / 2; const center = (oldMinimum + oldMaximum) / 2;
@@ -31,33 +45,62 @@
const scaledValue = shiftedValue * scalingFactor; const scaledValue = shiftedValue * scalingFactor;
// Shift the scaled value back to the center of the new range // Shift the scaled value back to the center of the new range
const centeredValue = scaledValue + ((newMaximum + newMinimum) / 2); const centeredValue = scaledValue + (newMaximum + newMinimum) / 2;
return centeredValue; return centeredValue;
} }
let translation_1 = 0; let translation_1 = 0;
let translation_2 = 0; let translation_2 = 0;
$: { $: {
(async () => { (async () => {
const result = (await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis)); const result = await endEnergieVerbrauchVerbrauchsausweis_2016({
...ausweis,
gebaeude_aufnahme_allgemein: {
...gebaeude_aufnahme_allgemein,
gebaeude_stammdaten: gebaeude,
},
});
console.log(result, ausweis);
if (!result) { if (!result) {
return return;
} }
//const primaerEnergieVerbrauch = (await ausweis.primaerEnergieBedarf); translation_1 = Math.max(
translation_1 = Math.max(0, Math.min(100, result.endEnergieVerbrauchGesamt / maxPerformance * 100)) 0,
//translation_2 = Math.max(0, Math.min(100, primaerEnergieVerbrauch / maxPerformance * 100)) Math.min(
})() 100,
(result.endEnergieVerbrauchGesamt / maxPerformance) * 100
)
);
translation_2 = Math.max(0, Math.min(100, result.primaerEnergieVerbrauchGesamt / maxPerformance * 100))
})();
} }
</script> </script>
<div class="w-full rounded-lg border-[#ffcc03] border-2 relative p-2"> <div class="w-full rounded-lg border-[#ffcc03] border-2 relative p-2">
<img src="/images/SKALA-910.png" alt="Energieeffizienz Skala"> <img src="/images/SKALA-910.png" alt="Energieeffizienz Skala" />
<ThickArrowDown size={28} class="fill-base-content absolute top-1 transition-left duration-1000 ease-in-out" <ThickArrowDown
style="left: {translation_1}%; transform: translateX({centerValueBetweenBoundaries(translation_1, 50, -150, 0, 100)}%)" /> size={28}
<ThickArrowUp size={28} class="fill-base-content absolute bottom-1 transition-left duration-1000 ease-in-out" class="fill-base-content absolute top-1 transition-left duration-1000 ease-in-out"
style="left: {translation_2}%; transform: translateX({centerValueBetweenBoundaries(translation_2, 50, -150, 0, 100)}%)" /> style="left: {translation_1}%; transform: translateX({centerValueBetweenBoundaries(
translation_1,
50,
-150,
0,
100
)}%)"
/>
<ThickArrowUp
size={28}
class="fill-base-content absolute bottom-1 transition-left duration-1000 ease-in-out"
style="left: {translation_2}%; transform: translateX({centerValueBetweenBoundaries(
translation_2,
50,
-150,
0,
100
)}%)"
/>
</div> </div>

View File

@@ -4,13 +4,17 @@
import Label from "../Label.svelte"; import Label from "../Label.svelte";
import fuelList from "./brennstoffListe"; import fuelList from "./brennstoffListe";
import { auditVerbrauchAbweichung } from "../Verbrauchsausweis/audits/VerbrauchAbweichung"; import { auditVerbrauchAbweichung } from "../Verbrauchsausweis/audits/VerbrauchAbweichung";
import type { VerbrauchsausweisGewerbe } from "@ibcornelsen/database/client";
import { GebaeudeAufnahmeClient, GebaeudeClient, VerbrauchsausweisWohnenClient } from "./types"; import { GebaeudeAufnahmeClient, GebaeudeClient, VerbrauchsausweisWohnenClient } from "./types";
let availableYears = [ // Wir dürfen bis zu 4.5 Jahre alte Klimafaktoren benutzen, also nehmen wir alle Monate seitdem und generieren daraus die Auswahl.
2018, 2019, // Allerdings müssen wir auch berücksichtigen, dass wir drei folgende Jahre brauchen, also
]; // kann der Nutzer nur 36 + 18 Monate zurückgehen.
let availableMonths = [ let availableDates: {
year: number;
month: number;
}[] = [];
let monthNames = [
"Januar", "Januar",
"Februar", "Februar",
"März", "März",
@@ -25,9 +29,20 @@
"Dezember", "Dezember",
]; ];
const startDate = moment().subtract(4, "years").subtract(6, "months");
const endDate = moment().subtract(3, "years");
for (let m = moment(startDate); m.isBefore(endDate); m.add(1, "month")) {
availableDates.push({
year: m.year(),
month: m.month(),
});
}
export let gebaeude: GebaeudeClient; export let gebaeude: GebaeudeClient;
export let gebaeude_aufnahme_allgemein: GebaeudeAufnahmeClient; export let gebaeude_aufnahme_allgemein: GebaeudeAufnahmeClient;
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbe; export let ausweis: VerbrauchsausweisWohnenClient;
const fuelMap: Record<string, string[]> = {}; const fuelMap: Record<string, string[]> = {};
for (const fuel of fuelList) { for (const fuel of fuelList) {
@@ -36,11 +51,9 @@
fuelMap[fuel[0]].push(fuel[1]); fuelMap[fuel[0]].push(fuel[1]);
} }
console.log(ausweis.startdatum);
let month = ausweis.startdatum?.getMonth() || null;
let month = ausweis.startdatum?.getMonth() || 1; let year = ausweis.startdatum?.getFullYear() || null;
let year = ausweis.startdatum?.getFullYear() || 2018;
$: { $: {
if (typeof month === "number" && typeof year === "number") { if (typeof month === "number" && typeof year === "number") {
@@ -173,9 +186,18 @@
required required
> >
<option>auswählen</option> <option>auswählen</option>
{#each availableMonths as m, i} {#if year !== null}
<option value={i}>{m}</option> {#each availableDates.filter(date => date.year == year) as date}
<option value={date.month}>{monthNames[date.month]}</option>
{/each} {/each}
{:else}
{#each Array.from(availableDates.reduce((a,c) => {
a.add(c.month);
return a;
}, new Set())) as month}
<option value={month}>{monthNames[month]}</option>
{/each}
{/if}
</select> </select>
<select <select
@@ -185,8 +207,11 @@
required required
> >
<option>auswählen</option> <option>auswählen</option>
{#each availableYears as y} {#each Array.from(availableDates.reduce((a,c) => {
<option value={y}>{y}</option> a.add(c.year);
return a;
}, new Set())) as year}
<option value={year}>{year}</option>
{/each} {/each}
</select> </select>
</div> </div>

View File

@@ -4,7 +4,7 @@ import { inferProcedureInput, inferProcedureOutput } from "@trpc/server";
export type UploadedGebaeudeBild = inferProcedureOutput< export type UploadedGebaeudeBild = inferProcedureOutput<
AppRouter["v1"]["verbrauchsausweisWohnen"]["get"] AppRouter["v1"]["verbrauchsausweisWohnen"]["get"]
>["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0]; >["gebaeude_aufnahme_allgemein"]["gebaeude_stammdaten"]["gebaeude_bilder"][0] & { base64?: string };
/** /**

View File

@@ -9,6 +9,9 @@
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbe | BedarfsausweisWohnen; export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbe | BedarfsausweisWohnen;
export let gebaeude: GebaeudeClient; export let gebaeude: GebaeudeClient;
export let kategorie: Enums.BilderKategorie export let kategorie: Enums.BilderKategorie
console.log(images);
</script> </script>
<div class="flex flex-col gap-4"> <div class="flex flex-col gap-4">
@@ -18,7 +21,7 @@
{#if image.kategorie == kategorie} {#if image.kategorie == kategorie}
<div class="relative group"> <div class="relative group">
<img <img
src="/bilder/{image.uid}.webp" src={image.base64 ? image.base64 : `/bilder/${image.uid}.webp`}
alt={kategorie} alt={kategorie}
class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all" class="h-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
/> />

View File

@@ -2,7 +2,7 @@
<nav> <nav>
<div class="nav-card"> <div class="nav-card">
<div class="card-menu-option dropdown dropdown-right dropdown-hover"> <div class="card-menu-option dropdown dropdown-right dropdown-hover">
<a href="/energieausweis-erstellen" <a href="/energieausweis-erstellen/verbrauchsausweis-wohnen"
>Energieausweis erstellen</a >Energieausweis erstellen</a
> >
<div class="dropdown-content"> <div class="dropdown-content">

View File

@@ -0,0 +1,41 @@
<script lang="ts">
import { dialogs } from "svelte-dialogs";
import TicketPopup from "./TicketPopup.svelte";
import { addNotification } from "@ibcornelsen/ui";
async function showTicketPopup() {
const success = await dialogs.modal(TicketPopup);
if (success) {
dialogs.alert({
title: "Ticket erstellt",
text: "Ihr Support Ticket wurde erfolgreich erstellt. Wir werden uns schnellstmöglich um ihre Angelegenheit kümmern. Vielen Dank für ihre Geduld.",
dismissButtonText: "Schließen",
dismissButtonClass: "btn btn-primary",
dialogClass: "modal-box",
headerClass: "bg-base-100 text-center",
titleClass: "text-base-content text-xl font-medium",
dividerClass: "hidden",
footerClass: "bg-base-100 justify-center gap-4 mt-4",
});
} else {
dialogs.alert({
title: "Ticket erstellen fehlgeschlagen",
text: "Leider ist beim erstellen des Tickets ein Fehler aufgetreten. Bitte versuchen sie es später erneut oder kontaktieren sie uns direkt per email unter info@ib-cornelsen.de.",
dismissButtonText: "Schließen",
dismissButtonClass: "btn btn-error",
dialogClass: "modal-box",
headerClass: "bg-base-100 text-center",
titleClass: "text-base-content text-xl font-medium",
dividerClass: "hidden",
footerClass: "bg-base-100 justify-center gap-4 mt-4",
});
}
}
</script>
<button
class="btn btn-primary fixed bottom-0 right-8 rounded-b-none rounded-t-xl w-48 h-12 text-xl hover:h-14 transition-all"
on:click={showTicketPopup}
>Support Ticket</button
>

View File

@@ -0,0 +1,104 @@
<script lang="ts">
import { addNotification } from "#components/Notifications/shared";
import { client } from "src/trpc";
import { getClose } from "svelte-dialogs";
const close = getClose();
async function createTicket(e: SubmitEvent) {
e.preventDefault();
try {
await client.v1.tickets.erstellen.mutate({
beschreibung: description,
email: email,
metadata: {
category: category,
phone: phone,
},
titel: title,
})
// Ticket wurde erfolgreich erstellt
close(true)
} catch (e) {
// Beim erstellen des Tickets ist ein Fehler aufgetreten, das ist ja mal ironisch...
close(false)
}
}
let category = "";
let title = "";
let description = "";
let email = "";
let phone = "";
</script>
<form class="max-w-lg" on:submit={createTicket}>
<h1 class="text-2xl font-semibold mb-6">Ticket erstellen</h1>
<p class="mb-6">
Vielen Dank, dass sie sich die Zeit nehmen ein Support Ticket zu
erstellen. Wir werden uns schnellstmöglich um ihre Angelegenheit
kümmern. Hier können sie alle Details eintragen und uns ihr Problem
schildern.
</p>
<div class="flex flex-col gap-4">
<div>
<h4>Kategorie *</h4>
<select class="select select-bordered" bind:value={category}>
<option value="" disabled selected>Bitte Auswählen</option>
<option value="Verständnisproblem">Verständnisproblem</option>
<option value="Technischer Fehler">Technischer Fehler</option>
<option value="Feature anfordern">Feature anfordern</option>
<option value="Fehlende Funktionalität"
>Fehlende Funktionalität</option
>
</select>
</div>
<div>
<h4>Überschrift *</h4>
<input
class="input input-bordered"
type="text"
placeholder="Überschrift in einem Satz"
name="title"
bind:value={title}
required
/>
</div>
<div>
<h4>Beschreibung *</h4>
<textarea
cols="10"
rows="5"
class="textarea textarea-bordered"
placeholder="Schildern sie hier ihre Erfahrung"
bind:value={description}
required
></textarea>
</div>
<div class="flex flex-row gap-4">
<div class="w-full">
<h4>Email Adresse *</h4>
<input
class="input input-bordered"
type="email"
placeholder="Ihre Email Adresse"
name="email"
bind:value={email}
required
/>
</div>
<div class="w-full">
<h4>Telefonnummer</h4>
<input
class="input input-bordered"
type="tel"
placeholder="Ihre Telefonnumer"
name="phone"
bind:value={phone}
required
/>
</div>
</div>
<button class="btn btn-primary" type="submit">Abschicken</button>
</div>
</form>

View File

@@ -4,7 +4,7 @@ import * as fs from "fs";
const start = moment().set("year", 2019).set("month", 8).set("date", 1); const start = moment().set("year", 2019).set("month", 8).set("date", 1);
const end = moment().set("year", 2022).set("month", 10).set("date", 1); const end = moment().set("year", 2023).set("month", 1).set("date", 1);
let current = start.clone(); let current = start.clone();

View File

@@ -8,6 +8,7 @@ import Header from "../components/Header.astro";
import SidebarLeft from "../components/SidebarLeft.astro"; import SidebarLeft from "../components/SidebarLeft.astro";
import SidebarRight from "../components/SidebarRight.astro"; import SidebarRight from "../components/SidebarRight.astro";
import { NotificationWrapper } from "@ibcornelsen/ui"; import { NotificationWrapper } from "@ibcornelsen/ui";
import TicketPopup from "../components/Tickets/TicketButton.svelte"
export interface Props { export interface Props {
title: string; title: string;
@@ -104,6 +105,7 @@ const schema = JSON.stringify({
</main> </main>
<Footer /> <Footer />
<NotificationWrapper client:load /> <NotificationWrapper client:load />
<TicketPopup client:load />
</body> </body>
</html> </html>

View File

@@ -1,6 +1,7 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { getKlimafaktoren } from "#lib/Klimafaktoren"; import { getKlimafaktoren } from "#lib/Klimafaktoren";
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor"; import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor";
import { Enums } from "@ibcornelsen/database/client";
import moment from "moment"; import moment from "moment";
export function energetischeNutzflaecheVerbrauchsausweisWohnen_2016( export function energetischeNutzflaecheVerbrauchsausweisWohnen_2016(
@@ -11,7 +12,8 @@ export function energetischeNutzflaecheVerbrauchsausweisWohnen_2016(
} }
let faktorKeller = 1.2; let faktorKeller = 1.2;
if (ausweis.keller_beheizt && (ausweis.gebaeude_aufnahme_allgemein.einheiten || 1) <= 2) { // Falls das Gebäude einen Keller besitzt der Beheizt ist erhöhen wir die Nutzfläche um 15%
if (ausweis.gebaeude_aufnahme_allgemein.keller == Enums.Heizungsstatus.BEHEIZT && (ausweis.gebaeude_aufnahme_allgemein.einheiten || 1) <= 2) {
faktorKeller = 1.35; faktorKeller = 1.35;
} }
@@ -129,6 +131,10 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
let energieVerbrauchHeizung_1 = energieVerbrauchGesamt_1; let energieVerbrauchHeizung_1 = energieVerbrauchGesamt_1;
let energieVerbrauchHeizung_2 = energieVerbrauchGesamt_2; let energieVerbrauchHeizung_2 = energieVerbrauchGesamt_2;
// TODO: Im aktuellen Skript vom Live System kommt hier etwas anderes raus,
// vielleicht ist da etwas kaputt? Da scheint es so, als wäre
// warmwasser_enthalten immer true...
// NOTE: Das hier müsste die richtige Version sein...
if (ausweis.warmwasser_enthalten) { if (ausweis.warmwasser_enthalten) {
energieVerbrauchHeizung_1 -= energieVerbrauchWarmwasser_1; energieVerbrauchHeizung_1 -= energieVerbrauchWarmwasser_1;
energieVerbrauchHeizung_2 -= energieVerbrauchWarmwasser_2; energieVerbrauchHeizung_2 -= energieVerbrauchWarmwasser_2;
@@ -285,7 +291,7 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
(ausweis.verbrauch_6 || 0) * brennstoff_2.umrechnungsfaktor (ausweis.verbrauch_6 || 0) * brennstoff_2.umrechnungsfaktor
), ),
energetische_nutzfläche: Math.round(energetischeNutzflaeche), energetischeNutzflaeche: energetischeNutzflaeche,
leerstand: leerstand, leerstand: leerstand,
leerstandsZuschlagHeizung: Math.round(leerstandsZuschlagHeizung), leerstandsZuschlagHeizung: Math.round(leerstandsZuschlagHeizung),
leerstandsZuschlagWarmwasser: Math.round(leerstandsZuschlagWarmwasser), leerstandsZuschlagWarmwasser: Math.round(leerstandsZuschlagWarmwasser),
@@ -331,6 +337,9 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
primaerEnergieVerbrauchKuehlungsZuschlag primaerEnergieVerbrauchKuehlungsZuschlag
), ),
primaerfaktorww,
primaerfaktorww_1,
co2Emissionen_1: co2Emissionen_1, co2Emissionen_1: co2Emissionen_1,
co2Emissionen_2: co2Emissionen_2, co2Emissionen_2: co2Emissionen_2,

View File

@@ -0,0 +1,135 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { faker } from "@faker-js/faker";
import { Enums } from "@ibcornelsen/database/client";
import moment from "moment";
export async function importVerbrauchsausweisWohnenAltesSystem(count: number = 5) {
const response = await fetch("https://online-energieausweis.org/user/ausweis-import.php", {
method: "POST",
body: JSON.stringify({
i: count,
offset: 0,
q: {}
})
})
const data = await response.json();
return data
}
export function verbrauchsausweisWohnenImportTranslate(ausweis: Record<string, any>) {
const ausweisTranslated: VerbrauchsausweisWohnenClient = {
rechnungen: null,
gebaeude_aufnahme_allgemein: {
baujahr_gebaeude: [ausweis.baujahr_gebaeude],
baujahr_heizung: [ausweis.baujahr_anlage],
baujahr_klima: [ausweis.baujahr_klimaanlage],
adresse: ausweis.objekt_strasse,
plz: ausweis.objekt_plz,
ort: ausweis.objekt_ort,
nutzflaeche: ausweis.nutzflaeche,
einheiten: ausweis.anzahl_einheiten,
saniert: ausweis.objekt_saniert,
keller: ausweis.keller_beheizt == "Beheizt" ? Enums.Heizungsstatus.BEHEIZT : ausweis.keller_beheizt == "Unbeheizt" ? Enums.Heizungsstatus.UNBEHEIZT : Enums.Heizungsstatus.NICHT_VORHANDEN,
dachgeschoss: ausweis.dachgeschoss == "Beheizt" ? Enums.Heizungsstatus.BEHEIZT : ausweis.dachgeschoss == "Unbeheizt" ? Enums.Heizungsstatus.UNBEHEIZT : Enums.Heizungsstatus.NICHT_VORHANDEN,
flaeche: ausweis.wohnflaeche,
gebaeudetyp: ausweis.objekt_typ,
gebaeudeteil: ausweis.objekt_gebaeudeteil,
lueftung: ausweis.lueftungskonzept,
kuehlung: ausweis.wird_gekuehlt,
gebaeude_stammdaten: {
adresse: ausweis.objekt_strasse,
plz: ausweis.objekt_plz,
ort: ausweis.objekt_ort,
uid: faker.string.uuid(),
gebaeude_bilder: [],
latitude: null,
longitude: null,
},
brennstoff_1: ausweis.energietraeger_1,
brennstoff_2: ausweis.energietraeger_2,
alternative_heizung: ausweis.alheizung,
alternative_kuehlung: ausweis.alkuehlung,
alternative_lueftung: ausweis.allueftung,
alternative_warmwasser: ausweis.alwarmwasser,
ausweisart: Enums.Ausweisart.VerbrauchsausweisWohnen,
energieeffizienzklasse: "",
aussenwand_gedaemmt: ausweis.aussenwand_gedaemmt,
aussenwand_min_12cm_gedaemmt: ausweis.aussenwand_min_12cm_gedaemmt,
bestellt: ausweis.bestellt,
boxpruefung: ausweis.boxpruefung,
brennwert_kessel: ausweis.brennwert_kessel,
dachgeschoss_gedaemmt: ausweis.dachgeschoss_gedaemmt,
dachgeschoss_min_12cm_gedaemmt: ausweis.dachgeschoss_min_12cm_gedaemmt,
doppel_verglasung: ausweis.doppel_verglasung,
dreifach_verglasung: ausweis.dreifach_verglasung,
durchlauf_erhitzer: ausweis.durchlauf_erhitzer,
einfach_verglasung: ausweis.einfach_verglasung,
einzelofen: ausweis.einzelofen,
erledigt: ausweis.erledigt,
erstellungsdatum: ausweis.erstellungsdatum,
fenster_dicht: ausweis.fenster_dicht,
fenster_teilweise_undicht: ausweis.fenster_teilweise_undicht,
heizungsrohre_gedaemmt: ausweis.heizungsrohre_gedaemmt,
isolier_verglasung: ausweis.isolier_verglasung,
keller_decke_gedaemmt: ausweis.keller_decke_gedaemmt,
keller_wand_gedaemmt: ausweis.keller_wand_gedaemmt,
niedertemperatur_kessel: ausweis.niedertemperatur_kessel,
oberste_geschossdecke_gedaemmt: ausweis.oberste_geschossdecke_gedaemmt,
oberste_geschossdecke_min_12cm_gedaemmt: ausweis.oberste_geschossdecke_min_12cm_gedaemmt,
raum_temperatur_regler: ausweis.raum_temperatur_regler,
rolllaeden_kaesten_gedaemmt: ausweis.rolllaeden_kaesten_gedaemmt,
solarsystem_warmwasser: ausweis.solarsystem_warmwasser,
standard_kessel: ausweis.standard_kessel,
waermepumpe: ausweis.waermepumpe,
warmwasser_rohre_gedaemmt: ausweis.warmwasser_rohre_gedaemmt,
zentralheizung: ausweis.zentralheizung,
zirkulation: ausweis.zirkulation,
photovoltaik: ausweis.photovoltaik,
leerstand: ausweis.leerstand,
prueftext: ausweis["check-texts"],
storniert: false,
tueren_dicht: ausweis.tueren_dicht,
tueren_undicht: ausweis.tueren_undicht,
zurueckgestellt: ausweis.zurueckGestellt,
uid: faker.string.uuid(),
events: []
},
verbrauch_1: parseInt(ausweis.energieverbrauch_1_heizquelle_1),
verbrauch_2: parseInt(ausweis.energieverbrauch_2_heizquelle_1),
verbrauch_3: parseInt(ausweis.energieverbrauch_3_heizquelle_1),
verbrauch_4: parseInt(ausweis.energieverbrauch_1_heizquelle_2),
verbrauch_5: parseInt(ausweis.energieverbrauch_2_heizquelle_2),
verbrauch_6: parseInt(ausweis.energieverbrauch_3_heizquelle_2),
einheit_1: ausweis.energietraeger_einheit_heizquelle_1,
einheit_2: ausweis.energietraeger_einheit_heizquelle_2,
warmwasser_enthalten: ausweis.warmwasser_enthalten,
uid: faker.string.uuid(),
alternative_heizung: ausweis.alheizung,
alternative_kuehlung: ausweis.alkuehlung,
alternative_lueftung: ausweis.allueftung,
alternative_warmwasser: ausweis.alwarmwasser,
anteil_warmwasser_1: ausweis.anteil_warmwasser_1,
anteil_warmwasser_2: ausweis.anteil_warmwasser_2,
ausstellgrund: ausweis.ausstellgrund,
ausstellungsdatum: moment(ausweis.bestelldatum).toDate(),
erledigt: ausweis.erledigt,
erstellungsdatum: moment(ausweis.erstellungsdatum).toDate(),
keller_beheizt: ausweis.keller_beheizt,
registriernummer: ausweis.regnummer,
// Der Monat im alten System ist 1-basiert, in der neuen Datenbank 0-basiert
// Also müssen wir hier 1 abziehen
startdatum: moment(`${ausweis.energieverbrauch_zeitraum_jahr}-${ausweis.energieverbrauch_zeitraum_monat}-01`).toDate(),
warmwasser_anteil_bekannt: ausweis.warmwasser_anteil_bekannt,
wird_gekuehlt: ausweis.wird_gekuehlt,
zusaetzliche_heizquelle: ausweis.zusaetzliche_heizquelle,
}
return ausweisTranslated
}

View File

@@ -0,0 +1,118 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { faker } from "@faker-js/faker";
import { Enums } from "@ibcornelsen/database/client";
export function verbrauchsausweisWohnenFaker(seed: number = 42): VerbrauchsausweisWohnenClient {
faker.seed(seed);
const tuerenDicht = faker.datatype.boolean();
const verbrauch_1 = faker.number.int({ min: 5000, max: 20000 });
const verbrauch_4 = faker.number.int({ min: 5000, max: 15000 });
const ausweis: VerbrauchsausweisWohnenClient = {
rechnungen: null,
gebaeude_aufnahme_allgemein: {
baujahr_gebaeude: [faker.number.int({ min: 1960, max: 2014 })],
baujahr_heizung: [faker.number.int({ min: 1960, max: 2014 })],
baujahr_klima: [faker.number.int({ min: 1985, max: 2014 })],
adresse: faker.location.streetAddress(),
plz: faker.location.zipCode({ format: "#####" }),
ort: faker.location.city(),
nutzflaeche: faker.number.int({ min: 50, max: 300 }),
einheiten: faker.number.int({ min: 1, max: 3 }),
saniert: faker.datatype.boolean(),
keller: faker.helpers.enumValue(Enums.Heizungsstatus),
dachgeschoss: faker.helpers.enumValue(Enums.Heizungsstatus),
flaeche: faker.number.int({ min: 50, max: 300 }),
gebaeudetyp: "Einfamilienhaus",
gebaeudeteil: "Gesamtgebäude",
lueftung: "Fensterlüftung",
kuehlung: "Vorhanden",
gebaeude_stammdaten: {
adresse: faker.location.streetAddress(),
plz: faker.location.zipCode({ format: "#####" }),
ort: faker.location.city(),
uid: faker.string.uuid(),
gebaeude_bilder: [],
latitude: faker.location.latitude(),
longitude: faker.location.longitude(),
},
brennstoff_1: "Erdgas H",
alternative_heizung: faker.datatype.boolean(),
alternative_kuehlung: faker.datatype.boolean(),
alternative_lueftung: faker.datatype.boolean(),
alternative_warmwasser: faker.datatype.boolean(),
aussenwand_gedaemmt: faker.datatype.boolean(),
aussenwand_min_12cm_gedaemmt: faker.datatype.boolean(),
ausweisart: Enums.Ausweisart.VerbrauchsausweisWohnen,
bestellt: faker.datatype.boolean(),
boxpruefung: faker.datatype.boolean(),
brennstoff_2: "Erdgas H",
brennwert_kessel: faker.datatype.boolean(),
dachgeschoss_gedaemmt: faker.datatype.boolean(),
dachgeschoss_min_12cm_gedaemmt: faker.datatype.boolean(),
doppel_verglasung: faker.datatype.boolean(),
dreifach_verglasung: faker.datatype.boolean(),
durchlauf_erhitzer: faker.datatype.boolean(),
einfach_verglasung: faker.datatype.boolean(),
einzelofen: faker.datatype.boolean(),
energieeffizienzklasse: "",
erledigt: faker.datatype.boolean(),
erstellungsdatum: faker.date.past(),
fenster_dicht: faker.datatype.boolean(),
fenster_teilweise_undicht: faker.datatype.boolean(),
heizungsrohre_gedaemmt: faker.datatype.boolean(),
isolier_verglasung: faker.datatype.boolean(),
keller_decke_gedaemmt: faker.datatype.boolean(),
keller_wand_gedaemmt: faker.datatype.boolean(),
leerstand: faker.number.int({ min: 0, max: 20 }),
niedertemperatur_kessel: faker.datatype.boolean(),
oberste_geschossdecke_gedaemmt: faker.datatype.boolean(),
oberste_geschossdecke_min_12cm_gedaemmt: faker.datatype.boolean(),
photovoltaik: faker.datatype.boolean(),
prueftext: faker.lorem.sentence(),
raum_temperatur_regler: faker.datatype.boolean(),
rolllaeden_kaesten_gedaemmt: faker.datatype.boolean(),
solarsystem_warmwasser: faker.datatype.boolean(),
standard_kessel: faker.datatype.boolean(),
storniert: false,
tueren_dicht: tuerenDicht,
tueren_undicht: !tuerenDicht,
waermepumpe: faker.datatype.boolean(),
warmwasser_rohre_gedaemmt: faker.datatype.boolean(),
zentralheizung: faker.datatype.boolean(),
zirkulation: faker.datatype.boolean(),
zurueckgestellt: faker.datatype.boolean(),
uid: faker.string.uuid(),
events: []
},
verbrauch_1: verbrauch_1,
verbrauch_2: verbrauch_1 + faker.number.int({ min: -2000, max: 2000 }),
verbrauch_3: verbrauch_1 + faker.number.int({ min: -2000, max: 2000 }),
einheit_1: "kWh",
warmwasser_enthalten: faker.datatype.boolean(),
uid: faker.string.uuid(),
alternative_heizung: faker.datatype.boolean(),
alternative_kuehlung: faker.datatype.boolean(),
alternative_lueftung: faker.datatype.boolean(),
alternative_warmwasser: faker.datatype.boolean(),
anteil_warmwasser_1: faker.number.int({ min: 0, max: 60 }),
anteil_warmwasser_2: faker.number.int({ min: 0, max: 60 }),
ausstellgrund: faker.helpers.enumValue(Enums.Ausstellgrund),
ausstellungsdatum: faker.date.past(),
einheit_2: "kWh",
erledigt: faker.datatype.boolean(),
erstellungsdatum: faker.date.past(),
keller_beheizt: faker.datatype.boolean(),
registriernummer: faker.string.uuid(),
startdatum: faker.date.past({ years: 3 }),
verbrauch_4: verbrauch_4,
verbrauch_5: verbrauch_4 + faker.number.int({ min: -2000, max: 2000 }),
verbrauch_6: verbrauch_4 + faker.number.int({ min: -2000, max: 2000 }),
warmwasser_anteil_bekannt: faker.datatype.boolean(),
wird_gekuehlt: faker.datatype.boolean(),
zusaetzliche_heizquelle: faker.datatype.boolean(),
}
return ausweis;
}

View File

@@ -38,8 +38,13 @@
async function spaeterWeitermachen() { async function spaeterWeitermachen() {
const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, gebaeude_aufnahme_allgemein, images, user); const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, gebaeude_aufnahme_allgemein, images, user);
if (result === true) { if (result !== null) {
window.history.pushState({}, "", `${location.pathname}?uid=${ausweis.uid}`); // Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
// Sonst müsste er alles neu eingeben...
ausweis.uid = result.uid
gebaeude.uid = result.gebaeude_uid
gebaeude_aufnahme_allgemein.uid = result.gebaeude_aufnahme_uid
window.history.pushState({}, "", `${location.pathname}?uid=${result.uid}`);
speichernOverlayHidden = false; speichernOverlayHidden = false;
} }
} }
@@ -74,11 +79,14 @@
if (e && e.preventDefault) e.preventDefault(); if (e && e.preventDefault) e.preventDefault();
const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, gebaeude_aufnahme_allgemein, images, user); const result = await verbrauchsausweisWohnenSpeichern(ausweis, gebaeude, gebaeude_aufnahme_allgemein, images, user);
if (result === true) { if (result !== null) {
// Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen. // Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
// Sonst müsste er alles neu eingeben... // Sonst müsste er alles neu eingeben...
window.history.pushState({}, "", `${location.pathname}?uid=${ausweis.uid}`); ausweis.uid = result.uid
window.location.href = `/kundendaten?uid=${ausweis.uid}`; gebaeude.uid = result.gebaeude_uid
gebaeude_aufnahme_allgemein.uid = result.gebaeude_aufnahme_uid
window.history.pushState({}, "", `${location.pathname}?uid=${result.uid}`);
window.location.href = `/kundendaten?uid=${result.uid}`;
} }
} }
@@ -102,7 +110,7 @@
<Progressbar progress={0} /> <Progressbar progress={0} />
</div> </div>
<PerformanceScore bind:ausweis /> <PerformanceScore bind:ausweis bind:gebaeude_aufnahme_allgemein bind:gebaeude />
</div> </div>
<form on:submit={ausweisAbschicken} name="ausweis" data-test="ausweis"> <form on:submit={ausweisAbschicken} name="ausweis" data-test="ausweis">
@@ -384,7 +392,7 @@
Bitte wählen Sie hier den Gebäudetyp aus. Bitte wählen Sie hier den Gebäudetyp aus.
</HelpLabel> </HelpLabel>
<div> <div>
<select name="gebaeudetyp" data-test="gebaeudetyp" required> <select name="gebaeudetyp" data-test="gebaeudetyp" bind:value={gebaeude_aufnahme_allgemein.gebaeudetyp} required>
<option disabled>Bitte auswählen</option> <option disabled>Bitte auswählen</option>
<option value="Einfamilienhaus">Einfamilienhaus</option> <option value="Einfamilienhaus">Einfamilienhaus</option>
<option value="Freistehendes Einfamilienhaus" <option value="Freistehendes Einfamilienhaus"
@@ -423,7 +431,7 @@
'Gewerbe'. 'Gewerbe'.
</HelpLabel> </HelpLabel>
<div> <div>
<select name="gebaeudeteil" data-test="gebaeudeteil" required> <select name="gebaeudeteil" data-test="gebaeudeteil" bind:value={gebaeude_aufnahme_allgemein.gebaeudeteil} required>
<option disabled>Bitte auswählen</option> <option disabled>Bitte auswählen</option>
<option value="Gesamtgebäude">Gesamtgebäude</option> <option value="Gesamtgebäude">Gesamtgebäude</option>
<option value="Wohnen">Wohnen</option> <option value="Wohnen">Wohnen</option>

View File

@@ -19,9 +19,17 @@
let container: HTMLDivElement; let container: HTMLDivElement;
let designer: Designer; let designer: Designer;
let page: number = 0;
onMount(() => { onMount(() => {
designer = new Designer({ domContainer: container, template, plugins }); designer = new Designer({ domContainer: container, template, plugins });
console.log(designer);
designer.onChangePage((p) => {
page = p
});
}); });
function loadBasePDF() { function loadBasePDF() {
@@ -44,7 +52,7 @@
function addNewField() { function addNewField() {
template = designer.getTemplate(); template = designer.getTemplate();
template.schemas[0]["new-field"] = { template.schemas[page]["new-field"] = {
type: "text", type: "text",
position: { x: 0, y: 0 }, position: { x: 0, y: 0 },
width: 10, width: 10,

View File

@@ -2,11 +2,7 @@
import ZipSearch from "../components/PlzSuche.svelte"; import ZipSearch from "../components/PlzSuche.svelte";
import Label from "../components/Label.svelte"; import Label from "../components/Label.svelte";
import type { import type {
BedarfsausweisWohnen,
Benutzer,
Bezahlmethoden, Bezahlmethoden,
VerbrauchsausweisGewerbe,
VerbrauchsausweisWohnen,
} from "@ibcornelsen/database/client"; } from "@ibcornelsen/database/client";
import { Enums } from "@ibcornelsen/database/client"; import { Enums } from "@ibcornelsen/database/client";
import PaymentOption from "#components/PaymentOption.svelte"; import PaymentOption from "#components/PaymentOption.svelte";
@@ -15,6 +11,7 @@
import type { AppRouter } from "@ibcornelsen/api"; import type { AppRouter } from "@ibcornelsen/api";
import CheckoutItem from "#components/CheckoutItem.svelte"; import CheckoutItem from "#components/CheckoutItem.svelte";
import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { PRICES } from "#lib/constants";
export let user: BenutzerClient; export let user: BenutzerClient;
export let ausweis: export let ausweis:
@@ -22,7 +19,18 @@
// TODO: überarbeiten und zu inferProcedureOutput machen // TODO: überarbeiten und zu inferProcedureOutput machen
let rechnung: inferProcedureInput< let rechnung: inferProcedureInput<
AppRouter["v1"]["rechnungen"]["erstellen"] AppRouter["v1"]["rechnungen"]["erstellen"]
> = {}; > = {
email: user.email,
empfaenger: user.vorname + " " + user.name,
strasse: user.adresse,
plz: user.plz,
ort: user.ort,
versand_empfaenger: user.vorname + " " + user.name,
versand_strasse: user.adresse,
versand_plz: user.plz,
versand_ort: user.ort,
telefon: user.telefon,
};
let services = [ let services = [
{ {
@@ -54,15 +62,12 @@
export let selectedPaymentType: Bezahlmethoden = export let selectedPaymentType: Bezahlmethoden =
Enums.Bezahlmethoden.paypal; Enums.Bezahlmethoden.paypal;
let agbAkzeptiert: boolean;
let datenschutzAkzeptiert: boolean;
async function createPayment(e: SubmitEvent) { async function createPayment(e: SubmitEvent) {
e.preventDefault(); e.preventDefault();
const response = await client.v1.rechnungen.erstellen.mutate({ const response = await client.v1.rechnungen.erstellen.mutate({
...rechnung, ...rechnung,
ausweisart: ausweis.gebaeude_aufnahme_allgemein.ausweisart, ausweisart: Enums.Ausweisart.VerbrauchsausweisWohnen,
uid: ausweis.uid, uid: ausweis.uid,
bezahlmethode: selectedPaymentType, bezahlmethode: selectedPaymentType,
services: services services: services
@@ -72,9 +77,16 @@
window.location.href = response.checkout_url; window.location.href = response.checkout_url;
} }
const priceTotal = services.reduce((acc, service) => {
if (service.selected) {
return acc + service.price;
}
return acc;
}, 0) + PRICES[Enums.Ausweisart.VerbrauchsausweisWohnen][0];
</script> </script>
<div class="grid grid-cols-[2fr_1fr] gap-4 h-full"> <form class="grid grid-cols-[2fr_1fr] gap-4 h-full" on:submit={createPayment}>
<div> <div>
<h3 class="font-semibold">Ansprechpartner</h3> <h3 class="font-semibold">Ansprechpartner</h3>
<div class="rounded-lg border p-4 border-base-300 bg-base-100"> <div class="rounded-lg border p-4 border-base-300 bg-base-100">
@@ -348,23 +360,23 @@
<div class="mt-auto"> <div class="mt-auto">
<hr /> <hr />
<div class="flex flex-row items-center justify-between"> <div class="flex flex-row items-center justify-between">
<span class="opacity-75 text-sm">Brutto</span> <span class="opacity-75 text-sm">Netto</span>
<span class="font-semibold text-sm">45</span> <span class="font-semibold text-sm">{priceTotal * 0.81}</span>
</div> </div>
<div class="flex flex-row items-center justify-between"> <div class="flex flex-row items-center justify-between">
<span class="opacity-75 text-sm">Netto</span> <span class="opacity-75 text-sm">19% MwSt</span>
<span class="font-semibold text-sm">45</span> <span class="font-semibold text-sm">{priceTotal * 0.19}</span>
</div> </div>
<hr /> <hr />
<div class="flex flex-row items-center justify-between"> <div class="flex flex-row items-center justify-between">
<span class="opacity-75 text-sm">Gesamt</span> <span class="opacity-75 text-sm">Gesamt</span>
<span class="font-semibold text-sm">45</span> <span class="font-semibold text-sm">{priceTotal}</span>
</div> </div>
<p class="mt-8">Mit dem Klick auf "Bestellung Bestätigen" akzeptieren sie unsere <a href="/agb">AGB</a> und <a href="/impressum">Datenschutzbestimmungen</a>. Sie werden zu ihrem ausgewählten Bezahlprovider weitergeleitet, nach Bezahlung werden sie automatisch zu unserem Portal zurückgeleitet.</p> <p class="mt-8">Mit dem Klick auf "Bestellung Bestätigen" akzeptieren sie unsere <a href="/agb">AGB</a> und <a href="/impressum">Datenschutzbestimmungen</a>. Sie werden zu ihrem ausgewählten Bezahlprovider weitergeleitet, nach Bezahlung werden sie automatisch zu unserem Portal zurückgeleitet.</p>
<button class="btn btn-secondary w-full mt-4" disabled <button class="btn btn-secondary w-full mt-4"
>Bestellung Bestätigen</button >Bestellung Bestätigen</button
> >
</div> </div>
</div> </div>
</div> </div>
</div> </form>

View File

@@ -4,6 +4,8 @@
Bezahlmethoden, Bezahlmethoden,
} from "@ibcornelsen/database/client"; } from "@ibcornelsen/database/client";
import { Enums } from "@ibcornelsen/database/client"; import { Enums } from "@ibcornelsen/database/client";
import { dialogs } from "svelte-dialogs";
import LoginDialog from "#components/LoginDialog.svelte";
export let user: BenutzerClient; export let user: BenutzerClient;
export let ausweis: VerbrauchsausweisWohnenClient; export let ausweis: VerbrauchsausweisWohnenClient;
@@ -40,6 +42,8 @@
import { PRICES } from "#lib/constants"; import { PRICES } from "#lib/constants";
import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { validateAccessTokenClient } from "src/client/lib/validateAccessToken";
import { client } from "src/trpc";
let prices: number[] = [] let prices: number[] = []
@@ -56,12 +60,29 @@
0 0
); );
function speichern(e: SubmitEvent) { async function speichern(e: SubmitEvent) {
e.preventDefault() e.preventDefault()
console.log("Speichern");
// Um einen Ausweis zu speichern müssen wir eingeloggt sein, andernfalls wird die API den call ablehnen.
// Wir prüfen also ob wir eingeloggt sind und leiten den Nutzer ggf. auf die Login Seite weiter.
if (!(await validateAccessTokenClient())) {
// TOOD: Auf Dialog umstellen.
const loggedIn = await dialogs.modal(LoginDialog);
if (!loggedIn) {
return false;
}
}
// Falls der Ausweis noch keine benutzer_id hat müssen wir ihn claimen, damit er dem jetzigen Nutzer zugewiesen wird...
await client.v1.verbrauchsausweisWohnen.claim.mutate({
uid: ausweis.uid
})
window.location.href = `/kaufabschluss?uid=${ausweis.uid}`; window.location.href = `/kaufabschluss?uid=${ausweis.uid}`;
} }
</script> </script>
<div class="w-full px-8"> <div class="w-full px-8">

View File

@@ -21,7 +21,7 @@ const ausweis = await caller.v1.verbrauchsausweisWohnen.get({
const user = await caller.v1.benutzer.self(); const user = await caller.v1.benutzer.self();
if (!ausweis || !user) { if (!ausweis) {
return Astro.redirect("/404"); return Astro.redirect("/404");
} }
--- ---

View File

@@ -1,11 +1,12 @@
--- ---
import { generate } from "@pdfme/generator"; import { generate } from "@pdfme/generator";
import VerbrauchsausweisWohnen2016Template from "../../data/templates/verbrauchsausweis-wohnen-2016.json"; import VerbrauchsausweisWohnen2016Template from "../../lib/pdf/templates/GEG24_Verbrauchsausweis.json";
import { convertAusweisData } from "#lib/AusweisData"; import { convertAusweisData } from "#lib/AusweisData";
import { variable } from "#lib/pdf/plugins/variables"; import { variable } from "#lib/pdf/plugins/variables";
import { text, image } from "@pdfme/schemas" import { text, image } from "@pdfme/schemas"
import { createCaller } from "#lib/caller"; import { createCaller } from "#lib/caller";
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { Template } from "@pdfme/common";
const base64 = Astro.url.searchParams.get("base64"); const base64 = Astro.url.searchParams.get("base64");
let ausweis: Partial<VerbrauchsausweisWohnenClient> | null = null; let ausweis: Partial<VerbrauchsausweisWohnenClient> | null = null;
@@ -27,16 +28,32 @@ if (base64) {
}) })
} }
const template = VerbrauchsausweisWohnen2016Template as Template;
template.schemas.push({})
template.schemas.push({})
template.schemas[2]["energie_1"] = {
position: {
x: 15,
y: 140
},
height: 5,
width: 14,
type: "text",
fontSize: 8,
verticalAlign: "middle"
}
const pdf = await generate({ const pdf = await generate({
template: VerbrauchsausweisWohnen2016Template, template,
plugins: { text, image, variable }, plugins: { text, image, variable },
inputs: [convertAusweisData(ausweis)], inputs: [{...convertAusweisData(ausweis), energie_1: "Hallo"}],
options: { options: {
author: "IB Cornelsen", author: "IB Cornelsen",
creationDate: new Date(), creationDate: new Date(),
creator: "IB Cornelsen", creator: "IB Cornelsen",
language: "de", language: "de",
title: "Verbrauchsausweis Wohnen 2016", title: "Verbrauchsausweis Wohnen GEG 2024",
}, },
}); });

View File

@@ -0,0 +1,28 @@
import { test, describe, expect } from "bun:test";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016";
import { importVerbrauchsausweisWohnenAltesSystem, verbrauchsausweisWohnenImportTranslate } from "#lib/altes-system/import";
describe('Energieverbrauch', async () => {
const alteAusweise = await importVerbrauchsausweisWohnenAltesSystem();
const ausweis = verbrauchsausweisWohnenImportTranslate(alteAusweise.data[0]);
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis);
const berechnungenAlt = alteAusweise.data[0].calculations;
test("Klimafaktoren", async () => {
console.log("PLZ: " + ausweis.gebaeude_aufnahme_allgemein.plz)
expect(berechnungen?.klimafaktoren).toHaveLength(3)
expect(berechnungen?.klimafaktoren.map(x => x.klimafaktor)).toEqual(berechnungenAlt.klimafaktoren)
})
test("Endenergieverbrauch", async () => {
expect(berechnungen?.endEnergieVerbrauchGesamt).toBeCloseTo(berechnungenAlt.endEnergieVerbrauchGesamt, 0)
})
test("Primärenergieverbrauch", async () => {
expect(berechnungen?.primaerEnergieVerbrauchGesamt).toBeCloseTo(berechnungenAlt.primaerEnergieVerbrauchGesamt, 0)
})
})