Merge pull request #430 from IBCornelsen/main

get main
This commit is contained in:
Jens Cornelsen
2025-03-09 21:37:55 +01:00
committed by GitHub
74 changed files with 848 additions and 317 deletions

View File

@@ -206,6 +206,7 @@ Table benutzer {
rolle BenutzerRolle [not null, default: 'USER']
firma String
lex_office_id String
verified Boolean [not null, default: false]
BedarfsausweisWohnen BedarfsausweisWohnen [not null]
documenttemplates documenttemplates [not null]
objekte Objekt [not null]
@@ -452,6 +453,7 @@ Table VerbrauchsausweisGewerbe {
alternative_lueftung Boolean
alternative_kuehlung Boolean
warmwasser_enthalten Boolean
warmwasser_anteil_bekannt Boolean [note: '@zod.describe("Falls der Warmwasser Anteil am Verbrauch bekannt ist, sollte dieser Wert auf true stehen")']
anteil_warmwasser_1 Float
anteil_warmwasser_2 Float
ausgestellt Boolean [default: false]

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();
-- AlterTable
ALTER TABLE "benutzer" ADD COLUMN "verified" BOOLEAN NOT NULL DEFAULT false,
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" ADD COLUMN "warmwasser_anteil_bekannt" BOOLEAN,
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

@@ -21,6 +21,8 @@ model Benutzer {
firma String?
lex_office_id String?
verified Boolean @default(false)
Anteilshaber Anteilshaber[] @ignore
BedarfsausweisWohnen BedarfsausweisWohnen[]
documenttemplates documenttemplates[]

View File

@@ -42,6 +42,8 @@ model VerbrauchsausweisGewerbe {
alternative_kuehlung Boolean?
warmwasser_enthalten Boolean?
/// @zod.describe("Falls der Warmwasser Anteil am Verbrauch bekannt ist, sollte dieser Wert auf true stehen")
warmwasser_anteil_bekannt Boolean?
anteil_warmwasser_1 Float?
anteil_warmwasser_2 Float?

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 KiB

View File

@@ -0,0 +1,3 @@
<svg width="165" height="225" viewBox="0 0 165 225" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M123.532 0H40.5V140H0L85.5 225L164.5 140H123.532V0Z" fill="#908580"/>
</svg>

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

0
src/assets/awd.png Normal file
View File

View File

@@ -15,7 +15,11 @@ export async function ausweisSpeichern(
) {
if (objekt.uid) {
await api.objekt._uid.PATCH.fetch({
...exclude(objekt, ["uid"])
adresse: objekt.adresse,
latitude: 0,
longitude: 0,
ort: objekt.ort,
plz: objekt.plz
}, {
params: {
uid: objekt.uid
@@ -26,7 +30,11 @@ export async function ausweisSpeichern(
})
} else {
const { uid } = await api.objekt.PUT.fetch({
...exclude(objekt, ["uid"])
adresse: objekt.adresse,
latitude: 0,
longitude: 0,
ort: objekt.ort,
plz: objekt.plz
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
@@ -50,8 +58,64 @@ export async function ausweisSpeichern(
}
})
} else {
console.log(aufnahme);
const { uid } = await api.aufnahme.PUT.fetch({
aufnahme,
aufnahme: {
baujahr_gebaeude: aufnahme.baujahr_gebaeude,
baujahr_heizung: aufnahme.baujahr_heizung,
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,
baujahr_klima: aufnahme.baujahr_klima,
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,
erstellungsdatum: aufnahme.erstellungsdatum,
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
},
uid_objekt: objekt.uid
}, {
headers: {

View File

@@ -1,3 +1,4 @@
import Sqids from "sqids";
import { writable, Writable } from "svelte/store";
import { ZodEffects, ZodNullable, ZodOptional, ZodType } from "zod";
@@ -57,4 +58,9 @@ export function getZodBaseType(schema: ZodType<any>): ZodType<any> {
return getZodBaseType(schema._def.schema)
}
return schema;
}
}
export const sqids = new Sqids({
alphabet: "0123456789abcdefghijklmnopqrstuvw",
minLength: 8
})

View File

@@ -4,7 +4,7 @@ import { exclude } from "#lib/exclude.js";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { AufnahmeClient, BedarfsausweisWohnenClient, BildClient, ObjektClient, UnterlageClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient, } from "#components/Ausweis/types.js";
import { Enums } from "#lib/client/prisma";
import { Enums } from "#lib/client/prisma.js";
export async function nachweisSpeichern(
nachweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient,

View File

@@ -2,8 +2,6 @@
import HelpLabel from "#components/labels/HelpLabel.svelte";
import Inputlabel from "#components/labels/InputLabel.svelte";
//import Label from "#components/Label.svelte";
import { auditHeizungGebaeudeBaujahr } from "../Verbrauchsausweis/audits/HeizungGebaeudeBaujahr.js";
import { addNotification, deleteNotification } from "#components/Notifications/shared.js";
import TagInput from "../TagInput.svelte";
@@ -48,7 +46,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
data-cy="ausstellgrund"
>
<option disabled selected value>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
{#each Object.entries(Enums.Ausstellgrund) as [name, ausstellgrund]}
<option value={ausstellgrund}>{name}</option>
{/each}
@@ -224,7 +222,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
bind:value={aufnahme.saniert}
>
<option disabled selected value>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
<option value={true}>saniert</option>
<option value={false}>unsaniert</option>
</select>

View File

@@ -62,7 +62,7 @@
async function spaeterWeitermachen() {
loginAction = spaeterWeitermachen;
if (!await validateAccessTokenClient()) {
if (!(await validateAccessTokenClient())) {
loginOverlayHidden = false;
return
}
@@ -120,18 +120,16 @@ sm:grid-cols-[1fr_min-content_min-content_min-content] sm:justify-self-end">
{#if showWeiter}
<div>
<Overlay bind:hidden={loginOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm py-8">
<EmbeddedAuthFlowModule onLogin={loginAction} email={""}></EmbeddedAuthFlowModule>
</div>
</Overlay>
<button on:click={ausweisAbschicken} type="button" class="button" data-cy="weiter">Weiter</button>
</div>
{/if}
</div>
<Overlay bind:hidden={loginOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm py-8">
<EmbeddedAuthFlowModule onLogin={loginAction} email={""}></EmbeddedAuthFlowModule>
</div>
</Overlay>
{#if showHelp}
<div class="w-full col-start-1 row-start-2 sm:row-start-2 col-span-4 mt-4">
<div

View File

@@ -121,7 +121,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
bind:value={aufnahme.dachgeschoss}
required
>
<option disabled selected value>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
<option value={Enums.Heizungsstatus.NICHT_VORHANDEN}
>nicht vorhanden</option
>
@@ -150,7 +150,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
bind:value={aufnahme.keller}
>
<option disabled selected value>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
<option value={Enums.Heizungsstatus.NICHT_VORHANDEN}
>nicht vorhanden</option
>

View File

@@ -2,8 +2,8 @@
import HelpLabel from "#components/labels/HelpLabel.svelte";
import Inputlabel from "#components/labels/InputLabel.svelte";
import { Enums } from "#lib/client/prisma.js";
import { Enums } from "@ibcornelsen/database/client";
export let ausweis;

View File

@@ -75,7 +75,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
bind:value={aufnahme.lueftung}
>
<option disabled selected value>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
<option value="Fensterlueftung">Fensterlüftung</option>
<option value="Schachtlueftung">Schachtlüftung</option>
<option value="LueftungsanlageOhneWaermerueckgewinnung"

View File

@@ -653,9 +653,8 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<input
name="stromverbrauch_enthaelt_sonstige"
type="number"
type="text"
bind:value={ausweis.stromverbrauch_enthaelt_sonstige}
required
/>
<div class="help-label">

View File

@@ -1,8 +1,9 @@
<script lang="ts">
import HelpLabel from "#components/labels/HelpLabel.svelte";
import Inputlabel from "#components/labels/InputLabel.svelte";
import { VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./types.js";
export let ausweis;
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient;
$: {
if (!ausweis.warmwasser_enthalten) {

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { AufnahmeKomplettClient, getAusweisartFromUUID, ObjektKomplettClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeKomplettClient, BedarfsausweisWohnenClient, getAusweisartFromUUID, ObjektKomplettClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import moment from "moment";
import { dialogs } from "svelte-dialogs";
import {
@@ -13,12 +13,13 @@
import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { Enums, Objekt } from "#lib/client/prisma";
import { Enums, Objekt } from "#lib/client/prisma.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
export let ausweis: VerbrauchsausweisWohnenClient;
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let aufnahme: AufnahmeKomplettClient;
export let objekt: Objekt;
export let progress: number;
const progress = ausweis.ausgestellt ? 100 : ausweis.bestellt ? 66 : 33;
const ausweisart = getAusweisartFromUUID(ausweis.uid);
@@ -38,14 +39,25 @@
});
if (result === true) {
await api["verbrauchsausweis-wohnen"]._uid.DELETE.fetch(undefined, {
params: {
uid: ausweis.uid,
},
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
});
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
await api["verbrauchsausweis-wohnen"]._uid.DELETE.fetch(undefined, {
params: {
uid: ausweis.uid,
},
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
});
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
await api["verbrauchsausweis-gewerbe"]._uid.DELETE.fetch(undefined, {
params: {
uid: ausweis.uid,
},
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
});
}
ausweis.storniert
ausweis = ausweis;
@@ -65,9 +77,18 @@
}
let hilfeModal: HTMLDialogElement;
let calculations = null;
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
calculations = endEnergieVerbrauchVerbrauchsausweis_2016(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt);
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
calculations = endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt);
}
</script>
<div class="card lg:card-side relative bg-base-200 card-bordered border-base-300">
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4">
{#if ausweis.storniert}
<div
class="absolute top-0 left-0 w-full h-full bg-[rgba(0,0,0,0.7)] z-[5] rounded-lg select-none"
@@ -79,14 +100,6 @@
</h1>
</div>
{/if}
<!-- <figure class="lg:w-1/2">
<img
src={(bilder.length > 0 && `/bilder/${bilder[0].uid}.webp`) ||
"/images/placeholder.jpg"}
class="object-cover w-full h-full"
alt="Gebäudebild"
/>
</figure> -->
<div class="card-body">
<div
class="flex justify-end mb-2 dropdown dropdown-bottom absolute top-4 right-4"
@@ -113,35 +126,38 @@
</li>
</ul>
</div>
<div class="flex flex-row flex-wrap gap-2">
<div class="flex flex-row flex-wrap items-center gap-2">
{#if ausweisart == Enums.Ausweisart.VerbrauchsausweisWohnen}
<div class="badge badge-accent font-semibold text-secondary text-lg">
<div class="text-lg font-semibold">
Verbrauchsausweis Wohnen
</div>
{:else if ausweisart == Enums.Ausweisart.BedarfsausweisWohnen}
<div class="badge badge-accent font-semibold">
<div class="text-lg font-semibold">
Bedarfsausweis Wohnen
</div>
{:else if ausweisart == Enums.Ausweisart.VerbrauchsausweisGewerbe}
<div class="badge badge-accent font-semibold">
<div class="text-lg font-semibold">
Verbrauchsausweis Gewerbe
</div>
{/if}
{#if ausweis.ausgestellt}
<div class="badge badge-success font-semibold">Ausgestellt</div>
<span class="bg-green-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Ausgestellt</span>
{:else if ausweis.bestellt}
<span class="bg-yellow-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Bestellt</span>
{/if}
</div>
<div class="badge badge-accent font-semibold text-black text-m">{objekt.adresse}</div>
<div class="mb-4 flex flex-row items-center gap-4">
<progress class="progress w-full" value={progress} max="100"
></progress>
<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>
{#await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt) then calculations}
{#await calculations then calculations}
<div class="flex flex-col gap-2">
<div class="flex flex-row justify-between">
<span>Energieverbrauch</span>
@@ -183,22 +199,35 @@
<div class="flex flex-row justify-between">
<span>ID</span>
<span class="font-bold text-base-content"
>{ausweis.uid.split("-")[0]}</span
>{ausweis.uid}</span
>
</div>
</div>
{/await}
<div class="flex flex-row justify-end gap-4 mt-4">
<a
{#if !ausweis.storniert && !ausweis.ausgestellt}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid={ausweis.uid}"
>Stornieren</a>
{/if}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid={ausweis.uid}"
>Freigeben</a>
{#if !ausweis.ausgestellt && !ausweis.bestellt}
<!-- TODO -->
{#if ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid={ausweis.uid}"
>Bearbeiten</a>
{:else if ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-gewerbe?uid={ausweis.uid}"
>Bearbeiten</a>
{/if}
{/if}
<a
class="p-2 rounded-lg hover:bg-gray-200"

View File

@@ -0,0 +1,111 @@
<script lang="ts">
import { AufnahmeKomplettClient, GEGNachweisWohnenClient, getAusweisartFromUUID } from "#components/Ausweis/types.js";
import {
CrossCircled,
DotsVertical,
Pencil2,
QuestionMarkCircled,
} from "radix-svelte-icons";
import { Enums, Objekt } from "#lib/client/prisma.js";
export let nachweis: GEGNachweisWohnenClient;
export let aufnahme: AufnahmeKomplettClient;
export let objekt: Objekt;
const ausweisart = getAusweisartFromUUID(nachweis.uid);
let hilfeModal: HTMLDialogElement;
</script>
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4">
{#if nachweis.storniert}
<div
class="absolute top-0 left-0 w-full h-full bg-[rgba(0,0,0,0.7)] z-[5] rounded-lg select-none"
>
<h1
class="absolute -rotate-[25deg] text-5xl md:text-7xl tracking-wide uppercase text-red-500 border-4 border-red-500 rounded-lg top-[50%] translate-y-[-50%] left-[50%] translate-x-[-50%]"
>
Storniert
</h1>
</div>
{/if}
<div class="card-body">
<div
class="flex justify-end mb-2 dropdown dropdown-bottom absolute top-4 right-4"
>
<button class="rounded-full p-2.5 hover:bg-base-100">
<DotsVertical size={15} />
</button>
<ul
tabindex="-1"
class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-64 gap-2"
>
<li>
<button><Pencil2 size={15} /> Als Vorlage benutzen</button>
</li>
<li>
<button on:click={() => hilfeModal.showModal()}
><QuestionMarkCircled size={15} /> Hilfe Erhalten</button
>
</li>
</ul>
</div>
<div class="flex flex-row flex-wrap items-center gap-2">
{#if ausweisart == Enums.Ausweisart.GEGNachweisWohnen}
<div class="text-lg font-semibold">
GEG Nachweis Wohnen
</div>
{:else if ausweisart == Enums.Ausweisart.GEGNachweisGewerbe}
<div class="text-lg font-semibold">
GEG Nachweis Gewerbe
</div>
{:else if ausweisart == Enums.Ausweisart.GEGNachweisBedarfsausweis}
<div class="text-lg font-semibold">
Bedarfsausweis Gewerbe
</div>
{/if}
</div>
<div class="badge badge-accent font-semibold text-black text-m">{objekt.adresse}</div>
<div class="flex flex-row justify-end gap-4 mt-4">
</div>
</div>
</div>
<dialog bind:this={hilfeModal} class="modal">
<div class="modal-box">
<h3 class="font-bold text-xl mb-4">Hilfe Anfordern</h3>
<p>
Brauchen sie Hilfe bei der Erstellung oder Bearbeitung ihres
Ausweises?
</p>
<p>
In unserem <a href="/helpdesk">Helpdesk</a> finden sie antworten auf
häufig gestellte Fragen.
</p>
<p>
Falls sie dort nicht finden wonach sie suchen, rufen sie uns doch
unter <a href="tel:040-209-339-850">040 209 339 850</a> an oder
<a href="mailto:info@online-energieausweis.com">schreiben sie uns eine email</a
>.
</p>
<p>
Wenn wir telefonisch nicht erreichbar sind, können sie uns auch
direkt hier eine Nachricht hinterlassen.
</p>
<form class="my-4">
<textarea
class="textarea textarea-bordered"
placeholder="Ihre Nachricht..."
cols="10"
rows="5"
></textarea>
<button class="btn btn-primary">Nachricht Abschicken</button>
</form>
<div class="modal-action">
<form method="dialog">
<button class="btn">Schließen</button>
</form>
</div>
</div>
</dialog>

View File

@@ -13,6 +13,8 @@
{#if bild}
<img src="/bilder/{bild.uid}.jpg" class="w-full max-h-72 object-cover rounded-t-lg" alt="Gebäude">
{:else}
<img src="/placeholder.png" class="w-full max-h-72 object-cover rounded-t-lg" alt="Gebäude">
{/if}
{/if}
@@ -30,10 +32,10 @@
<a href="/dashboard/aufnahme/{aufnahme.uid}" class="rounded-lg p-2 hover:bg-gray-100 transition-all"><OpenInNewWindow size={20}></OpenInNewWindow></a>
</div>
<div class="flex flex-row gap-2">
{#if aufnahme.verbrauchsausweise_wohnen}
{#if aufnahme.verbrauchsausweise_wohnen.length > 0}
<a href="/dashboard/aufnahme/{aufnahme.uid}" class="rounded-lg p-2 hover:bg-gray-100 transition-all"><File size={20}></File></a>
{/if}
{#if aufnahme.verbrauchsausweis_gewerbe}
{#if aufnahme.verbrauchsausweise_gewerbe.length > 0}
<a href="/dashboard/aufnahme/{aufnahme.uid}" class="rounded-lg p-2 hover:bg-gray-100 transition-all"><File size={20}></File></a>
{/if}
</div>

View File

@@ -6,10 +6,11 @@
import DashboardNotification from "./DashboardNotification.svelte";
import { notifications } from "#components/NotificationProvider/shared.js";
import ThemeController from "#components/ThemeController.svelte";
import { BenutzerClient } from "#components/Ausweis/types.js";
import { BenutzerClient, ObjektClient } from "#components/Ausweis/types.js";
export let lightTheme: boolean;
export let benutzer: BenutzerClient;
export let objekte: ObjektClient[];
const rippleOptions: RippleOptions = {
center: false,
@@ -41,15 +42,10 @@
<Reader width={22} height={22} />
Gebäude
</a>
<div class="flex ml-12">Katendeich 5AAA<br>44145 Dortmund</div>
<hr class="border-gray-600">
<div class="flex ml-12">Birkenalee<br>33175 Bad Lippspringe</div>
<hr class="border-gray-600">
<div class="flex ml-12">Birkenalee<br>33175 Bad Lippspringe</div>
<hr class="border-gray-600">
<div class="flex ml-12">Katendeich 5AAA<br>44145 Dortmund</div>
<hr class="border-gray-600">
<div class="flex ml-12">Katendeich 5AAA<br>44145 Dortmund</div>
{#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">
{/each}
<!-- <button use:ripple={rippleOptions} class="button-tab">
<EnvelopeClosed width={22} height={22} />
Kontakt

View File

@@ -1,8 +1,11 @@
<script lang="ts">
import UploadImages from "./UploadImages.svelte";
import type { Enums } from "#lib/client/prisma";
import { BedarfsausweisWohnenClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
import type { Enums } from "#lib/client/prisma.js";
import { BedarfsausweisWohnenClient, BildClient, ObjektClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
import { RotateCounterClockwise, Trash, Upload } from "radix-svelte-icons";
import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
export let images: BildClient[] = [];
export let max: number = Infinity;
@@ -12,24 +15,16 @@
export let objekt: ObjektClient;
export let kategorie: Enums.BilderKategorie
async function rotateImage(image: UploadedGebaeudeBild): Promise<UploadedGebaeudeBild> {
return new Promise((resolve, reject) => {
let img = new Image();
img.src = image.data ? image.data : `/bilder/${image.uid}.jpg`;
img.onload = () => {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = img.height;
canvas.height = img.width;
ctx?.translate(img.height / 2, img.width / 2);
ctx?.rotate((-90 * Math.PI) / 180);
ctx?.drawImage(img, -img.width / 2, -img.height / 2);
const clone = Object.assign({}, image)
clone.data = canvas.toDataURL("image/jpeg");
clone.update = true;
resolve(clone)
};
async function deleteImage(image: BildClient) {
await api.bild.DELETE.fetch({
uid: image.uid
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
images = images.filter((x) => x.uid !== image.uid);
}
let upload: () => void;
@@ -51,13 +46,12 @@
type="button"
class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
on:click={() => {
delete images[i];
images = images.filter((x) => x);
deleteImage(images[i])
}}
>
<Trash size={20} color="#fff"></Trash>
</button>
<button
<!-- <button
type="button"
class="rounded-full w-[30px] h-[30px] flex items-center justify-center p-0 bg-[rgba(0,0,0,0.4)]"
on:click={async () => {
@@ -67,7 +61,7 @@
}}
>
<RotateCounterClockwise size={20} color="#fff"></RotateCounterClockwise>
</button>
</button> -->
</div>
</div>
{/if}

View File

@@ -1,6 +1,6 @@
import { AufnahmeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
export function auditBedarfsausweisBenoetigt(ausweis: VerbrauchsausweisWohnenClient, gebaeude: AufnahmeClient): boolean {
export function auditBedarfsausweisBenoetigt(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient, gebaeude: AufnahmeClient): boolean {
if (ausweis.ausstellgrund == "Neubau" || ausweis.ausstellgrund == "Modernisierung") {
return true;
}

View File

@@ -1,9 +1,9 @@
import { ObjektClient, VerbrauchsausweisWohnenClient, AufnahmeClient } from "#components/Ausweis/types.js";
import { ObjektClient, VerbrauchsausweisWohnenClient, AufnahmeClient, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types.js";
import { AuditType, hidden } from "./hidden.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import { getKlimafaktoren } from "#lib/Klimafaktoren.js";
export async function auditEndEnergie(ausweis: VerbrauchsausweisWohnenClient, objekt: ObjektClient, aufnahme: AufnahmeClient): Promise<boolean> {
export async function auditEndEnergie(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient, objekt: ObjektClient, aufnahme: AufnahmeClient): Promise<boolean> {
if (hidden.has(AuditType.END_ENERGIE)) {
return false;
}

View File

@@ -1,12 +1,13 @@
import {
ObjektClient,
VerbrauchsausweisGewerbeClient,
VerbrauchsausweisWohnenClient,
} from "#components/Ausweis/types.js";
import { AuditType, hidden } from "./hidden.js";
import { getKlimafaktoren } from "#lib/Klimafaktoren.js";
export async function auditKlimaFaktoren(
ausweis: VerbrauchsausweisWohnenClient,
ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient,
gebaeude: ObjektClient
): Promise<boolean> {
if (hidden.has(AuditType.KLIMA_FAKTOREN)) {

View File

@@ -1,7 +1,7 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AuditType, hidden } from "./hidden.js";
export function auditWarmWasser(ausweis: VerbrauchsausweisWohnenClient): boolean {
export function auditWarmWasser(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient): boolean {
if (ausweis.warmwasser_anteil_bekannt && ausweis.warmwasser_enthalten && ausweis.anteil_warmwasser_1) {
if (!hidden.has(AuditType.WARM_WASSER)){

View File

@@ -1,7 +1,7 @@
import { ObjektClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { ObjektClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AuditType, hidden } from "./hidden.js";
export function auditZeitraumAktuell(ausweis: VerbrauchsausweisWohnenClient, gebaeude: ObjektClient): boolean {
export function auditZeitraumAktuell(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient, gebaeude: ObjektClient): boolean {
if (hidden.has(AuditType.ZEITRAUM_AKTUELL)) {
return false;
}

View File

@@ -1,5 +1,14 @@
---
import { BenutzerClient } from "#components/Ausweis/types";
import HeaderLogin from "#components/design/header/HeaderLogin.svelte";
export type Props = {
user: BenutzerClient | null
}
const { user } = Astro.props;
---
<header id="header" class="">
@@ -62,7 +71,7 @@ lg:px-0 lg:gap-x-4">
<div class="w-full justify-self-center">
<HeaderLogin client:load />
<HeaderLogin {user} client:load />
</div>
</div>

View File

@@ -17,4 +17,5 @@ export const BenutzerSchema = z.object({
rolle: z.nativeEnum(BenutzerRolle),
firma: z.string().nullish(),
lex_office_id: z.string().nullish(),
verified: z.boolean(),
})

View File

@@ -1,23 +1,23 @@
export * from "./anteilshaber.js"
export * from "./apirequests.js"
export * from "./aufnahme.js"
export * from "./bedarfsausweisgewerbe.js"
export * from "./bedarfsausweiswohnen.js"
export * from "./benutzer.js"
export * from "./bild.js"
export * from "./event.js"
export * from "./gegeinpreisung.js"
export * from "./gegnachweisgewerbe.js"
export * from "./gegnachweiswohnen.js"
export * from "./klimafaktoren.js"
export * from "./objekt.js"
export * from "./postleitzahlen.js"
export * from "./rechnung.js"
export * from "./refreshtokens.js"
export * from "./tickets.js"
export * from "./unterlage.js"
export * from "./verbrauchsausweisgewerbe.js"
export * from "./verbrauchsausweiswohnen.js"
export * from "./documenttemplates.js"
export * from "./documenttypes.js"
export * from "./tokens.js"
export * from "./anteilshaber"
export * from "./apirequests"
export * from "./aufnahme"
export * from "./bedarfsausweisgewerbe"
export * from "./bedarfsausweiswohnen"
export * from "./benutzer"
export * from "./bild"
export * from "./event"
export * from "./gegeinpreisung"
export * from "./gegnachweisgewerbe"
export * from "./gegnachweiswohnen"
export * from "./klimafaktoren"
export * from "./objekt"
export * from "./postleitzahlen"
export * from "./rechnung"
export * from "./refreshtokens"
export * from "./tickets"
export * from "./unterlage"
export * from "./verbrauchsausweisgewerbe"
export * from "./verbrauchsausweiswohnen"
export * from "./documenttemplates"
export * from "./documenttypes"
export * from "./tokens"

View File

@@ -37,6 +37,7 @@ export const VerbrauchsausweisGewerbeSchema = z.object({
alternative_lueftung: z.boolean().nullish(),
alternative_kuehlung: z.boolean().nullish(),
warmwasser_enthalten: z.boolean().nullish(),
warmwasser_anteil_bekannt: z.boolean().describe("Falls der Warmwasser Anteil am Verbrauch bekannt ist, sollte dieser Wert auf true stehen").nullish(),
anteil_warmwasser_1: z.number().nullish(),
anteil_warmwasser_2: z.number().nullish(),
ausgestellt: z.boolean().nullish(),

View File

@@ -6,6 +6,9 @@ import Header from "#components/design/header/AusweisHeader.astro";
import Footer from "#components/design/footer/Footer.astro";
import SidebarLeft from "#components/design/sidebars/SidebarLeft.astro";
import { NotificationWrapper } from "@ibcornelsen/ui";
import { getCurrentUser } from "#lib/server/user";
const user = await getCurrentUser(Astro)
export interface Props {
title: string;
@@ -61,7 +64,7 @@ const { title } = Astro.props;
<body>
<Header />
<Header {user} />
<main
class="w-full p-0 grid

View File

@@ -4,7 +4,8 @@ import "../style/global.css";
import "../../svelte-dialogs.config.js";
import DashboardSidebar from "../components/Dashboard/DashboardSidebar.svelte";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import { BenutzerClient } from "#components/Ausweis/types";
import { BenutzerClient, ObjektClient } from "#components/Ausweis/types";
import { prisma } from "#lib/server/prisma";
const valid = validateAccessTokenServer(Astro)
@@ -19,6 +20,29 @@ export interface Props {
const { title, user } = Astro.props;
const objekte = await prisma.objekt.findMany({
where: {
benutzer: {
uid: user.uid
}
},
take: 10,
orderBy: {
erstellungsdatum: "desc"
},
include: {
aufnahmen: {
include: {
bilder: true,
unterlagen: true,
bedarfsausweise_wohnen: true,
verbrauchsausweise_gewerbe: true,
verbrauchsausweise_wohnen: true
}
}
}
})
const schema = JSON.stringify({
"@context": "http://schema.org",
"@type": "Corporation",
@@ -107,7 +131,7 @@ let lightTheme = Astro.cookies.get("theme")?.value === "light";
2xl:grid-cols-[minmax(150px,300px)1fr] 2xl:gap-5 2xl:p-6"
>
<DashboardSidebar lightTheme={lightTheme} benutzer={user} client:load>
<DashboardSidebar lightTheme={lightTheme} benutzer={user} {objekte} client:load>
</DashboardSidebar>
<article class="box rounded-tl-none

View File

@@ -1,7 +1,8 @@
export enum TokenType {
Refresh,
Access,
Reset
Reset,
Verify
}
export type TokenData = { uid: string, typ: TokenType, exp: number }

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

View File

@@ -4,7 +4,7 @@ import * as fs from "fs"
import { PDFDocument, rgb, StandardFonts, TextAlignment } from "pdf-lib";
import { xml2pdf } from "./elements/xml2pdf.js";
import moment from "moment";
import { Heizungsstatus } from "#lib/server/prisma.js";
import { Enums, Heizungsstatus } from "#lib/server/prisma.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { fileURLToPath } from "url";
import { copyPage } from "./utils/copyPage.js";
@@ -355,37 +355,41 @@ export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: Verbrauchsa
const images: string[][] = []
for (const bild of bilder) {
let badge: string[];
let image: string = "";
if (bild.uid) {
image = `<img src="${fileURLToPath(new URL(`${PERSISTENT_DIR}/images/${bilder[0].uid}.jpg`, import.meta.url))}" width="${(pages[2].getHeight() - 120) / 3.1}" />`
} else if (bild.data) {
image = `<img data="${bild.data}" width="${(pages[2].getWidth() - 120) / 3.1}" height="180" />`
}
if (images.length > 0) {
let badge = images[images.length - 1]
if (badge.length == 3) {
badge = [image]
images.push(badge)
} else {
badge.push(image)
}
} else {
for (const bild of bilder) {
let badge: string[];
let image: string = "";
if (bild.kategorie === Enums.BilderKategorie.Gebaeude) {
continue;
}
if (bild.uid) {
image = `<img src="${fileURLToPath(new URL(`${PERSISTENT_DIR}/images/${bild.uid}.jpg`, import.meta.url))}" width="${(pages[2].getWidth() - 120) / 3.1}" height="${(pages[2].getHeight() - marginY * 2) / 4}" />`
} else if (bild.data) {
image = `<img data="${bild.data}" width="${(pages[2].getWidth() - 120) / 3.1}" height="180" />`
}
if (images.length > 0) {
let badge = images[images.length - 1]
if (badge.length == 3) {
badge = [image]
images.push(badge)
} else {
badge.push(image)
}
} else {
badge = [image]
images.push(badge)
}
}
const layoutPage3 = xml2pdf(`<layout height="${pages[2].getHeight()}" width="${pages[2].getWidth()}" marginTop="150" marginLeft="60" marginRight="60">
${images.map(badge => `<flex direction="row" justify="space-between" width="${pages[2].getWidth() - 120}" height="${(pages[2].getHeight() - marginY * 2) / 4}" marginTop="15">${badge.join("")}</flex>`).join("")}
</layout>`, { "default": font })
const layoutPage3 = xml2pdf(`<layout height="${pages[2].getHeight()}" width="${pages[2].getWidth()}" marginTop="150" marginLeft="60" marginRight="60">
${images.map(badge => `<flex direction="row" justify="space-between" width="${pages[2].getWidth() - 120}" height="180" marginTop="15">${badge.join("")}</flex>`).join("")}
</layout>`, { "default": font })
layout.draw(pages[0], 0, pages[0].getHeight())
layoutPage2.draw(pages[1], 0, pages[1].getHeight())
layoutPage3.draw(pages[2], 0, pages[2].getHeight())
layout.draw(pages[0], 0, pages[0].getHeight())
layoutPage2.draw(pages[1], 0, pages[1].getHeight())
layoutPage3.draw(pages[2], 0, pages[2].getHeight())
// const containerWidth = width - marginX;

View File

@@ -5,7 +5,7 @@ import { PDFDocument, rgb, StandardFonts, TextAlignment } from "pdf-lib";
import { checkbox, flex, text } from "./elements/index.js";
import { xml2pdf } from "./elements/xml2pdf.js";
import moment from "moment";
import { BilderKategorie, Heizungsstatus } from "#lib/server/prisma.js";
import { BilderKategorie, Enums, Heizungsstatus } from "#lib/server/prisma.js";
import { fileURLToPath } from "url";
import { copyPage } from "./utils/copyPage.js";
import { PERSISTENT_DIR } from "#lib/server/constants.js";
@@ -13,7 +13,7 @@ import { PERSISTENT_DIR } from "#lib/server/constants.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient, 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);
@@ -297,41 +297,38 @@ export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: Verbrauchsau
})
const images: string[][] = []
for (const bild of bilder) {
let badge: string[];
let image: string = "";
let individualHeight = (pages[2].getHeight() - 370) / 4;
const sortedImages = bilder.reduce((acc, c) => {
let img: string;
if (c.uid) {
img = `<img src="${fileURLToPath(new URL(`${PERSISTENT_DIR}/images/${bilder[0].uid}.jpg`, import.meta.url))}" width="${(pages[2].getHeight() - 120) / 4.1}" height="${individualHeight}" />`
} else {
img = `<img data="${c.data}" width="${(pages[2].getWidth() - 120) / 4.1}" height="${individualHeight}" />`
if (bild.kategorie === Enums.BilderKategorie.Gebaeude) {
continue;
}
if (c.kategorie in acc) {
acc[c.kategorie].push(img)
} else {
acc[c.kategorie] = [img];
if (bild.uid) {
image = `<img src="${fileURLToPath(new URL(`${PERSISTENT_DIR}/images/${bild.uid}.jpg`, import.meta.url))}" width="${(pages[2].getWidth() - 120) / 3.1}" height="${(pages[2].getHeight() - marginY * 2) / 4}" />`
} else if (bild.data) {
image = `<img data="${bild.data}" width="${(pages[2].getWidth() - 120) / 3.1}" height="180" />`
}
return acc;
}, {} as Record<BilderKategorie, string[]>)
let text = ""
for (const [kategorie, images] of Object.entries(sortedImages)) {
text += `<flex direction="column" gap="4" width="${pages[2].getWidth() - 120}" height="${individualHeight}" marginTop="25">
<text font="bold" size="14">${kategorie}</text>
<flex direction="row" justify="space-between" width="${pages[2].getWidth() - 120}" height="${individualHeight}">
${images.join("")}
</flex>
</flex>`
if (images.length > 0) {
let badge = images[images.length - 1]
if (badge.length == 3) {
badge = [image]
images.push(badge)
} else {
badge.push(image)
}
} else {
badge = [image]
images.push(badge)
}
}
const layoutPage3 = xml2pdf(`<layout height="${pages[2].getHeight()}" width="${pages[2].getWidth()}" marginTop="150" marginLeft="60" marginRight="60">
${text}
</layout>`, { "default": font, bold })
${images.map(badge => `<flex direction="row" justify="space-between" width="${pages[2].getWidth() - 120}" height="${(pages[2].getHeight() - marginY * 2) / 4}" marginTop="15">${badge.join("")}</flex>`).join("")}
</layout>`, { "default": font })
layout.draw(pages[0], 0, pages[0].getHeight())
layoutPage2.draw(pages[1], 0, pages[1].getHeight())

View File

@@ -140,18 +140,24 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
const gebaeudeBild = bilder.find(image => image.kategorie === Enums.BilderKategorie.Gebaeude);
if (gebaeudeBild) {
let image: PDFImage;
let image: PDFImage | null;
try {
image = await pdf.embedJpg(gebaeudeBild?.data)
image = await pdf.embedJpg(gebaeudeBild.data)
} catch(e) {
image = await pdf.embedPng(gebaeudeBild?.data)
try {
image = await pdf.embedPng(gebaeudeBild.data)
} catch(e) {
image = null;
}
}
if (image) {
pages[0].drawImage(image, {
x: 460.5,
y: height - 289,
width: 111,
height: 138
})
}
pages[0].drawImage(image, {
x: 460.5,
y: height - 289,
width: 111,
height: 138
})
}
// Checkmark Angabe energetische Qualität des Gebäudes.

View File

@@ -1,10 +1,10 @@
import { AufnahmeClient, BenutzerClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeClient, BenutzerClient, BildClient, ObjektClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import { getEmpfehlungen } from "#lib/XML/getEmpfehlungen.js";
import { Enums } from "#lib/server/prisma.js";
import * as fs from "fs"
import moment from "moment";
import { PDFDocument, PDFFont, PDFImage, PDFPage, RotationTypes, StandardFonts, TextAlignment } from "pdf-lib";
import { PDFDocument, PDFFont, PDFImage, PDFPage, StandardFonts, TextAlignment } from "pdf-lib";
import { addCheckMark } from "./utils/checkbox.js";
import { addText } from "./utils/text.js";
import { addAnsichtsausweisLabel, addDatumGEG } from "./utils/helpers.js";
@@ -14,7 +14,7 @@ import { PERSISTENT_DIR } from "#lib/server/constants.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient) {
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("./templates/GEG24_Wohngebaeude_ohne_pfeile_form.pdf", import.meta.url), "base64");
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("../../../public/pdf/templates/GEG24_Wohngebaeude_ohne_pfeile_form.pdf", import.meta.url), "base64");
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const pages = pdf.getPages()
@@ -130,7 +130,7 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
// 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, {
@@ -142,7 +142,7 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
}
// 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 - 770,
@@ -184,8 +184,8 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
const addEnergieverbrauchSkalaPfeile = async (page: PDFPage) => {
const pfeilNachUnten = await pdf.embedPng(fs.readFileSync(new URL("../../../public/images/pfeil-nach-unten.png", import.meta.url), "base64"))
const pfeilNachOben = await pdf.embedPng(fs.readFileSync(new URL("../../../public/images/pfeil-nach-oben.png", import.meta.url), "base64"))
const pfeilNachUnten = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/pfeil-nach-unten.png", import.meta.url), "base64"))
const pfeilNachOben = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/pfeil-nach-oben.png", import.meta.url), "base64"))
// Wir müssen den berechneten Wert zwischen 0 und 250 als Wert zwischen 0 und 1 festlegen
const endenergieverbrauchTranslationPercentage = Math.min(250, Math.max(0, berechnungen?.endEnergieVerbrauchGesamt || 0)) / 250

View File

@@ -3,7 +3,7 @@ import { pdfDatenblattVerbrauchsausweisGewerbe } from "#lib/pdf/pdfDatenblattVer
import { pdfDatenblattVerbrauchsausweisWohnen } from "#lib/pdf/pdfDatenblattVerbrauchsausweisWohnen.js";
import { pdfVerbrauchsausweisGewerbe } from "#lib/pdf/pdfVerbrauchsausweisGewerbe.js";
import { pdfVerbrauchsausweisWohnen } from "#lib/pdf/pdfVerbrauchsausweisWohnen.js";
import { Enums, prisma } from "#lib/server/prisma";
import { Enums, prisma } from "#lib/server/prisma.js";
/**
* Gibt den richtigen Prisma Adapter für die Ausweisart basierend auf der UID zurück, oder null bei einer falschen UID.

View File

@@ -6,17 +6,17 @@ import {
Enums,
Rechnung,
VerbrauchsausweisWohnen,
} from "#lib/client/prisma";
import { prisma } from "#lib/server/prisma";
} from "#lib/client/prisma.js";
import { prisma } from "#lib/server/prisma.js";
import { getAnsichtsausweis } from "../ausweis.js";
import Mail from "nodemailer/lib/mailer/index.js";
import { sqids } from "#client/lib/helpers.js";
export async function sendInvoiceMail(
ausweis: VerbrauchsausweisWohnen,
rechnung: Rechnung,
user: Benutzer
) {
console.log(ausweis);
const aufnahme = await prisma.aufnahme.findUnique({
where: {
id: ausweis.aufnahme_id,
@@ -33,7 +33,7 @@ export async function sendInvoiceMail(
const ausweisart = getAusweisartFromUUID(ausweis.uid);
const attachments: any[] = [];
const attachments: Mail.Attachment[] = [];
if (ausweisart != Enums.Ausweisart.BedarfsausweisWohnen) {
const ansichtsausweis = await getAnsichtsausweis(
@@ -46,15 +46,15 @@ export async function sendInvoiceMail(
);
if (ansichtsausweis) {
attachments.push([
attachments.push(
{
filename: "Ansichtsausweis.pdf",
filename: `ID_${ausweis.id}_Ansichtsausweis.pdf`,
encoding: "binary",
content: Buffer.from(ansichtsausweis),
contentType: "application/pdf",
contentDisposition: "attachment",
},
]);
);
}
}
@@ -62,7 +62,7 @@ export async function sendInvoiceMail(
attachments,
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${ausweis.uid})`,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${ausweis.id})`,
cc: {
address: rechnung.email || "",
name: rechnung.empfaenger || "",
@@ -79,7 +79,7 @@ export async function sendInvoiceMail(
<tr><td>IBAN</td><td>:<td>\t DE81 2004 0000 0348 6008 00</td>
<tr><td>BIC</td><td>:</td><td>\t COBADEFFXXX</td>
<tr><td>Betrag</td><td>:</td><td>\t <b>${rechnung.betrag}€</b></td>
<tr><td>Verwendungszweck</td><td>:</td><td>\t <b>${rechnung.uid}</b></td>
<tr><td>Verwendungszweck</td><td>:</td><td>\t <b>${rechnung.id}</b></td>
</table>
<br>

View File

@@ -8,18 +8,14 @@ import {
} from "#lib/client/prisma.js";
import { prisma } from "#lib/server/prisma.js";
import { getAnsichtsausweis } from "../ausweis.js";
import Sqids from "sqids";
import { sqids } from "#client/lib/helpers.js";
import Mail from "nodemailer/lib/mailer/index.js";
export async function sendPaymentSuccessMail(
ausweis: VerbrauchsausweisWohnen,
rechnung: Rechnung,
user: Benutzer
) {
const sqids = new Sqids({
alphabet: "0123456789abcdefghijklmnopqrstuvw",
minLength: 8
})
const aufnahme = await prisma.aufnahme.findUnique({
where: {
id: ausweis.aufnahme_id,
@@ -36,7 +32,7 @@ export async function sendPaymentSuccessMail(
let info: string = "";
const ausweisart = getAusweisartFromUUID(ausweis.uid);
const attachments: any[] = [];
const attachments: Mail.Attachment[] = [];
if (ausweisart != Enums.Ausweisart.BedarfsausweisWohnen) {
const ansichtsausweis = await getAnsichtsausweis(
@@ -49,15 +45,15 @@ export async function sendPaymentSuccessMail(
);
if (ansichtsausweis) {
attachments.push([
attachments.push(
{
filename: "Ansichtsausweis.pdf",
filename: `ID_${ausweis.id}_Ansichtsausweis.pdf`,
encoding: "binary",
content: Buffer.from(ansichtsausweis),
contentType: "application/pdf",
contentDisposition: "attachment",
},
]);
}
);
}
info =
"In der Regel erhalten Sie Ihren geprüften Ausweis innerhalb von 24 Stunden.";
@@ -70,7 +66,7 @@ export async function sendPaymentSuccessMail(
attachments,
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${sqids.encode([ausweis.id])})`,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${ausweis.id})`,
cc: {
address: rechnung.email || "",
name: rechnung.empfaenger || "",

View File

@@ -0,0 +1,37 @@
import { BASE_URI } from "#lib/constants.js";
import { transport } from "#lib/mail.js";
import {
Benutzer,
} from "#lib/client/prisma.js";
import { encodeToken } from "#lib/auth/token.js";
import { TokenType } from "#lib/auth/types.js";
export async function sendRegisterMail(
user: Benutzer
) {
const verificationJwt = encodeToken({
typ: TokenType.Verify,
exp: Date.now() + (15 * 60 * 1000),
uid: user.uid
})
await transport.sendMail({
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Ihre Registrierung bei IBCornelsen`,
bcc: "info@online-energieausweis.org",
text: `Hallo ${user.vorname},
vielen Dank für Ihre Registrierung bei IBCornelsen! Ihr Benutzerkonto wurde erfolgreich erstellt.
Um Ihre Registrierung abzuschließen, klicken Sie bitte auf den folgenden Link, um Ihre E-Mail-Adresse zu bestätigen:
https://${BASE_URI}/auth/verify?t=${verificationJwt}
Falls Sie diese Registrierung nicht durchgeführt haben, ignorieren Sie bitte diese E-Mail. Bei Fragen oder Problemen steht Ihnen unser Support-Team jederzeit zur Verfügung.
Wir freuen uns, Sie beim IBC willkommen zu heißen!
Mit freundlichen Grüßen
Ihr IBCornelsen-Team`
});
}

View File

@@ -2,6 +2,7 @@
import { AufnahmeKomplettClient, BenutzerClient } from "#components/Ausweis/types.js";
import Carousel from "#components/Carousel.svelte";
import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte";
import DashboardNachweis from "#components/Dashboard/DashboardNachweis.svelte";
import { Objekt } from "#lib/client/prisma.js";
import { ChevronLeft, ChevronRight } from "radix-svelte-icons";
@@ -9,18 +10,12 @@
export let aufnahme: AufnahmeKomplettClient;
export let objekt: Objekt;
import { onMount } from "svelte";
let dropdownOpen = false;
function toggleDropdown() {
dropdownOpen = !dropdownOpen;
}
function closeDropdown() {
dropdownOpen = false;
}
</script>
<h1>{objekt.adresse}, {objekt.plz} {objekt.ort}</h1>
@@ -34,9 +29,9 @@
{#if dropdownOpen}
<div class="absolut mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5" on:click|stopPropagation on:keydown|stopPropagation on:keyup|stopPropagation>
<div class="py-1" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
<button class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis Wohnen Erstellen</button>
<button class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis Gewerbe Erstellen</button>
<button class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Bedarfsausweis Erstellen</button>
<a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?aufnahme={aufnahme.uid}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis Wohnen Erstellen</a>
<a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe?aufnahme={aufnahme.uid}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis Gewerbe Erstellen</a>
<a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude?aufnahme={aufnahme.uid}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Bedarfsausweis Erstellen</a>
</div>
</div>
{/if}
@@ -69,12 +64,15 @@
<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} progress={0}></DashboardAusweis>
<DashboardAusweis {ausweis} {aufnahme} {objekt}></DashboardAusweis>
{/each}
{#each aufnahme.bedarfsausweise_wohnen as ausweis}
<DashboardAusweis {ausweis} {aufnahme} {objekt} progress={0}></DashboardAusweis>
<DashboardAusweis {ausweis} {aufnahme} {objekt}></DashboardAusweis>
{/each}
{#each aufnahme.verbrauchsausweise_gewerbe as ausweis}
<DashboardAusweis {ausweis} {aufnahme} {objekt} progress={0}></DashboardAusweis>
<DashboardAusweis {ausweis} {aufnahme} {objekt}></DashboardAusweis>
{/each}
{#each aufnahme.geg_nachweise_wohnen as nachweis}
<DashboardNachweis {nachweis} {aufnahme} {objekt}></DashboardNachweis>
{/each}
</div>

View File

@@ -19,7 +19,7 @@
import { AufnahmeClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types.js";
import { BenutzerClient } from "#components/Ausweis/types.js";
import GebaeudeDaten from "#components/Ausweis/GebaeudeDaten.svelte";
import { Enums } from "#lib/client/prisma";
import { Enums } from "#lib/client/prisma.js";
import moment from "moment";
import {
AuditType,
@@ -37,7 +37,11 @@
import { auditWohnFlaeche } from "#components/Verbrauchsausweis/audits/WohnFlaeche.js";
import { auditWohnflaecheGroesserGesamtflaeche } from "#components/Verbrauchsausweis/audits/WohnflaecheGroesserGesamtflaeche.js";
import { auditZeitraumAktuell } from "#components/Verbrauchsausweis/audits/ZeitraumAktuell.js";
import { notifications, RawNotificationWrapper, RawNotification } from "@ibcornelsen/ui";
import {
RawNotificationWrapper,
RawNotification,
notifications,
} from "#components/Notifications/index.js";
export let ausweis: VerbrauchsausweisGewerbeClient;
export let user: BenutzerClient;
@@ -116,10 +120,13 @@
localStorage.setItem("objekt", JSON.stringify(objekt))
localStorage.setItem("bilder", JSON.stringify(bilder))
}
let form: HTMLFormElement;
let skala: HTMLDivElement;
</script>
<div id="skala" class="bg-white grid grid-cols-1 px-0 sm:p-4 lg:grid-cols-2 lg:gap-x-6">
<div id="skala" bind:this={skala} class="bg-white grid grid-cols-1 px-0 sm:p-4 lg:grid-cols-2 lg:gap-x-6">
<PerformanceScore
bind:ausweis
@@ -138,7 +145,7 @@
<!-- TODO: Submit implementieren in externer Datei wenn Verbrauchsausweis Wohnen fertig ist -->
<form id="formInput-1" data-cy="ausweis" name="ausweis">
<form id="formInput-1" data-cy="ausweis" name="ausweis" bind:this={form}>
<div id="formular-box" class="formular-boxen ring-0">
<ButtonWeiterHilfe
@@ -147,8 +154,10 @@
bind:user
bind:objekt
bind:aufnahme
ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen}
ausweisart={Enums.Ausweisart.VerbrauchsausweisGewerbe}
showWeiter={false}
{form}
{skala}
>
</ButtonWeiterHilfe>
@@ -261,6 +270,9 @@
bind:objekt
bind:aufnahme
ausweisart={Enums.Ausweisart.VerbrauchsausweisGewerbe}
showWeiter={true}
{form}
{skala}
>
</ButtonWeiterHilfe>

View File

@@ -10,7 +10,7 @@
GEGNachweisWohnenClient,
} from "#components/Ausweis/types.js";
import Bereich from "#components/labels/Bereich.svelte";
import { Enums } from "#lib/client/prisma";
import { Enums } from "#lib/client/prisma.js";
import InputLabel from "#components/labels/InputLabel.svelte";
import HelpLabel from "#components/labels/HelpLabel.svelte";
import Progressbar from "#components/Ausweis/Progressbar.svelte";
@@ -24,40 +24,39 @@
export let aufnahme: AufnahmeClient;
export let user: BenutzerClient = {} as BenutzerClient;
export let bilder: UploadedGebaeudeBild[] = [];
export let plaene: UnterlageClient[] =
[];
export let plaene: UnterlageClient[] = [];
export let unterlagen: UnterlageClient[] = [];
if (Object.keys(nachweis).length === 0) {
const localStorageAusweis = localStorage.getItem("ausweis");
const localStorageAusweis = localStorage.getItem("geg-nachweis-wohnen.ausweis");
if (localStorageAusweis) {
nachweis = JSON.parse(localStorageAusweis)
}
}
if (Object.keys(aufnahme).length === 0) {
const localStorageAufnahme = localStorage.getItem("aufnahme");
const localStorageAufnahme = localStorage.getItem("geg-nachweis-wohnen.aufnahme");
if (localStorageAufnahme) {
aufnahme = JSON.parse(localStorageAufnahme)
}
}
if (Object.keys(objekt).length === 0) {
const localStorageObjekt = localStorage.getItem("objekt");
const localStorageObjekt = localStorage.getItem("geg-nachweis-wohnen.objekt");
if (localStorageObjekt) {
objekt = JSON.parse(localStorageObjekt)
}
}
if (Object.keys(bilder).length === 0) {
const localStorageBilder = localStorage.getItem("bilder");
const localStorageBilder = localStorage.getItem("geg-nachweis-wohnen.bilder");
if (localStorageBilder) {
bilder = JSON.parse(localStorageBilder)
}
}
if (Object.keys(unterlagen).length === 0) {
const localStorageUnterlagen = localStorage.getItem("unterlagen");
const localStorageUnterlagen = localStorage.getItem("geg-nachweis-wohnen.unterlagen");
if (localStorageUnterlagen) {
unterlagen = JSON.parse(localStorageUnterlagen)
}
@@ -65,18 +64,21 @@
$: {
localStorage.setItem("ausweis", JSON.stringify(nachweis))
localStorage.setItem("aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("objekt", JSON.stringify(objekt))
localStorage.setItem("bilder", JSON.stringify(bilder))
localStorage.setItem("unterlagen", JSON.stringify(unterlagen))
localStorage.setItem("geg-nachweis-wohnen.ausweis", JSON.stringify(nachweis))
localStorage.setItem("geg-nachweis-wohnen.aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("geg-nachweis-wohnen.objekt", JSON.stringify(objekt))
localStorage.setItem("geg-nachweis-wohnen.bilder", JSON.stringify(bilder))
localStorage.setItem("geg-nachweis-wohnen.unterlagen", JSON.stringify(unterlagen))
}
const ausweisart = Enums.Ausweisart.GEGNachweisWohnen;
const anliegen = "Angebot anfragen";
let form: HTMLFormElement;
let skala: HTMLDivElement;
</script>
<div id="skala" class="bg-white grid grid-cols-1 p-4 lg:grid-cols-2 lg:gap-x-6 no-scroll">
<div id="skala" bind:this={skala} class="bg-white grid grid-cols-1 p-4 lg:grid-cols-2 lg:gap-x-6 no-scroll">
<Progressbar active={0} {ausweisart} {anliegen} steps={["Gebäudedaten","Kundendaten","Anfragebestätigung"]} />
@@ -86,6 +88,7 @@
id="formInput-1"
name="ausweis"
data-test="ausweis"
bind:this={form}
>
<div id="formular-box" class="formular-boxen ring-0">
<!-- A Prüfung der Ausweisart -->
@@ -189,6 +192,8 @@
bind:objekt
bind:aufnahme
ausweisart={Enums.Ausweisart.GEGNachweisWohnen}
{form}
{skala}
>
</ButtonWeiterHilfe>

View File

@@ -2,7 +2,7 @@ import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { adminMiddleware } from "#lib/middleware/authorization.js";
import { mollieClient } from "#lib/mollie.js";
import { getPrismaAusweisAdapter } from "#lib/server/ausweis.js";
import { Prisma, prisma } from "#lib/server/prisma";
import { Prisma, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";

View File

@@ -1,8 +1,9 @@
import { AufnahmeClient, OptionalNullable, UUidWithPrefix, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { AufnahmeSchema, prisma } from "#lib/server/prisma.js";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { AufnahmeSchema } from "src/generated/zod/aufnahme.js";
import { z } from "zod";
export const PATCH = defineApiRoute({
@@ -22,7 +23,7 @@ export const PATCH = defineApiRoute({
where: {
uid,
benutzer_id: user.id
},
}
});
if (!aufnahme) {

View File

@@ -1,6 +1,6 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js"
import { authorizationMiddleware } from "#lib/middleware/authorization.js"
import { AufnahmeSchema, ObjektSchema, prisma } from "#lib/server/prisma"
import { AufnahmeSchema, ObjektSchema, prisma } from "#lib/server/prisma.js"
import { APIError, defineApiRoute } from "astro-typesafe-api/server"
import { z } from "zod"

View File

@@ -9,7 +9,8 @@ export const PUT = defineApiRoute({
input: ObjektSchema.omit({
id: true,
uid: true,
benutzer_id: true
benutzer_id: true,
erstellungsdatum: true
}),
output: z.object({
uid: UUidWithPrefix

View File

@@ -1,5 +1,5 @@
import { z } from "zod";
import { Enums, RechnungSchema, prisma } from "#lib/server/prisma";
import { Enums, prisma } from "#lib/server/prisma.js";
import { mollieClient } from "#lib/mollie.js";
import { PaymentMethod } from "@mollie/api-client";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
@@ -10,6 +10,8 @@ import {
import { 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";
import { RechnungSchema } from "src/generated/zod/rechnung.js";
export const PUT = defineApiRoute({
meta: {
@@ -28,7 +30,6 @@ export const PUT = defineApiRoute({
.merge(
RechnungSchema.omit({
benutzer_id: true,
aufnahme_id: true,
bezahlt_am: true,
erstellt_am: true,
id: true,
@@ -86,27 +87,57 @@ export const PUT = defineApiRoute({
});
}
// TODO
// Wir erstellen eine neue Rechnung in unserer Datenbank.
const rechnung = await prisma.rechnung.create({
data: {
benutzer_id: user.id,
betrag,
bezahlmethode: bezahlmethode,
status: Enums.Rechnungsstatus.open,
verbrauchsausweis_wohnen: {
connect: {
uid: ausweis_uid
}
},
services,
ausweistyp
},
select: {
uid: true,
betrag: true,
},
});
let rechnung: Rechnung | null = null;
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
rechnung = await prisma.rechnung.create({
data: {
benutzer_id: user.id,
betrag,
bezahlmethode: bezahlmethode,
status: Enums.Rechnungsstatus.open,
verbrauchsausweis_wohnen: {
connect: {
uid: ausweis_uid
}
},
services,
ausweistyp
}
});
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
rechnung = await prisma.rechnung.create({
data: {
benutzer_id: user.id,
betrag,
bezahlmethode: bezahlmethode,
status: Enums.Rechnungsstatus.open,
verbrauchsausweis_gewerbe: {
connect: {
uid: ausweis_uid
}
},
services,
ausweistyp
}
});
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
rechnung = await prisma.rechnung.create({
data: {
benutzer_id: user.id,
betrag,
bezahlmethode: bezahlmethode,
status: Enums.Rechnungsstatus.open,
bedarfsausweis_wohnen: {
connect: {
uid: ausweis_uid
}
},
services,
ausweistyp
}
});
}
if (!rechnung) {
throw new APIError({

View File

@@ -1,10 +1,11 @@
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma, UnterlageSchema } from "#lib/server/prisma";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";
import { fileURLToPath } from "url";
import { writeFileSync } from "fs";
import { PERSISTENT_DIR } from "#lib/server/constants.js";
import { UnterlageSchema } from "src/generated/zod/unterlage.js";
export const PUT = defineApiRoute({
input: UnterlageSchema.omit({

View File

@@ -1,6 +1,7 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
import { hashPassword } from "#lib/password.js";
import { sendRegisterMail } from "#lib/server/mail/registrierung.js";
import { BenutzerSchema, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";
@@ -50,20 +51,20 @@ export const PUT = defineApiRoute({
uid: UUidWithPrefix
}),
async fetch(input) {
const user = await prisma.benutzer.findUnique({
const existingUser = await prisma.benutzer.findUnique({
where: {
email: input.email
}
})
if (user) {
if (existingUser) {
throw new APIError({
code: "CONFLICT",
message: "Email Adresse ist bereits vergeben."
})
}
const { uid } = await prisma.benutzer.create({
const user = await prisma.benutzer.create({
data: {
email: input.email,
passwort: hashPassword(input.passwort),
@@ -72,6 +73,8 @@ export const PUT = defineApiRoute({
}
})
return { uid }
await sendRegisterMail(user)
return { uid: user.uid }
},
})

View File

@@ -1,8 +1,9 @@
import { OptionalNullable, UUidWithPrefix, VerbrauchsausweisGewerbeClient, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma, VerbrauchsausweisGewerbeSchema } from "#lib/server/prisma";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { VerbrauchsausweisGewerbeSchema } from "src/generated/zod/verbrauchsausweisgewerbe.js";
import { z } from "zod";
export const PATCH = defineApiRoute({
@@ -64,13 +65,6 @@ export const DELETE = defineApiRoute({
const ausweis = await prisma.verbrauchsausweisGewerbe.findUnique({
where: {
uid,
},
include: {
aufnahme: {
select: {
storniert: true
}
}
}
});
@@ -100,7 +94,7 @@ export const DELETE = defineApiRoute({
// });
// }
if (ausweis.aufnahme.storniert) {
if (ausweis.storniert) {
// Falls der Ausweis bereits storniert ist, werfen wir einen Fehler
throw new APIError({
code: "BAD_REQUEST",
@@ -108,9 +102,9 @@ export const DELETE = defineApiRoute({
});
}
await prisma.aufnahme.update({
await prisma.verbrauchsausweisGewerbe.update({
where: {
id: ausweis.aufnahme_id
uid
},
data: {
storniert: true

View File

@@ -1,7 +1,8 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma, VerbrauchsausweisGewerbeSchema } from "#lib/server/prisma";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { VerbrauchsausweisGewerbeSchema } from "src/generated/zod/verbrauchsausweisgewerbe.js";
import { z } from "zod";
export const PUT = defineApiRoute({
@@ -17,7 +18,9 @@ export const PUT = defineApiRoute({
benutzer_id: true,
uid: true,
aufnahme_id: true
}),
}).merge(z.object({
startdatum: z.coerce.date()
})),
uid_aufnahme: UUidWithPrefix
}),
output: z.object({

View File

@@ -1,8 +1,9 @@
import { OptionalNullable, UUidWithPrefix, VerbrauchsausweisWohnenClient, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma, VerbrauchsausweisWohnenSchema } from "#lib/server/prisma.js";
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({
@@ -66,13 +67,6 @@ export const DELETE = defineApiRoute({
const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
uid,
},
include: {
aufnahme: {
select: {
storniert: true
}
}
}
});
@@ -102,7 +96,7 @@ export const DELETE = defineApiRoute({
// });
// }
if (ausweis.aufnahme.storniert) {
if (ausweis.storniert) {
// Falls der Ausweis bereits storniert ist, werfen wir einen Fehler
throw new APIError({
code: "BAD_REQUEST",
@@ -110,9 +104,9 @@ export const DELETE = defineApiRoute({
});
}
await prisma.aufnahme.update({
await prisma.verbrauchsausweisWohnen.update({
where: {
id: ausweis.aufnahme_id
uid
},
data: {
storniert: true

View File

@@ -0,0 +1,32 @@
---
import Layout from "#layouts/Layout.astro";
import { decodeToken } from "#lib/auth/token";
import { TokenType } from "#lib/auth/types";
import { prisma } from "#lib/server/prisma";
const token = Astro.url.searchParams.get("t");
if (!token) {
return Astro.redirect("/")
}
const payload = decodeToken(token)
if (payload.typ !== TokenType.Verify || !payload.uid || !payload.exp || payload.exp < Date.now()) {
return Astro.redirect("/")
}
await prisma.benutzer.update({
where: {
uid: payload.uid
},
data: {
verified: true
}
})
---
<Layout title="Bestätigung">
<h1>Vielen Dank</h1>
<p>Ihre Email Adresse wurde bestätigt, sie können diese Seite nun schließen.</p>
</Layout>

View File

@@ -31,6 +31,9 @@ const objekte = await prisma.objekt.findMany({
}
},
take: 10,
orderBy: {
erstellungsdatum: "desc"
},
include: {
aufnahmen: {
include: {

View File

@@ -2,12 +2,12 @@
import AusweisLayout from "#layouts/AusweisLayoutDaten.astro";
import { AufnahmeClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types";
import { createCaller } from "src/astro-typesafe-api-caller";
import { inferOutput } from "astro-typesafe-api/client";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import VerbrauchsausweisGewerbeModule from "#modules/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbeModule.svelte";
const uid = Astro.url.searchParams.get("uid");
const uid_aufnahme = Astro.url.searchParams.get("aufnahme")
let ausweis: VerbrauchsausweisGewerbeClient = {} as VerbrauchsausweisGewerbeClient;
let aufnahme: AufnahmeClient = {} as AufnahmeClient;
let objekt: ObjektClient = {} as ObjektClient;
@@ -75,9 +75,35 @@ if (uid) {
"/energieausweis-erstellen/verbrauchsausweis-gewerbe"
);
}
} else if (uid_aufnahme) {
if (!valid) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
let { uid_objekt, ...result} = await caller.aufnahme._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: uid_aufnahme
}
})
aufnahme = result;
objekt = await caller.objekt._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: uid_objekt
}
})
}
---
<AusweisLayout title="Verbrauchsausweis Gewerbe erstellen | IBCornelsen">
<VerbrauchsausweisGewerbeModule client:only {ausweis} {objekt} {aufnahme} {bilder} />
<VerbrauchsausweisGewerbeModule client:only {ausweis} {objekt} {aufnahme} {bilder} />
</AusweisLayout>

View File

@@ -8,6 +8,7 @@ import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import { Enums } from "#lib/server/prisma";
const uid = Astro.url.searchParams.get("uid");
const uid_aufnahme = Astro.url.searchParams.get("aufnahme")
const ausweistyp = Astro.url.searchParams.get("ausweistyp") || Enums.AusweisTyp.Standard;
@@ -76,6 +77,32 @@ if (uid) {
"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude"
);
}
} else if (uid_aufnahme) {
if (!valid) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
let { uid_objekt, ...result} = await caller.aufnahme._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: uid_aufnahme
}
})
aufnahme = result;
objekt = await caller.objekt._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: uid_objekt
}
})
}
---

View File

@@ -338,6 +338,7 @@ export function fakeBenutzerComplete() {
rolle: BenutzerRolle.USER,
firma: undefined,
lex_office_id: undefined,
verified: false,
};
}
export function fakeBild() {
@@ -659,6 +660,7 @@ export function fakeVerbrauchsausweisGewerbe() {
alternative_lueftung: undefined,
alternative_kuehlung: undefined,
warmwasser_enthalten: undefined,
warmwasser_anteil_bekannt: undefined,
anteil_warmwasser_1: undefined,
anteil_warmwasser_2: undefined,
prueftext: undefined,
@@ -702,6 +704,7 @@ export function fakeVerbrauchsausweisGewerbeComplete() {
alternative_lueftung: undefined,
alternative_kuehlung: undefined,
warmwasser_enthalten: undefined,
warmwasser_anteil_bekannt: undefined,
anteil_warmwasser_1: undefined,
anteil_warmwasser_2: undefined,
ausgestellt: false,

View File

@@ -32,6 +32,10 @@ module.exports = {
'base-content': '#1e2734',
'box-heading': '#3A4AB5',
'accent': '#7b37cd',
'accent-focus': '#5f25a7',
'accent-content': '#ffffff',
"formular-box": "rgba(252,234,187,0.2)",
"formular-rahmen": "rgba(255,204,6,1)",