Merge pull request #433 from IBCornelsen/main

get main
This commit is contained in:
Jens Cornelsen
2025-03-12 17:35:23 +01:00
committed by GitHub
43 changed files with 1041 additions and 495 deletions

View File

@@ -463,6 +463,8 @@ Table VerbrauchsausweisGewerbe {
prueftext String [note: '@zod.describe("Durch den Kunden hinzugefügte Anmerkung zur Vorabprüfung")']
beschreibung String
kontrolldatei_angefragt Boolean [default: false, note: '@zod.describe("Ob bei der Anfrage der Registriernummer eine Kontrolldatei angefragt wurde")']
created_at DateTime [default: `now()`, not null]
updated_at DateTime [not null]
benutzer benutzer
rechnung_id Int [unique]
rechnung Rechnung
@@ -503,6 +505,8 @@ Table VerbrauchsausweisWohnen {
prueftext String [note: '@zod.describe("Durch den Kunden hinzugefügte Anmerkung zur Vorabprüfung")']
beschreibung String
kontrolldatei_angefragt Boolean [default: false, note: '@zod.describe("Ob bei der Anfrage der Registriernummer eine Kontrolldatei angefragt wurde")']
created_at DateTime [default: `now()`, not null]
updated_at DateTime [not null]
benutzer benutzer
rechnung_id Int [unique]
rechnung Rechnung

View File

@@ -0,0 +1,49 @@
-- AlterTable
ALTER TABLE "Anteilshaber" ALTER COLUMN "uid" SET DEFAULT 'ant-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Aufnahme" ALTER COLUMN "uid" SET DEFAULT 'auf-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'bag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'baw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Bild" ALTER COLUMN "uid" SET DEFAULT 'img-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "uid" SET DEFAULT 'evt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGEinpreisung" ALTER COLUMN "uid" SET DEFAULT 'gge-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Objekt" ALTER COLUMN "uid" SET DEFAULT 'obj-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Rechnung" ALTER COLUMN "uid" SET DEFAULT 'inv-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Tickets" ALTER COLUMN "uid" SET DEFAULT 'tkt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Unterlage" ALTER COLUMN "uid" SET DEFAULT 'pln-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'vag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisWohnen" ADD COLUMN "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ALTER COLUMN "uid" SET DEFAULT 'vaw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "benutzer" ALTER COLUMN "uid" SET DEFAULT 'usr-' || gen_random_uuid();

View File

@@ -0,0 +1,48 @@
-- AlterTable
ALTER TABLE "Anteilshaber" ALTER COLUMN "uid" SET DEFAULT 'ant-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Aufnahme" ALTER COLUMN "uid" SET DEFAULT 'auf-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'bag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'baw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Bild" ALTER COLUMN "uid" SET DEFAULT 'img-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "uid" SET DEFAULT 'evt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGEinpreisung" ALTER COLUMN "uid" SET DEFAULT 'gge-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Objekt" ALTER COLUMN "uid" SET DEFAULT 'obj-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Rechnung" ALTER COLUMN "uid" SET DEFAULT 'inv-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Tickets" ALTER COLUMN "uid" SET DEFAULT 'tkt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Unterlage" ALTER COLUMN "uid" SET DEFAULT 'pln-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'vag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'vaw-' || gen_random_uuid(),
ALTER COLUMN "updated_at" DROP DEFAULT;
-- AlterTable
ALTER TABLE "benutzer" ALTER COLUMN "uid" SET DEFAULT 'usr-' || gen_random_uuid();

View File

@@ -0,0 +1,49 @@
-- AlterTable
ALTER TABLE "Anteilshaber" ALTER COLUMN "uid" SET DEFAULT 'ant-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Aufnahme" ALTER COLUMN "uid" SET DEFAULT 'auf-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'bag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'baw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Bild" ALTER COLUMN "uid" SET DEFAULT 'img-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "uid" SET DEFAULT 'evt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGEinpreisung" ALTER COLUMN "uid" SET DEFAULT 'gge-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Objekt" ALTER COLUMN "uid" SET DEFAULT 'obj-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Rechnung" ALTER COLUMN "uid" SET DEFAULT 'inv-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Tickets" ALTER COLUMN "uid" SET DEFAULT 'tkt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Unterlage" ALTER COLUMN "uid" SET DEFAULT 'pln-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ADD COLUMN "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ALTER COLUMN "uid" SET DEFAULT 'vag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'vaw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "benutzer" ALTER COLUMN "uid" SET DEFAULT 'usr-' || gen_random_uuid();

View File

@@ -0,0 +1,48 @@
-- AlterTable
ALTER TABLE "Anteilshaber" ALTER COLUMN "uid" SET DEFAULT 'ant-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Aufnahme" ALTER COLUMN "uid" SET DEFAULT 'auf-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'bag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'baw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Bild" ALTER COLUMN "uid" SET DEFAULT 'img-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "uid" SET DEFAULT 'evt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGEinpreisung" ALTER COLUMN "uid" SET DEFAULT 'gge-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Objekt" ALTER COLUMN "uid" SET DEFAULT 'obj-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Rechnung" ALTER COLUMN "uid" SET DEFAULT 'inv-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Tickets" ALTER COLUMN "uid" SET DEFAULT 'tkt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Unterlage" ALTER COLUMN "uid" SET DEFAULT 'pln-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'vag-' || gen_random_uuid(),
ALTER COLUMN "updated_at" DROP DEFAULT;
-- AlterTable
ALTER TABLE "VerbrauchsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'vaw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "benutzer" ALTER COLUMN "uid" SET DEFAULT 'usr-' || gen_random_uuid();

View File

@@ -62,6 +62,9 @@ model VerbrauchsausweisGewerbe {
/// @zod.describe("Ob bei der Anfrage der Registriernummer eine Kontrolldatei angefragt wurde")
kontrolldatei_angefragt Boolean? @default(false)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
benutzer Benutzer? @relation(fields: [benutzer_id], references: [id], onDelete: NoAction, onUpdate: NoAction)

View File

@@ -66,6 +66,9 @@ model VerbrauchsausweisWohnen {
/// @zod.describe("Ob bei der Anfrage der Registriernummer eine Kontrolldatei angefragt wurde")
kontrolldatei_angefragt Boolean? @default(false)
created_at DateTime @default(now())
updated_at DateTime @updatedAt
benutzer Benutzer? @relation(fields: [benutzer_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
rechnung_id Int? @unique

View File

@@ -13,18 +13,19 @@ export const createCaller = createCallerFactory({
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/forgot-password": await import("../src/pages/api/auth/forgot-password.ts"),
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"),
"auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
"bedarfsausweis-wohnen/[uid]": await import("../src/pages/api/bedarfsausweis-wohnen/[uid].ts"),
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"bilder/[uid]": await import("../src/pages/api/bilder/[uid].ts"),
"geg-nachweis-gewerbe/[uid]": await import("../src/pages/api/geg-nachweis-gewerbe/[uid].ts"),
"geg-nachweis-gewerbe": await import("../src/pages/api/geg-nachweis-gewerbe/index.ts"),
"geg-nachweis-wohnen/[uid]": await import("../src/pages/api/geg-nachweis-wohnen/[uid].ts"),
"geg-nachweis-wohnen": await import("../src/pages/api/geg-nachweis-wohnen/index.ts"),
"objekt": await import("../src/pages/api/objekt/index.ts"),
"rechnung/[uid]": await import("../src/pages/api/rechnung/[uid].ts"),
"rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"),
"rechnung": await import("../src/pages/api/rechnung/index.ts"),
"ticket": await import("../src/pages/api/ticket/index.ts"),

View File

@@ -48,7 +48,58 @@ export async function ausweisSpeichern(
if (aufnahme.uid) {
await api.aufnahme._uid.PATCH.fetch({
...exclude(aufnahme, ["uid"])
baujahr_gebaeude: aufnahme.baujahr_gebaeude,
baujahr_heizung: aufnahme.baujahr_heizung,
baujahr_klima: aufnahme.baujahr_klima,
alternative_heizung: aufnahme.alternative_heizung,
alternative_kuehlung: aufnahme.alternative_kuehlung,
alternative_lueftung: aufnahme.alternative_lueftung,
alternative_warmwasser: aufnahme.alternative_warmwasser,
aussenwand_gedaemmt: aufnahme.aussenwand_gedaemmt,
aussenwand_min_12cm_gedaemmt: aufnahme.aussenwand_min_12cm_gedaemmt,
ausweisart: aufnahme.ausweisart,
brennstoff_1: aufnahme.brennstoff_1,
brennstoff_2: aufnahme.brennstoff_2,
brennwert_kessel: aufnahme.brennwert_kessel,
dachgeschoss: aufnahme.dachgeschoss,
dachgeschoss_gedaemmt: aufnahme.dachgeschoss_gedaemmt,
dachgeschoss_min_12cm_gedaemmt: aufnahme.dachgeschoss_min_12cm_gedaemmt,
doppel_verglasung: aufnahme.doppel_verglasung,
dreifach_verglasung: aufnahme.dreifach_verglasung,
durchlauf_erhitzer: aufnahme.durchlauf_erhitzer,
einfach_verglasung: aufnahme.einfach_verglasung,
einheiten: aufnahme.einheiten,
einzelofen: aufnahme.einzelofen,
energieeffizienzklasse: aufnahme.energieeffizienzklasse,
fenster_dicht: aufnahme.fenster_dicht,
fenster_teilweise_undicht: aufnahme.fenster_teilweise_undicht,
flaeche: aufnahme.flaeche,
gebaeudeteil: aufnahme.gebaeudeteil,
gebaeudetyp: aufnahme.gebaeudetyp,
heizungsrohre_gedaemmt: aufnahme.heizungsrohre_gedaemmt,
isolier_verglasung: aufnahme.isolier_verglasung,
keller: aufnahme.keller,
keller_decke_gedaemmt: aufnahme.keller_decke_gedaemmt,
keller_wand_gedaemmt: aufnahme.keller_wand_gedaemmt,
kuehlung: aufnahme.kuehlung,
leerstand: aufnahme.leerstand,
lueftung: aufnahme.lueftung,
niedertemperatur_kessel: aufnahme.niedertemperatur_kessel,
nutzflaeche: aufnahme.nutzflaeche,
oberste_geschossdecke_gedaemmt: aufnahme.oberste_geschossdecke_gedaemmt,
oberste_geschossdecke_min_12cm_gedaemmt: aufnahme.oberste_geschossdecke_min_12cm_gedaemmt,
photovoltaik: aufnahme.photovoltaik,
raum_temperatur_regler: aufnahme.raum_temperatur_regler,
rolllaeden_kaesten_gedaemmt: aufnahme.rolllaeden_kaesten_gedaemmt,
saniert: aufnahme.saniert,
solarsystem_warmwasser: aufnahme.solarsystem_warmwasser,
standard_kessel: aufnahme.standard_kessel,
tueren_dicht: aufnahme.tueren_dicht,
tueren_undicht: aufnahme.tueren_undicht,
waermepumpe: aufnahme.waermepumpe,
warmwasser_rohre_gedaemmt: aufnahme.warmwasser_rohre_gedaemmt,
zentralheizung: aufnahme.zentralheizung,
zirkulation: aufnahme.zirkulation
}, {
params: {
uid: aufnahme.uid

View File

@@ -138,21 +138,22 @@ export function getAusweisartFromUUID(uid: string): Enums.Ausweisart | null {
return null
}
if (uid.startsWith("vaw")) {
return Enums.Ausweisart.VerbrauchsausweisWohnen
} else if (uid.startsWith("vag")) {
return Enums.Ausweisart.VerbrauchsausweisGewerbe
} else if (uid.startsWith("baw")) {
return Enums.Ausweisart.BedarfsausweisWohnen
} else if (uid.startsWith("bag")) {
return Enums.Ausweisart.BedarfsausweisGewerbe
} else if (uid.startsWith("gnw")) {
return Enums.Ausweisart.GEGNachweisWohnen
} else if (uid.startsWith("gng")) {
return Enums.Ausweisart.GEGNachweisGewerbe
switch(uid.split("-")[0]) {
case "vaw":
return Enums.Ausweisart.VerbrauchsausweisWohnen
case "vag":
return Enums.Ausweisart.VerbrauchsausweisGewerbe
case "baw":
return Enums.Ausweisart.BedarfsausweisWohnen
case "bag":
return Enums.Ausweisart.BedarfsausweisGewerbe
case "gnw":
return Enums.Ausweisart.GEGNachweisWohnen
case "gng":
return Enums.Ausweisart.GEGNachweisGewerbe
default:
return null
}
return null;
}
export type UnterlageClient = Omit<Unterlage, "id" | "aufnahme_id">
@@ -165,10 +166,10 @@ export type ObjektKomplettClient = ObjektClient & {
export type AufnahmeKomplettClient = AufnahmeClient & {
bilder: BildClient[],
unterlagen: UnterlageClient[],
bedarfsausweise_wohnen: BedarfsausweisWohnenClient[],
verbrauchsausweise_wohnen: VerbrauchsausweisWohnenClient[],
verbrauchsausweise_gewerbe: VerbrauchsausweisGewerbeClient[],
geg_nachweise_wohnen: GEGNachweisWohnenClient[]
bedarfsausweise_wohnen: (BedarfsausweisWohnenClient & { rechnung: RechnungClient })[],
verbrauchsausweise_wohnen: (VerbrauchsausweisWohnenClient & { rechnung: RechnungClient })[],
verbrauchsausweise_gewerbe: (VerbrauchsausweisGewerbeClient & { rechnung: RechnungClient })[],
geg_nachweise_wohnen: (GEGNachweisWohnenClient & { rechnung: RechnungClient })[]
}
export type GEGNachweisWohnenClient = Omit<GEGNachweisWohnen, "id" | "aufnahme_id" | "benutzer_id"> & {

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { AufnahmeKomplettClient, BedarfsausweisWohnenClient, getAusweisartFromUUID, ObjektKomplettClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeKomplettClient, BedarfsausweisWohnenClient, getAusweisartFromUUID, ObjektKomplettClient, RechnungClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import moment from "moment";
import { dialogs } from "svelte-dialogs";
import {
@@ -18,6 +18,7 @@
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let aufnahme: AufnahmeKomplettClient;
export let rechnung: RechnungClient;
export let objekt: Objekt;
const progress = ausweis.ausgestellt ? 100 : ausweis.bestellt ? 66 : 33;
@@ -152,11 +153,13 @@
<div class="w-full border rounded-lg my-2">
<div class="bg-green-600 h-4 rounded-lg" class:bg-red-600={progress == 33} class:bg-primary={progress == 66} style="width: {progress}%;"></div>
</div>
<!-- TODO: Metrics für den Fortschritt festlegen -->
<span class="text-sm font-semibold text-base-content"
>{progress}%</span
>
</div>
{#if ausweis.bestellt}
<p class="text-sm font-semibold">Der Ausweis wurde von Ihnen freigegeben und befindet sich in Prüfung vom IB Cornelsen</p>
{/if}
{#await calculations then calculations}
<div class="flex flex-col gap-2">
<div class="flex flex-row justify-between">
@@ -212,6 +215,10 @@
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid={ausweis.uid}"
>Stornieren</a>
{/if}
{#if ausweis.bestellt && (!rechnung || rechnung.bezahlmethode === Enums.Bezahlmethoden.rechnung)}
<a href="/energieausweis-erstellen/bezahlung?uid={ausweis.uid}" class="button text-sm">Bezahlen</a>
{/if}
{#if !ausweis.ausgestellt && !ausweis.bestellt}

View File

@@ -6,11 +6,11 @@
import DashboardNotification from "./DashboardNotification.svelte";
import { notifications } from "#components/NotificationProvider/shared.js";
import ThemeController from "#components/ThemeController.svelte";
import { BenutzerClient, ObjektClient } from "#components/Ausweis/types.js";
import { BenutzerClient, ObjektKomplettClient } from "#components/Ausweis/types.js";
export let lightTheme: boolean;
export let benutzer: BenutzerClient;
export let objekte: ObjektClient[];
export let objekte: ObjektKomplettClient[];
const rippleOptions: RippleOptions = {
center: false,
@@ -43,8 +43,10 @@
Gebäude
</a>
{#each objekte as objekt}
<a class="flex ml-12" href="/dashboard/aufnahme/{objekt.aufnahmen[0].uid}">{objekt.adresse}<br>{objekt.plz} {objekt.ort}</a>
<hr class="border-gray-600">
{#if objekt.aufnahmen.length > 0}
<a class="flex ml-12" href="/dashboard/aufnahme/{objekt.aufnahmen[0].uid}">{objekt.adresse}<br>{objekt.plz} {objekt.ort}</a>
<hr class="border-gray-600">
{/if}
{/each}
<!-- <button use:ripple={rippleOptions} class="button-tab">
<EnvelopeClosed width={22} height={22} />
@@ -94,7 +96,7 @@
<Bell size={24} />
</button>
</div>
<ul tabindex="0" class="dropdown-content mb-2 border border-base-300 z-10 menu py-4 px-0 bg-base-200 rounded-box w-80">
<ul class="dropdown-content mb-2 border border-base-300 z-10 menu py-4 px-0 bg-base-200 rounded-box w-80">
<NotificationProvider component={DashboardNotification} />
</ul>
</div>

View File

@@ -66,7 +66,7 @@
maxlength="5"
/>
<div data-test="plz-container" class="absolute top-[calc(100%+4px)] flex flex-col left-0 bg-white py-1 shadow-md rounded-lg z-10" class:hidden={hideZipDropdown}>
<div data-cy="plz-container" class="absolute top-[calc(100%+4px)] flex flex-col left-0 bg-white py-1 shadow-md rounded-lg z-10" class:hidden={hideZipDropdown}>
{#each zipCodes as zipCode}
<button class="hover:bg-gray-100 cursor-pointer px-2 py-1 text-nowrap" type="button" tabindex="-1" on:click={() => {
zip = zipCode.plz;

View File

@@ -19,86 +19,49 @@
const twoBoxReason = ["Vermietung/Verkauf", "Aushangpflicht", "Sonstiges"];
const gewerbeHouse = ["Gewerbegebäude", "Mischgebäude"];
$: {
$: ausnahme =
leerStand === "mehr als 30" ||
heizungsAlter === "< 3" ||
(baujahr === "vor 1978" && einheiten === "bis 4 Wohneinheiten" && sanierungsstatus === "unsaniert");
ausnahme = ((leerStand === "mehr als 30") || (heizungsAlter === "< 3") || (baujahr === "vor 1978" && einheiten === "bis 4 Wohneinheiten" && sanierungsstatus === "unsaniert"))
? true
: false;
$: isTwoBoxReason = twoBoxReason.includes(anlass);
oneBOX = ((ausnahme === true) && (gebaeudetyp !== "Gewerbegebäude") && (gebaeudetyp !== "Mischgebäude")) ||
(!twoBoxReason.includes(anlass) && (gebaeudetyp !== "Mischgebäude")) ||
((gebaeudetyp === "Gewerbegebäude") && (leerStand === "mehr als 30"))
? true
: false;
threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBoxReason.includes(anlass) && (leerStand != "mehr als 30")))
? true
: false;
}
$: isGewerbe = gewerbeHouse.includes(gebaeudetyp);
$: oneBOX =
(ausnahme && !isGewerbe) ||
(!isTwoBoxReason && gebaeudetyp !== "Mischgebäude") ||
(gebaeudetyp === "Gewerbegebäude" && leerStand === "mehr als 30");
$: threeBOX =
(ausnahme && gebaeudetyp === "Mischgebäude" && isTwoBoxReason && leerStand !== "mehr als 30");
function getBoxes(){
if(twoBoxReason.includes(anlass)){
document.getElementById('firstrow')?.classList.remove('sm:grid-cols-2');
document.getElementById('firstrow')?.classList.add('sm:grid-cols-3');
}else{
document.getElementById('firstrow')?.classList.remove('sm:grid-cols-3');
document.getElementById('firstrow')?.classList.add('sm:grid-cols-2');
}
}
function getCount(){
if(oneBOX===true){
console.log('ONE');
document.getElementById('thirdrow')?.classList.remove('md:grid-cols-6');
document.getElementById('thirdrow')?.classList.remove('md:grid-cols-4');
document.getElementById('thirdrow')?.classList.add('grid-cols-1');
}
else if(threeBOX===true){
console.log('THREE');
document.getElementById('thirdrow')?.classList.remove('grid-cols-1');
document.getElementById('thirdrow')?.classList.remove('md:grid-cols-4');
document.getElementById('thirdrow')?.classList.add('md:grid-cols-6');
}
else{
console.log('FOUR');
document.getElementById('thirdrow')?.classList.remove('grid-cols-1');
document.getElementById('thirdrow')?.classList.remove('md:grid-cols-6');
document.getElementById('thirdrow')?.classList.add('md:grid-cols-4');
}
//console.log(!twoBoxReason.includes(anlass)&& (gebaeudetyp != "Mischgebäude"));
}
</script>
<div id="IBC_app">
<div id="OEA_widget">
<input id="recode" type="hidden" value="widgetvorlage" />
<div id="OEA_input">
<div id="firstrow" class="firstrow">
<div id="firstrow" class="firstrow"
class:sm:grid-cols-3={isTwoBoxReason}
class:sm:grid-cols-2={!isTwoBoxReason}>
<div class="auswahl">
<div class="titel">Anlass</div>
<select
id="anlass"
class="selectfeld"
bind:value={anlass} on:change={getBoxes} on:change={getCount}
bind:value={anlass}>
>
<option selected disabled>bitte auswählen</option>
<option value="Vermietung/Verkauf"
>Vermietung/Verkauf</option
>
<option value="Vermietung/Verkauf">Vermietung/Verkauf</option>
<option value="Modernisierung">Modernisierung</option>
<option value="Neubau">Neubau</option>
<option value="Erweiterung">Erweiterung</option>
@@ -111,7 +74,7 @@ else{
<div class="titel">Gebäudetyp</div>
<select
class="selectfeld"
bind:value={gebaeudetyp} on:change={getBoxes} on:change={getCount}
bind:value={gebaeudetyp}>
>
<option selected disabled>bitte auswählen</option>
<option value="Einfamilienhaus">Einfamilienhaus</option>
@@ -122,12 +85,12 @@ else{
</select>
</div>
{#if twoBoxReason.includes(anlass)}
{#if isTwoBoxReason}
<div class="auswahl">
<div class="titel">Sanierungsstand</div>
<select
class="selectfeld"
bind:value={sanierungsstatus} on:change={getBoxes} on:change={getCount}
bind:value={sanierungsstatus}>
>
<option selected disabled>bitte auswählen</option>
@@ -139,14 +102,14 @@ else{
</div>
{#if twoBoxReason.includes(anlass)}
{#if isTwoBoxReason}
<div id="secondrow" class="secondrow">
<div class="auswahl">
<div class="titel">Baujahr</div>
<select
id="baujahr"
class="selectfeld"
bind:value={baujahr} on:change={getCount}
bind:value={baujahr}
>
<option selected disabled>bitte auswählen</option>
@@ -159,7 +122,7 @@ else{
<div class="titel">Heizungsalter</div>
<select
class="selectfeld"
bind:value={heizungsAlter} on:change={getCount}
bind:value={heizungsAlter}
>
<option selected disabled>bitte auswählen</option>
<option value="< 3">jünger als 3 Jahre</option>
@@ -171,7 +134,7 @@ else{
<div class="titel">Wohneinheiten</div>
<select
class="selectfeld"
bind:value={einheiten} on:change={getCount}
bind:value={einheiten}
>
<option selected disabled>bitte auswählen</option>
<option value="bis 4 Wohneinheiten"
@@ -187,7 +150,7 @@ else{
<div class="titel">Leerstand</div>
<select
class="selectfeld ausnahmen"
bind:value={leerStand} on:change={getCount}
bind:value={leerStand}
>
<option selected disabled>bitte auswählen</option>
<option value="bis 30">bis 30%</option>
@@ -197,17 +160,20 @@ else{
</div>
{/if}
<div id="thirdrow" class="thirdrow">
{#if twoBoxReason.includes(anlass) && (gebaeudetyp != "Gewerbegebäude") && (ausnahme === false)}
<div id="thirdrow" class="thirdrow"
class:grid-cols-1={oneBOX}
class:md:grid-cols-6={threeBOX}
class:md:grid-cols-4={!oneBOX && !threeBOX}
>
{#if isTwoBoxReason && (gebaeudetyp != "Gewerbegebäude") && (ausnahme === false)}
<div
class="produktbox"
transition:fade={{ duration: 0 }}
>
<WidgetCardTemplate
name="Verbrauchsausweis Wohngebäude"
price={PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/immowelt/wohngebaeude_immowelt.svg"
src="https://online-energieausweis.org/images/immowelt/wohngebaeude_immowelt.svg"
alt="Wohnhaus Verbrauchsausweis"
variant="einfach"
empfehlung="nein"
@@ -219,21 +185,18 @@ else{
["Ungenau durch individuelles Heizverhalten.", false],
["Wird nicht immer bei den Banken akzeptiert.", false]
]}
href_buy="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/"
href_overview="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/produkt-uebersicht/"
href_buy="https://online-energieausweis.org/immowelt/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/"
href_overview="https://online-energieausweis.org/immowelt/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/produkt-uebersicht/"
></WidgetCardTemplate>
</div>
{/if}
{#if twoBoxReason.includes(anlass) && (gebaeudetyp != "Gewerbegebäude")}
<div
class="produktbox"
transition:fade={{ duration: 0 }}
>
{#if isTwoBoxReason && (gebaeudetyp != "Gewerbegebäude")}
<WidgetCardTemplate
name="Bedarfsausweis Wohngebäude"
price={PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/immowelt/wohngebaeude_immowelt.svg"
src="https://online-energieausweis.org/images/immowelt/wohngebaeude_immowelt.svg"
alt="Wohnhaus Bedarfsausweis"
variant="fundiert"
empfehlung="ja"
@@ -245,21 +208,18 @@ else{
["Kann als Grundlage für den ISFP dienen.", true],
["Objektivere Berechnungsmethode nach DIN 18599.", true],
]}
href_buy="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/"
href_overview="/energieausweis-erstellen/bedarfsausweis-wohngebaeude/produkt-uebersicht/"
href_buy="https://online-energieausweis.org/immowelt/energieausweis-erstellen/bedarfsausweis-wohngebaeude/"
href_overview="https://online-energieausweis.org/immowelt/energieausweis-erstellen/bedarfsausweis-wohngebaeude/produkt-uebersicht"
></WidgetCardTemplate>
</div>
{/if}
{#if twoBoxReason.includes(anlass) && gewerbeHouse.includes(gebaeudetyp) && (leerStand != "mehr als 30")}
<div
class="produktbox"
transition:fade={{ duration: 0 }}
>
{#if isTwoBoxReason && isGewerbe && (leerStand != "mehr als 30")}
<WidgetCardTemplate
name="Verbrauchsausweis Gewerbegebäude"
price={PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/immowelt/gewerbegebaeude_immowelt.svg"
src="https://online-energieausweis.org/images/immowelt/gewerbegebaeude_immowelt.svg"
alt="Gewerbe Verbrauchsausweis"
variant="einfach"
empfehlung="nein"
@@ -272,22 +232,18 @@ else{
["Wird nicht immer bei den Banken akzeptiert.", false],
["Ungenau durch individuelles Heizverhalten", false],
]}
href_buy="/energieausweis-erstellen/verbrauchsausweis-gewerbe/"
href_overview="/energieausweis-erstellen/verbrauchsausweis-gewerbe/produkt-uebersicht/"
href_buy="https://online-energieausweis.org/immowelt/energieausweis-erstellen/verbrauchsausweis-gewerbe/"
href_overview="https://online-energieausweis.org/immowelt/energieausweis-erstellen/verbrauchsausweis-gewerbe/produkt-uebersicht/"
></WidgetCardTemplate>
</div>
{/if}
{#if twoBoxReason.includes(anlass) && gewerbeHouse.includes(gebaeudetyp)}
<div
class="produktbox"
transition:fade={{ duration: 0 }}
>
{#if isTwoBoxReason && isGewerbe}
<WidgetCardTemplate
name="Bedarfsausweis Gewerbegebäude"
price={PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/immowelt/gewerbegebaeude_immowelt.svg"
src="https://online-energieausweis.org/images/immowelt/gewerbegebaeude_immowelt.svg"
alt="Gewerbe Bedarfsausweis"
variant="fundiert"
empfehlung="ja"
@@ -300,22 +256,19 @@ else{
["Objektiveres, besser vergleichbares Ergebnis.", true],
["Zulässig bei Leerstand oder fehlenden Verbräuchen", true],
]}
href_buy="/energieausweis-erstellen/bedarfsausweis-gewerbe/"
href_overview="/energieausweis-erstellen/bedarfsausweis-gewerbe/produkt-uebersicht/"
href_buy="https://online-energieausweis.org/immowelt/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/"
href_overview="https://online-energieausweis.org/immowelt/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/produkt-uebersicht/"
></WidgetCardTemplate>
</div>
{/if}
{#if (anlass != "bitte auswählen") && !twoBoxReason.includes(anlass) && (gebaeudetyp != "Gewerbegebäude")}
<div
class="produktbox"
transition:fade={{ duration: 0 }}
>
{#if (anlass != "bitte auswählen") && !isTwoBoxReason && (gebaeudetyp != "Gewerbegebäude")}
<WidgetCardTemplate
name="GEG-Nachweis Wohngebäude"
price={PRICES.GEGNachweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/immowelt/wohngebaeude_immowelt.svg"
alt="Gewerbe Bedarfsausweis"
src="https://online-energieausweis.org/images/immowelt/wohngebaeude_immowelt.svg"
alt="GEG-Nachweis-Wohnen"
variant="Bauvorlage"
empfehlung="ja"
cta="Angebot anfragen"
@@ -327,24 +280,20 @@ else{
["Berechnung und Bilanzierung nach aktueller DIN 18599.", true],
["Zonierung und Erstellung eines 3D Gebäudemodells.", true],
]}
href_buy="/energieausweis-erstellen/bedarfsausweis-gewerbe/"
href_overview="/energieausweis-erstellen/bedarfsausweis-gewerbe/produkt-uebersicht/"
href_buy="https://online-energieausweis.org/immowelt/angebot-anfragen/geg-nachweis-wohnen-anfragen/"
href_overview="https://online-energieausweis.org/immowelt/angebot-anfragen/geg-nachweis-wohnen-anfragen/produkt-uebersicht/"
></WidgetCardTemplate>
</div>
{/if}
{#if (anlass != "bitte auswählen") && !twoBoxReason.includes(anlass) && gewerbeHouse.includes(gebaeudetyp)}
<div
class="produktbox"
transition:fade={{ duration: 0 }}
>
{#if (anlass != "bitte auswählen") && !isTwoBoxReason && isGewerbe}
<WidgetCardTemplate
name="GEG-Nachweis Gewerbegebäude"
price={PRICES.GEGNachweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/immowelt/gewerbegebaeude_immowelt.svg"
alt="Gewerbe Bedarfsausweis"
src="https://online-energieausweis.org/images/immowelt/gewerbegebaeude_immowelt.svg"
alt="GEG-Nachweis-Gewerbe"
variant="Bauvorlage"
empfehlung="ja"
cta="Angebot anfragen"
@@ -356,28 +305,23 @@ else{
["Berechnung und Bilanzierung nach aktueller DIN 18599.", true],
["Mehrzonenmodell inkl. Erstellung eines 3D Gebäudemodells.", true],
]}
href_buy="/energieausweis-erstellen/bedarfsausweis-gewerbe/"
href_overview="/energieausweis-erstellen/bedarfsausweis-gewerbe/produkt-uebersicht/"
href_buy="https://online-energieausweis.org/immowelt/angebot-anfragen/geg-nachweis-gewerbe-anfragen/"
href_overview="https://online-energieausweis.org/immowelt/angebot-anfragen/geg-nachweis-gewerbe-anfragen/produkt-uebersicht/"
></WidgetCardTemplate>
</div>
{/if}
</div>
</div>
</div>
<style lang="postcss">
@font-face {
font-family: 'Antique Olive Compact bold';
font-weight: 700;
font-style: normal;
font-display:swap;
src: url("/fonts/Antique Olive Std Compact.woff2") format('woff2');
}
#IBC_app {
@font-face {
@font-face {
font-family: "immo Sans";
src: url('/fonts/Immo-Sans/immoSans-Regular.eot');
src: url('/fonts/Immo-Sans/immoSans-Regular.eot?#iefix') format('embedded-opentype'),
@@ -395,14 +339,21 @@ else{
font-weight: 700;
}
@font-face {
font-family: 'Antique Olive Compact bold';
font-weight: 700;
font-style: normal;
font-display:swap;
src: url("/fonts/Antique Olive Std Compact.woff2") format('woff2');
}
*{font-family: "immo Sans";}
select option{font-family: "immo Sans",sans-serif;}
#OEA_widget {
@apply min-w-[320px] max-w-[1920px] p-[4px]
sm:p-[10px];
font-family: "immo Sans";
select option{
font-family: "immo Sans",sans-serif;}
.firstrow{@apply grid grid-cols-1 gap-x-4 gap-y-2
sm:grid-cols-2 sm:gap-x-4 sm:gap-y-2;
@@ -426,16 +377,10 @@ select option{font-family: "immo Sans",sans-serif;}
.thirdrow{@apply grid grid-cols-1 gap-x-4 gap-y-2 col-start-1
md:grid-cols-4 md:gap-x-4 md:gap-y-2;
.produktbox{@apply grid grid-cols-subgrid col-span-2 grid-rows-subgrid row-span-3 md:row-span-12 bg-black/5 rounded-lg
px-2 py-2 mt-5;
box-shadow:2px 2px 8px rgba(0,0,0,0.25)
}
}
}
</style>

View File

@@ -1,4 +1,5 @@
<script lang="ts">
import { fade } from "svelte/transition";
export let price: number;
export let name: string;
export let variant: string;
@@ -11,9 +12,13 @@
export let cta: string;
</script>
<div
class="produktbox"
transition:fade={{ duration: 0 }}
>
{#if empfehlung=="ja"}
<div class="empfehlung">Empfehlung</div>
{#if empfehlung === "ja"}
<div class="empfehlung" aria-label="Empfohlenes Produkt">Empfehlung</div>
{/if}
<h2 class="titel sm:mb-2">{name}</h2>
@@ -35,13 +40,19 @@
<div class="sumCent buttoncols">
<a
href="{href_buy}"
class="buttoncol">{cta}</a
>
href={href_buy}
class="buttoncol"
aria-label="Jetzt {name} kaufen"
target="_blank"
>{cta}
</a>
<a
href="{href_overview}"
class="buttoncol">Produkt-Übersicht</a
href={href_overview}
class="buttoncol"
aria-label="{name} Produkt-Übersicht"
target="_blank"
>Produkt-Übersicht</a
>
</div>
@@ -50,19 +61,21 @@
{#each services as [service, check]}
<div class="services">
<span>{@html service}</span>
<div class:check={check} class:check-no={!check}>{check ? "✔" : "✘"}</div>
<span>{@html service}</span>
<span class={check ? "check" : "check-no"}>{check ? "✔" : "✘"}</span>
</div>
{/each}
</div>
</div>
<style lang="postcss">
.produktbox{@apply grid grid-cols-subgrid col-span-2 grid-rows-subgrid row-span-3 md:row-span-12 bg-black/5 rounded-lg
px-2 py-2 mt-5;
box-shadow:2px 2px 8px rgba(0,0,0,0.25);
.sumCent{@apply justify-self-center col-span-2}
.sumCent{@apply justify-self-center col-span-2}
.sumRows{@apply hidden sm:grid grid-rows-subgrid row-span-5 items-center}
.forServices{@apply grid-rows-subgrid row-span-5 items-center col-span-2 justify-center px-6}
@@ -75,12 +88,9 @@ md:grid-cols-2 md:w-[auto]}
.buttoncol{@apply mt-2 md:mt-0 text-center text-black bg-[#ffcc00] rounded-md px-3 py-1 no-underline
hover:bg-[#222222] hover:text-white}
.price{@apply tracking-tighter text-[2rem] text-[#222222] pl-12 m-0 -mt-7 text-nowrap text-left;
font-family: "Antique Olive Compact bold";}
.titel {@apply col-span-2 text-center [font-size:_clamp(20px,2.5vw,28px)]}
.empfehlung{@apply -mt-4 absolute justify-self-end rounded-md bg-red-700 text-white w-fit h-fit px-2 py-1 rotate-1 text-[0.65rem] ring-4 ring-white mr-6}
.variante {
@@ -100,4 +110,6 @@ hover:bg-[#222222] hover:text-white}
@apply justify-self-end self-center font-bold text-red-700;
}
}
</style>

View File

@@ -1,6 +1,6 @@
import fuelList from "#components/Ausweis/brennstoffListe.js";
import { faker } from "@faker-js/faker";
import { type Enums } from "#lib/client/prisma";
import { Enums } from "#lib/client/prisma.js";
import "cypress-file-upload"
@@ -10,14 +10,14 @@ describe("Verbrauchsausweis erstellen Schritt 1", () => {
it("erstellt einen neuen Verbrauchsausweis Wohngebäude.", () => {
cy.visit("/energieausweis-erstellen/verbrauchsausweis-wohngebaeude");
cy.wait(1000);
cy.wait(2000);
// Wir überprüfen, ob alle Ausstelgründe vorhanden sind, diese sollten genau so viele sein wie in der Datenbank vorhanden sind.
cy.get("select[data-cy='ausstellgrund']")
.select(
faker.number.int({
min: 0,
max: (["Modernisierung", "Neubau", "Sonstiges", "Verkauf", "Vermietung"] as Enums.Ausstellgrund[]).length - 1,
min: 1,
max: Object.values(Enums.Ausstellgrund).length - 1,
})
)
@@ -60,6 +60,7 @@ describe("Verbrauchsausweis erstellen Schritt 1", () => {
);
// TODO: Ort - Dieser wird aus der Datenbank abgefragt, wir müssen also warten, bis der Dropdown da ist.
cy.get("[data-cy='plz-container']").find("button").first().click()
// Flaeche
cy.get("input[name='flaeche']")
@@ -103,8 +104,9 @@ describe("Verbrauchsausweis erstellen Schritt 1", () => {
}
// Verbrauchszeitraum
cy.get("select[name='energieverbrauch_zeitraum_monat']").select(availableDates[0].month.toString());
cy.get("select[name='energieverbrauch_zeitraum_jahr']").select(availableDates[0].year.toString());
cy.get("select[name='energieverbrauch_zeitraum_monat']").select(availableDates[0].month.toString());
// Verbrauch
cy.get("input[name='verbrauch_1']").type(faker.number.int({ min: 4000, max: 15000 }).toString(), { force: true });
@@ -235,58 +237,45 @@ describe("Verbrauchsausweis erstellen Schritt 1", () => {
cy.get("input[name='gebaeude_image']").should("have.attr", "type", "file").attachFile("images/gebaeude/1.jpeg", { subjectType: "input" });
// Jetzt können wir den Verbrauchsausweis erstellen.
cy.get("form[name='ausweis'] button[data-cy='weiter']").click({ force: true });
cy.get("form[data-cy='ausweis'] button[data-cy='weiter']").click({ force: true });
// Wir sind nicht eingeloggt also sollte jetzt ein Login Screen erscheinen.
// Wir klicken auf registrieren und erstellen einen neuen Benutzer, danach loggen wir uns mit diesem ein.
cy.get("[data-cy='registrieren']").click();
cy.url().should("contain", "/kundendaten");
const email = faker.internet.email();
const passwort = "test1234";
const vorname = faker.person.firstName();
const nachname = faker.person.lastName();
const telefon = faker.phone.number()
cy.get("form[name='signup'] input[name='email']").should("be.visible").should("have.attr", "type", "email").type(email);
cy.get("form[name='signup'] input[name='passwort']").should("be.visible").should("have.attr", "type", "password").type(passwort);
cy.get("form[name='signup'] input[name='vorname']").should("be.visible").should("have.attr", "type", "text").type(vorname);
cy.get("form[name='signup'] input[name='nachname']").should("be.visible").should("have.attr", "type", "text").type(nachname);
const strasse = faker.location.streetAddress({ useFullAddress: true })
const plz = faker.location.zipCode("#####")
cy.get("form[name='signup'] button[type='submit']").click();
cy.get("input[name='vorname']").should("have.attr", "type", "text").type(vorname);
cy.get("input[name='name']").should("have.attr", "type", "text").type(nachname);
cy.get("input[name='telefon']").should("have.attr", "type", "text").type(telefon);
// Rechnung
cy.get("input[name='rechnung_empfaenger']").should("have.attr", "type", "text").type(`${vorname} ${nachname}`);
cy.get("input[name='rechnung_strasse']").should("have.attr", "type", "text").type(strasse);
cy.get("input[name='rechnung_plz']").should("have.attr", "type", "text").type(plz);
cy.get("[data-cy='plz-container']").children().first().click()
cy.get("input[name='rechnung_email']").should("have.attr", "type", "email").type(email);
cy.get("[data-cy='paypal']").click()
cy.get("button[data-cy='bestellen']").click();
cy.get("a[data-cy='registrieren']").should("be.visible").click();
// Wir sind jetzt registriert und können uns nun einloggen.
// Die Email sollte automatisch eingetragen sein, da wir uns gerade registriert haben.
cy.get("form[name='login'] input[name='email']").should("be.visible").should("have.attr", "type", "email").should("contain.value", email);
cy.get("form[name='login'] input[name='passwort']").should("be.visible").should("have.attr", "type", "password").type(passwort);
cy.get("form[name='signup'] input[name='vorname']").should("be.visible").should("have.attr", "type", "text").type(vorname);
cy.get("form[name='signup'] input[name='nachname']").should("be.visible").should("have.attr", "type", "text").type(nachname);
cy.get("form[name='signup'] input[name='email']").should("be.visible").should("have.attr", "type", "email").should("contain.value", email);
cy.get("form[name='signup'] input[name='passwort']").should("be.visible").should("have.attr", "type", "password").type(passwort);
cy.get("form[name='signup'] button[type='submit']").click();
cy.get("form[name='login'] button[type='submit']").click();
// Der Ausweis sollte jetzt schon erstellt worden sein und wir sollten auf die kundendaten seite weitergeleitet worden sein.
cy.url().should("contain", "/kundendaten");
cy.wait(1000)
// Wir füllen jetzt die Kundendaten aus.
// cy.get("select[name='anrede']").select(Math.random() > 0.5 ? "Herr" : "Frau");
cy.get("input[name='vorname']").should("contain.value", vorname);
cy.get("input[name='name']").should("contain.value", nachname);
// cy.get("input[name='email']").should("contain.value", email);
// cy.get("input[name='telefon']").type(faker.phone.number());
cy.get("input[name='rechnung_empfaenger']").type(`${vorname} ${nachname}`);
cy.get("input[name='rechnung_strasse']").type(faker.location.streetAddress());
// TODO: Random Plz generieren, allerdings muss die auch in der Datenbank vorhanden sein...
cy.get("input[name='rechnung_plz']").type("2103");
// Jetzt sollte der PLZ Container erscheinen, dort klicken wir einfach das erste Element an.
cy.get("div[data-test='plz-container']").children().first().click();
// cy.get("input[name='rechnung_telefon']").type(faker.phone.number());
cy.get("input[name='rechnung_email']").should("contain.value", email);
cy.get("input[data-cy='paypal']").click();
// Datenschutz und AGB akzeptieren, dann schicken wir das Formular ab.
// cy.get("input[name='agb-akzeptieren']").check()
// cy.get("input[name='datenschutz-akzeptieren']").check()
cy.get("button[data-cy='bestellen']").click();
cy.origin('https://www.mollie.com', () => {
// Jetzt sind wir auf der Mollie Seite, dort wählen wir den "paid" status aus
cy.get("input[type='radio'][name='final_state'][value='paid']").check();

View File

@@ -26,6 +26,6 @@ describe('Benutzer Logout', () => {
it("meldet einen Nutzer ab und leitet auf die Login Seite weiter", () => {
cy.visit("/auth/logout")
cy.url().should("include", "/auth/login")
cy.url().should("include", "/")
})
})

View File

@@ -47,6 +47,8 @@ export const VerbrauchsausweisGewerbeSchema = z.object({
prueftext: z.string().describe("Durch den Kunden hinzugefügte Anmerkung zur Vorabprüfung").nullish(),
beschreibung: z.string().nullish(),
kontrolldatei_angefragt: z.boolean().describe("Ob bei der Anfrage der Registriernummer eine Kontrolldatei angefragt wurde").nullish(),
created_at: z.date(),
updated_at: z.date(),
rechnung_id: z.number().int().nullish(),
aufnahme_id: z.number().int().describe("ID der korrespondierenden Gebäudeaufnahme"),
})

View File

@@ -34,6 +34,8 @@ export const VerbrauchsausweisWohnenSchema = z.object({
prueftext: z.string().describe("Durch den Kunden hinzugefügte Anmerkung zur Vorabprüfung").nullish(),
beschreibung: z.string().nullish(),
kontrolldatei_angefragt: z.boolean().describe("Ob bei der Anfrage der Registriernummer eine Kontrolldatei angefragt wurde").nullish(),
created_at: z.date(),
updated_at: z.date(),
rechnung_id: z.number().int().nullish(),
aufnahme_id: z.number().int().describe("ID der korrespondierenden Gebäudeaufnahme"),
})

View File

@@ -1,6 +1,6 @@
import { decodeToken } from "#lib/auth/token.js";
import { hashPassword } from "#lib/password.js";
import { prisma } from "#lib/server/prisma";
import { prisma } from "#lib/server/prisma.js";
import { APIError, TypesafeAPIContextWithRequest } from "astro-typesafe-api/server";
import { z } from "zod";

View File

@@ -13,7 +13,7 @@ import { PERSISTENT_DIR } from "#lib/server/constants.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, benutzer: BenutzerClient, bilder: UploadedGebaeudeBild[]) {
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("./templates/Leerseite_Datenblatt.pdf", import.meta.url), "base64");
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("../../../public/pdf/templates/Leerseite_Datenblatt.pdf", import.meta.url), "base64");
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const page3 = copyPage(pdf.getPages()[0]);
pdf.addPage(page3);

View File

@@ -11,7 +11,7 @@ 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 VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("../../../public/pdf/templates/GEG24_Nichtwohngebaeude.pdf", import.meta.url), "base64");
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const pages = pdf.getPages()
@@ -184,7 +184,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
// Stempel und Unterschrift
if (ausweis.ausgestellt) {
const stempel = await pdf.embedPng(fs.readFileSync(new URL("./images/stempel-unterschrift.png", import.meta.url), "base64"));
const stempel = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/stempel-unterschrift.png", import.meta.url), "base64"));
const stempelHeight = 60
pages[0].drawImage(stempel, {
@@ -197,7 +197,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
// Aussteller
const aussteller = await pdf.embedPng(fs.readFileSync(new URL("./images/aussteller.png", import.meta.url), "base64"));
const aussteller = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/aussteller.png", import.meta.url), "base64"));
pages[0].drawImage(aussteller, {
x: 40,
y: height - 750,

View File

@@ -0,0 +1,48 @@
import { transport } from "#lib/mail.js";
import {
BedarfsausweisGewerbe,
Benutzer,
GEGNachweisGewerbe,
GEGNachweisWohnen,
} from "#lib/client/prisma.js";
export async function sendGEGAnforderungsMail(
nachweis: GEGNachweisWohnen | GEGNachweisGewerbe | BedarfsausweisGewerbe,
user: Benutzer,
) {
await transport.sendMail({
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `GEG Nachweis angefordert beim IBCornelsen (ID: ${nachweis.id})`,
cc: {
address: user.email || "",
name: user.name || "",
},
bcc: "info@online-energieausweis.org",
html: `<p>Sehr geehrte/r ${user.vorname} ${user.name},
<br>
<br>
Sie haben einen GEG Nachweis bei uns angefordert.</p>
<p>
Mit freundlichen Grüßen,
<br>
Dipl.-Ing. Jens Cornelsen
<br>
<br>
<strong>IB Cornelsen</strong>
<br>
Katendeich 5A
<br>
21035 Hamburg
<br>
www.online-energieausweis.org
<br>
<br>
fon 040 · 209339850
<br>
fax 040 · 209339859
</p>`,
});
}

View File

@@ -2,7 +2,7 @@ import { transport } from "#lib/mail.js";
import {
Benutzer,
GEGNachweisWohnen,
} from "#lib/client/prisma";
} from "#lib/client/prisma.js";
export async function sendGEGBestellungsMail(
nachweis: GEGNachweisWohnen,

View File

@@ -11,12 +11,14 @@
async function sendPasswordMail(e: SubmitEvent) {
e.preventDefault()
try {
const response = await api.auth["forgot-password"].GET.fetch({
sent = true
const response = await api.auth["passwort-vergessen"].GET.fetch({
email
})
showEmailSuccess = true;
} catch (e) {
sent = false;
addNotification({
message: "Ups...",
subtext: "Da ist wohl etwas schiefgelaufen... Bitte versuchen sie es erneut, falls das Problem weiterhin bestehen sollte melden sie sich bei unserem Support damit wir ihnen helfen können.",
@@ -28,6 +30,7 @@
}
let showEmailSuccess = false;
let sent = false;
</script>
<div class="mx-auto w-1/3 bg-base-200 p-8 border border-base-300 rounded-lg">
@@ -48,7 +51,7 @@
<span class="font-semibold">Falls sie ein Konto bei uns haben wurde eine Email an sie verschickt.</span>
</div>
{/if}
<button type="submit" class="button"
<button type="submit" class="button" disabled={sent}
>Email zum Zurücksetzen des Passworts senden.</button
>
{#if showEmailSuccess}

View File

@@ -14,7 +14,7 @@
e.preventDefault()
try {
disabled = true
await api.auth["forgot-password"].POST.fetch({
await api.auth["passwort-vergessen"].POST.fetch({
passwort,
token
})

View File

@@ -64,13 +64,13 @@
<div class="my-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
{#each aufnahme.verbrauchsausweise_wohnen as ausweis}
<DashboardAusweis {ausweis} {aufnahme} {objekt}></DashboardAusweis>
<DashboardAusweis {ausweis} {aufnahme} {objekt} rechnung={ausweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.bedarfsausweise_wohnen as ausweis}
<DashboardAusweis {ausweis} {aufnahme} {objekt}></DashboardAusweis>
<DashboardAusweis {ausweis} {aufnahme} {objekt} rechnung={ausweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.verbrauchsausweise_gewerbe as ausweis}
<DashboardAusweis {ausweis} {aufnahme} {objekt}></DashboardAusweis>
<DashboardAusweis {ausweis} {aufnahme} {objekt} rechnung={ausweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.geg_nachweise_wohnen as nachweis}
<DashboardNachweis {nachweis} {aufnahme} {objekt}></DashboardNachweis>

View File

@@ -14,6 +14,7 @@
BenutzerClient,
BildClient,
ObjektClient,
RechnungClient,
UnterlageClient,
VerbrauchsausweisWohnenClient,
} from "#components/Ausweis/types.js";
@@ -38,6 +39,7 @@
export let objekt: ObjektClient;
export let bilder: BildClient[];
export let unterlagen: UnterlageClient[];
export let rechnung: RechnungClient | null = null;
export let ausweisart: Enums.Ausweisart;
export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal;
export let ausweistyp: Enums.AusweisTyp = Enums.AusweisTyp.Standard;
@@ -289,14 +291,12 @@
}
try {
const { uid, checkout_url } = await api.rechnung.PUT.fetch(
{
ausweisart,
let uid: string, checkout_url: string | undefined;
if (rechnung) {
const result = await api.rechnung._uid.PATCH.fetch({
bezahlmethode: aktiveBezahlmethode,
services: services
.filter((service) => service.selected)
.map((service) => service.id),
email: $email,
abweichende_versand_adresse: $abweichende_versand_adresse,
empfaenger: $empfaenger,
strasse: $strasse,
plz: $plz,
@@ -306,15 +306,52 @@
versand_plz: $versand_plz,
versand_ort: $versand_ort,
telefon: $telefon,
ausweis_uid: ausweis.uid,
ausweistyp,
},
{
versand_zusatzzeile: $versand_zusatzzeile
}, {
params: {
uid: rechnung.uid
},
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
}
);
})
console.log(result);
uid = result.uid
checkout_url = result.checkout_url
} else {
const result = await api.rechnung.PUT.fetch(
{
ausweisart,
bezahlmethode: aktiveBezahlmethode,
services: services
.filter((service) => service.selected)
.map((service) => service.id),
email: $email,
empfaenger: $empfaenger,
strasse: $strasse,
plz: $plz,
ort: $ort,
versand_empfaenger: $versand_empfaenger,
versand_strasse: $versand_strasse,
versand_plz: $versand_plz,
versand_ort: $versand_ort,
telefon: $telefon,
ausweis_uid: ausweis.uid,
ausweistyp,
},
{
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
}
);
uid = result.uid;
checkout_url = result.checkout_url;
}
// Alle alten Ausweisdateien im localStorage löschen.
localStorage.clear();

View File

@@ -1,9 +1,7 @@
<script lang="ts">
import PerformanceScore from "#components/Ausweis/PerformanceScore.svelte";
import Progressbar from "#components/Ausweis/Progressbar.svelte";
import { PRICES } from "#lib/constants.js";
import ButtonSpaeterHilfe from "#components/Ausweis/ButtonSpaeterHilfe.svelte";
import ButtonWeiterHilfe from "#components/Ausweis/ButtonWeiterHilfe.svelte";
import Ausweisart from "#components/Ausweis/Ausweisart.svelte";
import Warmwasseranteil from "#components/Ausweis/Warmwasseranteil.svelte";
@@ -52,73 +50,37 @@
const ausweisart = Enums.Ausweisart.VerbrauchsausweisGewerbe
const anliegen = "Energieausweis erstellen";
if (Object.keys(ausweis).length === 0) {
const localStorageAusweis = localStorage.getItem("ausweis");
if (!ausweis.updated_at || moment(localStorage.getItem("verbrauchsausweis-gewerbe.updated_at") || new Date()).isAfter(ausweis.updated_at)) {
const localStorageAusweis = localStorage.getItem("verbrauchsausweis-gewerbe.ausweis");
if (localStorageAusweis) {
ausweis = JSON.parse(localStorageAusweis)
}
}
if (Object.keys(aufnahme).length === 0) {
const localStorageAufnahme = localStorage.getItem("aufnahme");
const localStorageAufnahme = localStorage.getItem("verbrauchsausweis-gewerbe.aufnahme");
if (localStorageAufnahme) {
aufnahme = JSON.parse(localStorageAufnahme)
}
}
if (Object.keys(objekt).length === 0) {
const localStorageObjekt = localStorage.getItem("objekt");
const localStorageObjekt = localStorage.getItem("verbrauchsausweis-gewerbe.objekt");
if (localStorageObjekt) {
objekt = JSON.parse(localStorageObjekt)
}
}
if (Object.keys(bilder).length === 0) {
const localStorageBilder = localStorage.getItem("bilder");
const localStorageBilder = localStorage.getItem("verbrauchsausweis-gewerbe.bilder");
if (localStorageBilder) {
bilder = JSON.parse(localStorageBilder)
}
}
function automatischAusfüllen() {
aufnahme.baujahr_gebaeude = [1952];
aufnahme.baujahr_heizung = [1952];
aufnahme.saniert = true;
aufnahme.einheiten = 1;
aufnahme.gebaeudetyp = "Polizeidienstgebäude";
aufnahme.keller =
Enums.Heizungsstatus.NICHT_VORHANDEN;
aufnahme.dachgeschoss =
Enums.Heizungsstatus.NICHT_VORHANDEN;
aufnahme.lueftung = "Fensterlueftung";
aufnahme.kuehlung = "1";
ausweis.ausstellgrund = "Vermietung";
ausweis.verbrauch_1 = 15000;
ausweis.verbrauch_2 = 14000;
ausweis.verbrauch_3 = 16000;
aufnahme.flaeche = 152;
aufnahme.nutzflaeche = 172;
ausweis.keller_beheizt = true;
aufnahme.brennstoff_1 = "Erdgas H";
ausweis.einheit_1 = "kWh";
ausweis.anteil_warmwasser_1 = 18;
ausweis.startdatum = moment("01.01.2021").toDate();
objekt.plz = "21039";
objekt.ort = "Hamburg";
objekt.adresse = "Curslacker Deich 170";
aufnahme.gebaeudeteil = "Gesamtgebäude";
objekt = objekt;
ausweis = ausweis;
}
let waitOverlayHidden = true;
let speichernOverlayHidden = true;
$: {
localStorage.setItem("ausweis", JSON.stringify(ausweis))
localStorage.setItem("aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("objekt", JSON.stringify(objekt))
localStorage.setItem("bilder", JSON.stringify(bilder))
localStorage.setItem("verbrauchsausweis-gewerbe.ausweis", JSON.stringify(ausweis))
localStorage.setItem("verbrauchsausweis-gewerbe.aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("verbrauchsausweis-gewerbe.objekt", JSON.stringify(objekt))
localStorage.setItem("verbrauchsausweis-gewerbe.bilder", JSON.stringify(bilder))
localStorage.setItem("verbrauchsausweis-gewerbe.updated_at", moment().toString())
}
let form: HTMLFormElement;

View File

@@ -1,7 +1,6 @@
<script lang="ts">
import PerformanceScore from "#components/Ausweis/PerformanceScore.svelte";
import Progressbar from "#components/Ausweis/Progressbar.svelte";
import { PRICES } from "#lib/constants.js";
import Bereich from "#components/labels/Bereich.svelte";
@@ -11,7 +10,6 @@
import Warmwasseranteil from "#components/Ausweis/Warmwasseranteil.svelte";
import Verbrauch from "#components/Ausweis/Verbrauch.svelte";
import moment from "moment";
import LueftungundLeerstand from "#components/Ausweis/LueftungundLeerstand.svelte";
import SanierungszustandHeizungsanlage from "#components/Ausweis/SanierungszustandHeizungsanlage.svelte";
@@ -50,85 +48,48 @@
AufnahmeClient,
} from "#components/Ausweis/types.js";
import { Enums } from "#lib/client/prisma.js";
import moment from "moment";
// TODO: Vom Server sollte ein volles Objekt kommen, dass alle Subobjekte enthält, weil es sonst zu Problemen führen kann
// wenn aufnahme oder objekt nicht existiert...
export let ausweis: VerbrauchsausweisWohnenClient;
export let objekt: ObjektClient
export let aufnahme: AufnahmeClient
export let user: BenutzerClient = {} as BenutzerClient;
export let bilder: UploadedGebaeudeBild[] = []
export let ausweistyp: Enums.AusweisTyp;
if (Object.keys(ausweis).length === 0) {
const localStorageAusweis = localStorage.getItem("ausweis");
export let user: BenutzerClient;
export let bilder: UploadedGebaeudeBild[];
export let ausweistyp: Enums.AusweisTyp;
if (moment(localStorage.getItem("verbrauchsausweis-wohnen.updated_at") || new Date()).isAfter(ausweis.updated_at)) {
const localStorageAusweis = localStorage.getItem("verbrauchsausweis-wohnen.ausweis");
if (localStorageAusweis) {
ausweis = JSON.parse(localStorageAusweis)
}
}
if (Object.keys(aufnahme).length === 0) {
const localStorageAufnahme = localStorage.getItem("aufnahme");
const localStorageAufnahme = localStorage.getItem("verbrauchsausweis-wohnen.aufnahme");
if (localStorageAufnahme) {
aufnahme = JSON.parse(localStorageAufnahme)
}
}
if (Object.keys(objekt).length === 0) {
const localStorageObjekt = localStorage.getItem("objekt");
const localStorageObjekt = localStorage.getItem("verbrauchsausweis-wohnen.objekt");
if (localStorageObjekt) {
objekt = JSON.parse(localStorageObjekt)
}
}
if (Object.keys(bilder).length === 0) {
const localStorageBilder = localStorage.getItem("bilder");
const localStorageBilder = localStorage.getItem("verbrauchsausweis-wohnen.bilder");
if (localStorageBilder) {
bilder = JSON.parse(localStorageBilder)
}
}
function automatischAusfüllen() {
aufnahme.baujahr_gebaeude = [1962];
aufnahme.baujahr_heizung = [1952];
aufnahme.saniert = true;
aufnahme.einheiten = 1;
aufnahme.gebaeudetyp = "Einfamilienhaus";
aufnahme.keller =
Enums.Heizungsstatus.NICHT_VORHANDEN;
aufnahme.dachgeschoss =
Enums.Heizungsstatus.NICHT_VORHANDEN;
aufnahme.lueftung = "Fensterlueftung";
aufnahme.kuehlung = "1";
ausweis.ausstellgrund = "Vermietung";
ausweis.verbrauch_1 = 15000;
ausweis.verbrauch_2 = 14000;
ausweis.verbrauch_3 = 16000;
aufnahme.flaeche = 152;
aufnahme.nutzflaeche = 172;
ausweis.keller_beheizt = true;
aufnahme.brennstoff_1 = "Erdgas H";
ausweis.einheit_1 = "kWh";
ausweis.anteil_warmwasser_1 = 18;
ausweis.startdatum = moment("01.01.2021").toDate();
objekt.plz = "21039";
objekt.ort = "Hamburg";
objekt.adresse = "Curslacker Deich 170";
aufnahme.gebaeudeteil = "Gesamtgebäude";
objekt = objekt;
ausweis = ausweis;
}
let waitOverlayHidden = true;
let speichernOverlayHidden = true;
$: {
localStorage.setItem("ausweis", JSON.stringify(ausweis))
localStorage.setItem("aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("objekt", JSON.stringify(objekt))
localStorage.setItem("bilder", JSON.stringify(bilder))
localStorage.setItem("verbrauchsausweis-wohnen.ausweis", JSON.stringify(ausweis))
localStorage.setItem("verbrauchsausweis-wohnen.aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("verbrauchsausweis-wohnen.objekt", JSON.stringify(objekt))
localStorage.setItem("verbrauchsausweis-wohnen.bilder", JSON.stringify(bilder))
localStorage.setItem("verbrauchsausweis-wohnen.updated_at", moment().toString())
}
$: {
@@ -182,7 +143,7 @@ let skala: HTMLDivElement;
<form id="formInput-1" data-test="ausweis" bind:this={form}>
<form id="formInput-1" data-cy="ausweis" bind:this={form}>
<div id="formular-box" class="formular-boxen ring-0">
<ButtonWeiterHilfe

View File

@@ -1,7 +1,7 @@
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";
import * as nodemailer from "nodemailer"
import { prisma } from "#lib/server/prisma";
import { prisma } from "#lib/server/prisma.js";
import { decodeToken, encodeToken } from "#lib/auth/token.js";
import { TokenType } from "#lib/auth/types.js";
import { hashPassword } from "#lib/password.js";

View File

@@ -0,0 +1,150 @@
import { UUidWithPrefix, getAusweisartFromUUID } from "#components/Ausweis/types.js"
import { Enums } from "#lib/client/prisma.js"
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js"
import { mollieClient } from "#lib/mollie.js"
import { prisma } from "#lib/server/prisma.js"
import { PaymentMethod } from "@mollie/api-client"
import { defineApiRoute, APIError } from "astro-typesafe-api/server"
import { RechnungSchema } from "src/generated/zod/rechnung.js"
import { z } from "zod"
export const PATCH = defineApiRoute({
input: RechnungSchema.pick({
bezahlmethode: true,
ort: true,
plz: true,
strasse: true,
telefon: true,
empfaenger: true,
versand_empfaenger: true,
versand_ort: true,
versand_plz: true,
versand_strasse: true,
versand_zusatzzeile: true,
abweichende_versand_adresse: true
}),
output: z.object({
checkout_url: z.string().optional(),
uid: UUidWithPrefix,
}),
middleware: authorizationMiddleware,
headers: authorizationHeaders,
async fetch(input, context, user) {
// Wir holen uns die Rechnung
const rechnung = await prisma.rechnung.findUnique({
where: {
uid: context.params.uid,
benutzer: {
id: user.id
}
},
include: {
bedarfsausweis_gewerbe: true,
bedarfsausweis_wohnen: true,
geg_nachweis_gewerbe: true,
geg_nachweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
verbrauchsausweis_wohnen: true
}
})
if (!rechnung) {
throw new APIError({
code: "NOT_FOUND",
message: "Rechnung konnte nicht gefunden werden oder gehört einem anderen Benutzer."
})
}
await prisma.rechnung.update({
where: {
id: rechnung.id
},
data: {
bezahlmethode: input.bezahlmethode,
ort: input.ort,
plz: input.plz,
strasse: input.strasse,
telefon: input.telefon,
empfaenger: input.empfaenger,
versand_empfaenger: input.versand_empfaenger,
versand_ort: input.versand_ort,
versand_plz: input.versand_plz,
versand_strasse: input.versand_strasse,
versand_zusatzzeile: input.versand_zusatzzeile,
abweichende_versand_adresse: input.abweichende_versand_adresse,
}
})
if (input.bezahlmethode === Enums.Bezahlmethoden.rechnung) {
return { uid: rechnung.uid }
}
const ausweis = rechnung.verbrauchsausweis_gewerbe || rechnung.verbrauchsausweis_wohnen || rechnung.bedarfsausweis_gewerbe || rechnung.bedarfsausweis_wohnen || rechnung.geg_nachweis_gewerbe || rechnung.geg_nachweis_wohnen;
if (!ausweis) {
throw new APIError({
code: "NOT_FOUND",
message: "Rechnung hat keinen verknüpften Ausweis"
})
}
const ausweisart = getAusweisartFromUUID(ausweis.uid)
if (!ausweisart) {
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Ausweis ist ungültig."
})
}
const description = getPaymentDescription(ausweisart);
// Wir erstellen eine Mollie Payment Referenz.
const payment = await mollieClient.payments.create({
amount: {
value: rechnung.betrag.toFixed(2),
currency: "EUR",
},
metadata: {
rechnung_uid: rechnung.uid,
},
method: input.bezahlmethode as PaymentMethod,
description,
redirectUrl: `https://ibcornelsen.de/payment/success?a=${ausweis.uid}&r=${rechnung.uid}`,
webhookUrl: `http://ibcornelsen.de/api/webhooks/mollie?uid=${rechnung.uid}`,
});
const checkoutUrl = payment.getCheckoutUrl();
if (!checkoutUrl) {
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Checkout URL konnte nicht erstellt werden.",
});
}
return {
uid: rechnung.uid,
checkout_url: checkoutUrl,
};
},
})
function getPaymentDescription(ausweisart: Enums.Ausweisart) {
switch(ausweisart) {
case "BedarfsausweisWohnen":
return "Bedarfsausweis Wohngebäude"
case "BedarfsausweisGewerbe":
return "Bedarfsausweis Gewerbegebäude"
case "VerbrauchsausweisGewerbe":
return "Verbrauchsausweis Gewerbegebäude"
case "VerbrauchsausweisWohnen":
return "Verbrauchsausweis Wohngebäude"
case "GEGNachweisBedarfsausweis":
case "GEGNachweisGewerbe":
case "GEGNachweisWohnen":
return "GEG Nachweis"
default:
return ""
}
}

View File

@@ -1,8 +1,10 @@
import { getAusweisartFromUUID, UUidWithPrefix } from "#components/Ausweis/types.js";
import { omit } from "#lib/helpers.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { Enums, GEGEinpreisungSchema, prisma } from "#lib/server/prisma";
import { sendGEGAnforderungsMail } from "#lib/server/mail/geg-anfordern.js";
import { Enums, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { GEGEinpreisungSchema } from "src/generated/zod/gegeinpreisung.js";
import { z } from "zod";
export const PUT = defineApiRoute({
@@ -51,13 +53,15 @@ export const PUT = defineApiRoute({
}
}
})
} else {
await sendGEGAnforderungsMail(nachweis, user)
} else {
throw new APIError({
"code": "BAD_REQUEST",
"message": `Ausweisart wird nicht unterstützt: ${ausweisart}`
})
}
return {

View File

@@ -7,7 +7,7 @@ import {
authorizationHeaders,
authorizationMiddleware,
} from "#lib/middleware/authorization.js";
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { getAusweisartFromUUID, UUidWithPrefix } from "#components/Ausweis/types.js";
import { getPrismaAusweisAdapter } from "#lib/server/ausweis.js";
import { PRICES, SERVICES } from "#lib/constants.js";
import { Rechnung } from "#lib/client/prisma.js";
@@ -162,7 +162,7 @@ export const PUT = defineApiRoute({
// Wir erstellen eine Mollie Payment Referenz.
const payment = await mollieClient.payments.create({
amount: {
value: "45.00",
value: betrag.toFixed(2),
currency: "EUR",
},
metadata: {
@@ -189,3 +189,5 @@ export const PUT = defineApiRoute({
};
},
});

View File

@@ -12,7 +12,11 @@ export const PATCH = defineApiRoute({
id: true,
benutzer_id: true,
aufnahme_id: true,
}),
updated_at: true,
created_at: true
}).merge(z.object({
startdatum: z.coerce.date()
})),
output: z.void(),
headers: {
"Authorization": z.string()

View File

@@ -17,7 +17,10 @@ export const PUT = defineApiRoute({
id: true,
benutzer_id: true,
uid: true,
aufnahme_id: true
aufnahme_id: true,
rechnung_id: true,
updated_at: true,
created_at: true
}).merge(z.object({
startdatum: z.coerce.date()
})),
@@ -110,12 +113,7 @@ export const GET = defineApiRoute({
benutzer: true,
aufnahme: {
include: {
objekt: {
include: {
bilder: true,
},
},
rechnungen: true,
bilder: true,
events: {
include: {
benutzer: {

View File

@@ -11,7 +11,10 @@ export const PATCH = defineApiRoute({
uid: true,
id: true,
benutzer_id: true,
aufnahme_id: true
aufnahme_id: true,
rechnung_id: true,
created_at: true,
updated_at: true
}).merge(z.object({
startdatum: z.coerce.date()
})),

View File

@@ -1,7 +1,8 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma, VerbrauchsausweisWohnenSchema } from "#lib/server/prisma";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { VerbrauchsausweisWohnenSchema } from "src/generated/zod/verbrauchsausweiswohnen.js";
import { z } from "zod";
export const PATCH = defineApiRoute({
@@ -22,7 +23,10 @@ export const PUT = defineApiRoute({
id: true,
benutzer_id: true,
uid: true,
aufnahme_id: true
aufnahme_id: true,
rechnung_id: true,
created_at: true,
updated_at: true
}),
uid_aufnahme: UUidWithPrefix
}),
@@ -113,12 +117,7 @@ export const GET = defineApiRoute({
benutzer: true,
aufnahme: {
include: {
objekt: {
include: {
bilder: true,
},
},
rechnungen: true,
bilder: true,
events: {
include: {
benutzer: {

View File

@@ -37,12 +37,36 @@ const aufnahme = await prisma.aufnahme.findUnique({
objekt: true,
bilder: true,
unterlagen: true,
bedarfsausweise_wohnen: true,
verbrauchsausweise_gewerbe: true,
verbrauchsausweise_wohnen: true,
bedarfsausweise_gewerbe: true,
geg_nachweise_gewerbe: true,
geg_nachweise_wohnen: true,
bedarfsausweise_wohnen: {
include: {
rechnung: true
}
},
verbrauchsausweise_gewerbe: {
include: {
rechnung: true
}
},
verbrauchsausweise_wohnen: {
include: {
rechnung: true
}
},
bedarfsausweise_gewerbe: {
include: {
rechnung: true
}
},
geg_nachweise_gewerbe: {
include: {
rechnung: true
}
},
geg_nachweise_wohnen: {
include: {
rechnung: true
}
},
events: true
}
})

View File

@@ -0,0 +1,52 @@
---
import { getAusweisartFromUUID } from "#components/Ausweis/types";
import AusweisLayoutPruefung from "#layouts/AusweisLayoutPruefung.astro";
import { getPrismaAusweisAdapter } from "#lib/server/ausweis";
import { Enums } from "#lib/server/prisma";
import { getCurrentUser } from "#lib/server/user";
import KundendatenModule from "#modules/KundendatenModule.svelte";
import { PaymentStatus } from "@mollie/api-client";
import { AusweisTyp } from "src/generated/enums";
const uid = Astro.url.searchParams.get("uid")
if (!uid) {
return Astro.redirect("/404")
}
const user = await getCurrentUser(Astro)
const adapter = getPrismaAusweisAdapter(uid)
const ausweisart = getAusweisartFromUUID(uid)
if (!user || !adapter || !ausweisart) {
return Astro.redirect("/404")
}
const ausweis = await adapter.findUnique({
where: {
uid,
benutzer_id: user.id
},
include: {
aufnahme: {
include: {
objekt: true,
bilder: true
}
},
rechnung: true
}
})
if (!ausweis) {
return Astro.redirect("/404")
}
if (ausweis.rechnung.status === PaymentStatus.paid) {
return Astro.redirect("/dashboard")
}
---
<AusweisLayoutPruefung title="Energieausweis Bezahlung">
<KundendatenModule {user} {ausweis} objekt={ausweis.aufnahme.objekt} rechnung={ausweis.rechnung} aufnahme={ausweis.aufnahme} bilder={ausweis.aufnahme.bilder} {ausweisart} ausweistyp={AusweisTyp.Standard} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} client:only></KundendatenModule>
</AusweisLayoutPruefung>

View File

@@ -9,6 +9,7 @@ import { getCurrentUser } from "#lib/server/user";
const user = await getCurrentUser(Astro) || {}
// POST Body
const params = new URLSearchParams(await Astro.request.text());
if (!params.has("ausweis") || !params.has("aufnahme") || !params.has("objekt") || !params.has("bilder") || !params.has("ausweisart")) {

View File

@@ -2,28 +2,28 @@
@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;1,400&display=swap');*/
@font-face {
font-family: 'Heron';
font-family: "Heron";
font-weight: 400;
font-style: normal;
font-display:swap;
src: url("/fonts/HeronSans-Light.woff2") format('woff2');
}
font-display: swap;
src: url("/fonts/HeronSans-Light.woff2") format("woff2");
}
@font-face {
font-family: 'Heron';
font-family: "Heron";
font-weight: 700;
font-style: normal;
font-display:swap;
src: url("/fonts/HeronSans-Regular.woff2") format('woff2');
}
font-display: swap;
src: url("/fonts/HeronSans-Regular.woff2") format("woff2");
}
@font-face {
font-family: 'Antique Olive Compact bold';
@font-face {
font-family: "Antique Olive Compact bold";
font-weight: 700;
font-style: normal;
font-display:swap;
src: url("/fonts/Antique Olive Std Compact.woff2") format('woff2');
}
font-display: swap;
src: url("/fonts/Antique Olive Std Compact.woff2") format("woff2");
}
* {
font-weight: 400;
@@ -31,48 +31,72 @@
font-family: "Heron";
}
.promo{
font-weight: 700;
box-sizing: border-box;
font-family: "Antique Olive Compact bold";
color:#222222;
.promo {
font-weight: 700;
box-sizing: border-box;
font-family: "Antique Olive Compact bold";
color: #222222;
}
body{
@apply bg-[#efefef] min-w-[320px]
body {
@apply bg-[#efefef] min-w-[320px];
}
main{
main {
@apply bg-[url('/images/pattern.png')] bg-repeat bg-fixed max-w-[1920px] mx-auto border-gray-200 border-[1px] min-w-[320px];
}
.button {
@apply w-full sm:w-min h-[38px] px-4 py-2 bg-secondary ring-2 ring-secondary/25 rounded-none xs:rounded-md text-white text-nowrap
hover:bg-gradient-to-br from-secondary to-secondary-grad hover:shadow-lg transition-all hover:no-underline hover:ring-2 hover:ring-primary
@apply w-full sm:w-min h-[38px] px-4 py-2 bg-secondary ring-2 ring-secondary/25 rounded-none xs:rounded-md text-white text-nowrap transition-all;
}
input, select, textarea{
.button:not([disabled]):hover {
@apply bg-gradient-to-br from-secondary to-secondary-grad shadow-lg no-underline ring-2 ring-primary;
}
.button[disabled] {
@apply bg-gray-400;
}
.button[disabled]:hover {
@apply bg-gray-400;
}
input,
select,
textarea {
@apply py-1.5 px-2.5 w-full outline-none;
}
input[type="text"],
input[type="email"],
input[type="number"],
input[type="password"],
input[type="email"],
input[type="number"],
input[type="password"],
input[type="file"],
textarea,
select{
@apply p-1 min-h-[38px] ring-1 ring-black/15 rounded-sm;}
select {
@apply p-1 min-h-[38px] ring-1 ring-black/15 rounded-sm;
}
select option{font-family: "Heron", sans-serif !important;}
select, select option:disabled{@apply bg-white}
select option {
font-family: "Heron", sans-serif !important;
}
select,
select option:disabled {
@apply bg-white;
}
input[type="file"]{@apply pt-[4px]}
input[type="file"] {
@apply pt-[4px];
}
input[type="checkbox"],input[type="radio"]{@apply inline-block accent-secondary h-[13px]}
input[type="checkbox"],
input[type="radio"] {
@apply inline-block accent-secondary h-[13px];
}
input:disabled, input:read-only {
input:disabled,
input:read-only {
@apply lg:bg-gray-200 border-gray-500/15;
}
@@ -81,125 +105,177 @@ input:disabled, input:read-only {
article {
@apply w-full relative bg-white p-0 z-0 box rounded-tl-none sm:p-2 lg:p-12;
hr {@apply mb-4 mt-4 border-primary;}
hr {
@apply mb-4 mt-4 border-primary;
}
h1 {@apply pl-2 font-normal mb-2
h1 {
@apply pl-2 font-normal mb-2
[font-size:_clamp(24px,1.5vw,36px)] leading-7
sm:text-4xl;}
h2 {@apply pl-2 font-normal mb-2
sm:text-4xl;
}
h2 {
@apply pl-2 font-normal mb-2
[font-size:_clamp(24px,1.5vw,36px)] leading-7
sm:text-2xl;}
h3 {@apply pl-2 sm:pl-0 text-xl font-normal ml-1 mb-1;}
a {@apply text-blue-700 font-medium inline;}
sm:text-2xl;
}
h3 {
@apply pl-2 sm:pl-0 text-xl font-normal ml-1 mb-1;
}
p {@apply text-lg font-normal pl-2 pr-2 mb-4;}
li {@apply text-lg font-normal }
ul {@apply list-disc list-inside mb-4}
a {
@apply text-blue-700 font-medium inline;
}
p {
@apply text-lg font-normal pl-2 pr-2 mb-4;
}
li {
@apply text-lg font-normal;
}
ul {
@apply list-disc list-inside mb-4;
}
/*span {@apply text-secondary font-bold;}*/
}
/*SIDEBARS*/
/*BOXES*/
.box{
@apply rounded-lg
.box {
@apply rounded-lg
lg:shadow-box lg:ring-1 lg:ring-gray-300
xl:rounded-xl
xl:rounded-xl;
}
.card:not(:last-child){@apply mb-5}
.card{@apply bg-white px-6 py-4;
h2 {@apply w-full [font-size:_clamp(8px,1.25vw,16px)] font-bold text-box-heading leading-6 pb-1 mb-4 border-b-[1px] border-primary/35}
hr {@apply my-0}
p {@apply text-lg}
a {@apply text-lg}
.card:not(:last-child) {
@apply mb-5;
}
.card {
@apply bg-white px-6 py-4;
h2 {
@apply w-full [font-size:_clamp(8px,1.25vw,16px)] font-bold text-box-heading leading-6 pb-1 mb-4 border-b-[1px] border-primary/35;
}
hr {
@apply my-0;
}
p {
@apply text-lg;
}
a {
@apply text-lg;
}
}
/*SIDEBAR-LEFT*/
/*NAVIGATION*/
.nav-element{@apply relative block cursor-pointer}
.nav-element:not(:first-child){@apply border-gray-200 border-t-[1px]}
.no-dropdown, .no-dropdown:hover{@apply text-black no-underline}
.nav-element:hover > .nav-element-child{
@apply !bg-primary !text-white cursor-pointer
.nav-element {
@apply relative block cursor-pointer;
}
.nav-element:hover > .nav-element-child .no-dropdown{
@apply !bg-primary !text-white cursor-pointer
.nav-element:not(:first-child) {
@apply border-gray-200 border-t-[1px];
}
.nav-element:hover > .dropdown-content{
@apply lg:visible lg:opacity-100 lg:block lg:ml-[calc(100%+2px)]
.no-dropdown,
.no-dropdown:hover {
@apply text-black no-underline;
}
.nav-element:hover:first-child > .nav-element-child{
@apply !rounded-none
lg:!rounded-tl-xl lg:!rounded-tr-none
.nav-element:hover > .nav-element-child {
@apply !bg-primary !text-white cursor-pointer;
}
.nav-element:hover:last-child > .nav-element-child{
@apply !rounded-none
xl:!rounded-b-xl
.nav-element:hover > .nav-element-child .no-dropdown {
@apply !bg-primary !text-white cursor-pointer;
}
.nav-element-child{
@apply px-4 py-2 w-full justify-start text-sm bg-white flex !no-underline text-black
xl:text-lg
.nav-element:hover > .dropdown-content {
@apply lg:visible lg:opacity-100 lg:block lg:ml-[calc(100%+2px)];
}
.nav-element:hover:first-child > .nav-element-child {
@apply !rounded-none
lg:!rounded-tl-xl lg:!rounded-tr-none;
}
.dropdown-content{
@apply !relative z-[1] !p-0 !scale-100 hidden
.nav-element:hover:last-child > .nav-element-child {
@apply !rounded-none
xl:!rounded-b-xl;
}
.nav-element-child {
@apply px-4 py-2 w-full justify-start text-sm bg-white flex !no-underline text-black
xl:text-lg;
}
.dropdown-content {
@apply !relative z-[1] !p-0 !scale-100 hidden
lg:!absolute lg:min-w-max lg:p-2 lg:shadow-lg lg:!top-0 lg:ring-gray-300 lg:ring-1;
li {@apply text-sm bg-white flex
xl:text-lg}
li a {@apply w-full text-sm px-4 py-2 rounded-none no-underline hover:text-white hover:bg-gradient-to-br from-secondary to-secondary-grad
li {
@apply text-sm bg-white flex
xl:text-lg;
}
li a {
@apply w-full text-sm px-4 py-2 rounded-none no-underline hover:text-white hover:bg-gradient-to-br from-secondary to-secondary-grad
lg:px-4 bg-[#efefef] text-black lg:hover:bg-secondary
xl:text-lg}
xl:text-lg;
}
li:not(:first-child) {@apply !border-gray-200 !border-t-[1px]}
li:not(:first-child) {
@apply !border-gray-200 !border-t-[1px];
}
}
.verbrauchsausweis li:nth-child(6), .bedarfsausweis li:nth-child(6){
@apply !border-primary !border-t-[1px]
.verbrauchsausweis li:nth-child(6),
.bedarfsausweis li:nth-child(6) {
@apply !border-primary !border-t-[1px];
}
#hamburger{
#hamburger {
@apply my-1;
.burger {@apply w-6}
span {@apply block h-[4px] bg-white !transition-all}
span:nth-child(2) {@apply my-[3px]}
.burger {
@apply w-6;
}
span {
@apply block h-[4px] bg-white !transition-all;
}
span:nth-child(2) {
@apply my-[3px];
}
}
.hamburger-swing-0{@apply origin-left rotate-45 -translate-y-[1.5px] !transition-all duration-500}
.hamburger-swing-1{@apply origin-center opacity-0 !transition-all}
.hamburger-swing-2{@apply origin-left -rotate-45 translate-y-[1.5px] !transition-all duration-500}
.show-dropdown-content{@apply block !visible !opacity-100 lg:!invisible}
.dd-symbol{ @apply absolute right-[20px] rotate-0 transition-all duration-300 origin-center md:transition-none}
.dd-symbol-clone{ @apply absolute right-[20px] lg:text-primary}
.rotate-symbol{@apply rotate-[90deg] transition-all duration-300 origin-center lg:rotate-0 md:transition-none}
.hamburger-swing-0 {
@apply origin-left rotate-45 -translate-y-[1.5px] !transition-all duration-500;
}
.hamburger-swing-1 {
@apply origin-center opacity-0 !transition-all;
}
.hamburger-swing-2 {
@apply origin-left -rotate-45 translate-y-[1.5px] !transition-all duration-500;
}
.show-dropdown-content {
@apply block !visible !opacity-100 lg:!invisible;
}
.dd-symbol {
@apply absolute right-[20px] rotate-0 transition-all duration-300 origin-center md:transition-none;
}
.dd-symbol-clone {
@apply absolute right-[20px] lg:text-primary;
}
.rotate-symbol {
@apply rotate-[90deg] transition-all duration-300 origin-center lg:rotate-0 md:transition-none;
}
/*NAVIGATION-ANIMATION*/
/*SIDEBAR-RIGHT*/
/*FOOTER*/
/*FOOTER*/

View File

@@ -665,6 +665,7 @@ export function fakeVerbrauchsausweisGewerbe() {
anteil_warmwasser_2: undefined,
prueftext: undefined,
beschreibung: undefined,
updated_at: faker.date.anytime(),
};
}
export function fakeVerbrauchsausweisGewerbeComplete() {
@@ -714,6 +715,8 @@ export function fakeVerbrauchsausweisGewerbeComplete() {
prueftext: undefined,
beschreibung: undefined,
kontrolldatei_angefragt: false,
created_at: new Date(),
updated_at: faker.date.anytime(),
rechnung_id: undefined,
aufnahme_id: faker.number.int(),
};
@@ -744,6 +747,7 @@ export function fakeVerbrauchsausweisWohnen() {
anteil_warmwasser_2: undefined,
prueftext: undefined,
beschreibung: undefined,
updated_at: faker.date.anytime(),
};
}
export function fakeVerbrauchsausweisWohnenComplete() {
@@ -780,6 +784,8 @@ export function fakeVerbrauchsausweisWohnenComplete() {
prueftext: undefined,
beschreibung: undefined,
kontrolldatei_angefragt: false,
created_at: new Date(),
updated_at: faker.date.anytime(),
rechnung_id: undefined,
aufnahme_id: faker.number.int(),
};