Merge branch 'main' into UMBE

This commit is contained in:
UMBENOMENA
2025-02-21 19:12:43 +01:00
committed by GitHub
151 changed files with 8589 additions and 1729 deletions

View File

@@ -61,6 +61,7 @@
"@types/jsonwebtoken": "^9.0.7",
"@types/mime-types": "^2.1.4",
"@types/nodemailer": "^6.4.17",
"@types/papaparse": "^5.3.15",
"@types/siema": "^1.4.11",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^5.62.0",
@@ -72,6 +73,7 @@
"cypress-vite": "^1.6.0",
"eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0",
"papaparse": "^5.5.2",
"postcss": "^8.5.1",
"postcss-import": "^16.1.0",
"postcss-nesting": "^13.0.1",
@@ -556,6 +558,8 @@
"@types/nodemailer": ["@types/nodemailer@6.4.17", "", { "dependencies": { "@types/node": "*" } }, "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww=="],
"@types/papaparse": ["@types/papaparse@5.3.15", "", { "dependencies": { "@types/node": "*" } }, "sha512-JHe6vF6x/8Z85nCX4yFdDslN11d+1pr12E526X8WAfhadOeaOTx5AuIkvDKIBopfvlzpzkdMx4YyvSKCM9oqtw=="],
"@types/pug": ["@types/pug@2.0.10", "", {}, "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA=="],
"@types/qs": ["@types/qs@6.9.18", "", {}, "sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA=="],
@@ -1658,6 +1662,8 @@
"pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
"papaparse": ["papaparse@5.5.2", "", {}, "sha512-PZXg8UuAc4PcVwLosEEDYjPyfWnTEhOrUfdv+3Bx+NuAb+5NhDmXzg5fHWmdCh1mP5p7JAZfFr3IMQfcntNAdA=="],
"parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="],
"parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "^2.0.0", "character-entities-legacy": "^3.0.0", "character-reference-invalid": "^2.0.0", "decode-named-character-reference": "^1.0.0", "is-alphanumerical": "^2.0.0", "is-decimal": "^2.0.0", "is-hexadecimal": "^2.0.0" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="],

View File

@@ -75,6 +75,7 @@
"@types/jsonwebtoken": "^9.0.7",
"@types/mime-types": "^2.1.4",
"@types/nodemailer": "^6.4.17",
"@types/papaparse": "^5.3.15",
"@types/siema": "^1.4.11",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^5.62.0",
@@ -86,6 +87,7 @@
"cypress-vite": "^1.6.0",
"eslint": "~8.15.0",
"eslint-config-prettier": "8.1.0",
"papaparse": "^5.5.2",
"postcss": "^8.5.1",
"postcss-import": "^16.1.0",
"postcss-nesting": "^13.0.1",

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@@ -6,9 +6,9 @@ const app = express();
const base = '/';
app.use(base, express.static('dist/client/'));
app.use(ssrHandler);
app.use(express.json({ limit: "50mb" }))
app.use(express.urlencoded({ limit: "50mb" }))
app.listen(80, function() {
console.log('Server started on http://localhost:80');
});

View File

@@ -1,24 +1,31 @@
import { createCallerFactory } from "astro-typesafe-api/server";
export const createCaller = createCallerFactory({
"bild": await import("../src/pages/api/bild.ts"),
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
"unterlage": await import("../src/pages/api/unterlage.ts"),
"admin/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"),
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
"admin/erinnern": await import("../src/pages/api/admin/erinnern.ts"),
"admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"),
"admin/post-ausstellen": await import("../src/pages/api/admin/post-ausstellen.ts"),
"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"),
"bedarfsausweis-wohnen/[uid]": await import("../src/pages/api/bedarfsausweis-wohnen/[uid].ts"),
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/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/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"),
"bilder/[uid]": await import("../src/pages/api/bilder/[uid].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"),
"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"),
"objekt": await import("../src/pages/api/objekt/index.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"),
"user": await import("../src/pages/api/user/index.ts"),
@@ -30,6 +37,6 @@ export const createCaller = createCallerFactory({
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
"aufnahme/[uid]/bilder": await import("../src/pages/api/aufnahme/[uid]/bilder.ts"),
"aufnahme/[uid]": await import("../src/pages/api/aufnahme/[uid]/index.ts"),
"aufnahme/[uid]/unterlagen": await import("../src/pages/api/aufnahme/[uid]/unterlagen.ts"),
"objekt/[uid]": await import("../src/pages/api/objekt/[uid]/index.ts"),
"objekt/[uid]/unterlagen": await import("../src/pages/api/objekt/[uid]/unterlagen.ts"),
})

View File

@@ -3,14 +3,14 @@ import { api } from "astro-typesafe-api/client"
import { exclude } from "#lib/exclude.js";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { AufnahmeClient, BedarfsausweisWohnenClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient, } from "#components/Ausweis/types.js";
import { AufnahmeClient, BedarfsausweisWohnenClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient, } from "#components/Ausweis/types.js";
import { Enums } from "@ibcornelsen/database/client";
export async function ausweisSpeichern(
ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient,
objekt: ObjektClient,
aufnahme: AufnahmeClient,
bilder: (UploadedGebaeudeBild & { base64?: string })[],
bilder: BildClient[],
ausweisart: Enums.Ausweisart
) {
if (objekt.uid) {
@@ -99,15 +99,7 @@ export async function ausweisSpeichern(
ausweis.uid = uid;
}
for (const bild of bilder) {
if (bild.uid) {
continue;
}
const response = await api.aufnahme._uid.bilder.PUT.fetch({
base64: bild.base64,
kategorie: bild.kategorie
}, {
await api.aufnahme._uid.bilder.PUT.fetch(bilder.map(bild => bild.uid), {
params: {
uid: aufnahme.uid
},
@@ -116,9 +108,6 @@ export async function ausweisSpeichern(
}
})
bild.uid = response.uid
}
return {
uid_ausweis: ausweis.uid,
uid_aufnahme: aufnahme.uid,

View File

@@ -22,7 +22,7 @@ export async function bilderHochladen(
const imagesToUpload = images.filter(
(image) => !image.uid || image.update
) as unknown as {
base64: string;
data: string;
kategorie: string;
uid?: string;
update: boolean;
@@ -46,7 +46,7 @@ export async function bilderHochladen(
try {
if (image.update) {
await api.bilder._uid.PATCH.fetch({
base64: image.base64,
data: image.data,
kategorie: image.kategorie as Enums.BilderKategorie,
}, {
params: {
@@ -58,7 +58,7 @@ export async function bilderHochladen(
});
} else {
const response = await api.aufnahme._uid.bilder.PUT.fetch({
base64: image.base64,
data: image.data,
kategorie: image.kategorie as Enums.BilderKategorie
}, {
params: {

45
src/client/lib/helpers.ts Normal file
View File

@@ -0,0 +1,45 @@
import { writable, Writable } from "svelte/store";
import { ZodEffects, ZodNullable, ZodOptional, ZodType } from "zod";
export function localStorageSync<T>(initial: T, name: string, modifier: (stored: any) => T = (stored) => JSON.parse(stored), reverseModifier: (value: T) => string = (value) => JSON.stringify(value)): Writable<T> {
const stored = localStorage.getItem(name) as T
let value = initial;
if (stored) {
value = modifier(stored)
}
const writableStore = writable(value)
writableStore.subscribe((value) => {
const reversed = reverseModifier(value);
localStorage.setItem(name, reversed)
})
return writableStore
}
export function isZodInstanceOf<T extends ZodType<any>>(
schema: ZodType<any>,
targetType: new (...args: any) => T
): schema is T {
if (schema instanceof targetType) {
return true;
}
if (schema instanceof ZodOptional || schema instanceof ZodNullable) {
return isZodInstanceOf(schema._def.innerType, targetType);
}else if (schema instanceof ZodEffects) {
return getZodBaseType(schema._def.schema)
}
return false;
}
export function getZodBaseType(schema: ZodType<any>): ZodType<any> {
if (schema instanceof ZodOptional || schema instanceof ZodNullable) {
return getZodBaseType(schema._def.innerType);
} else if (schema instanceof ZodEffects) {
return getZodBaseType(schema._def.schema)
}
return schema;
}

View File

@@ -0,0 +1,138 @@
import { api } from "astro-typesafe-api/client"
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 "@ibcornelsen/database/client";
export async function nachweisSpeichern(
nachweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient,
objekt: ObjektClient,
aufnahme: AufnahmeClient,
bilder: BildClient[],
unterlagen: UnterlageClient[],
ausweisart: Enums.Ausweisart
) {
if (objekt.uid) {
await api.objekt._uid.PATCH.fetch({
...exclude(objekt, ["uid"])
}, {
params: {
uid: objekt.uid
},
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
} else {
const { uid } = await api.objekt.PUT.fetch({
...exclude(objekt, ["uid"])
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
objekt.uid = uid;
}
if (aufnahme.uid) {
await api.aufnahme._uid.PATCH.fetch({
...exclude(aufnahme, ["uid"]),
baujahr_gebaeude: aufnahme.baujahr_gebaeude || [],
baujahr_klima: aufnahme.baujahr_klima || [],
baujahr_heizung: aufnahme.baujahr_heizung || [],
}, {
params: {
uid: aufnahme.uid
},
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
} else {
const { uid } = await api.aufnahme.PUT.fetch({
aufnahme,
uid_objekt: objekt.uid
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
aufnahme.uid = uid
}
let patchRoute: any;
let putRoute: any;
if (ausweisart == Enums.Ausweisart.GEGNachweisWohnen) {
patchRoute = api["geg-nachweis-wohnen"]._uid.PATCH
putRoute = api["geg-nachweis-wohnen"].PUT
} else if (ausweisart === Enums.Ausweisart.GEGNachweisGewerbe) {
patchRoute = api["geg-nachweis-gewerbe"]._uid.PATCH
putRoute = api["geg-nachweis-gewerbe"].PUT
}
if (nachweis.uid) {
await patchRoute.fetch({
...exclude(nachweis, ["uid"])
}, {
params: {
uid: nachweis.uid
},
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
} else {
const { uid } = await putRoute.fetch({
nachweis,
uid_aufnahme: aufnahme.uid
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
nachweis.uid = uid;
}
await api.aufnahme._uid.bilder.PUT.fetch(bilder.map(bild => bild.uid), {
params: {
uid: aufnahme.uid
},
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
return {
uid_nachweis: nachweis.uid,
uid_aufnahme: aufnahme.uid,
uid_objekt: objekt.uid
}
// await client.v1.tickets.erstellen.mutate({
// titel: "Ausweis konnte nicht gespeichert werden",
// beschreibung: e.stack,
// email: user.email ?? "",
// metadata: JSON.stringify({
// ausweis,
// }),
// });
// addNotification({
// dismissable: false,
// message:
// "Ausweis konnte nicht gespeichert werden, bitte versuchen sie es erneut.",
// subtext:
// "Sollte das Problem weiterhin bestehen, kontaktieren sie bitte den Support.",
// timeout: 6000,
// type: "error",
// });
return null;
}

View File

@@ -39,6 +39,7 @@ export async function validateAccessTokenClient() {
refreshToken
})
Cookies.set(API_ACCESS_TOKEN_COOKIE_NAME, newAccessToken, {
domain: `.${window.location.hostname}`,
path: "/",

View File

@@ -11,12 +11,12 @@
export let ausweisart: Enums.Ausweisart
</script>
<button class="border-2 rounded-lg bg-white text-center hover:shadow-md no-underline p-3 cursor-pointer" on:click={() => {
<button class="border-2 rounded-lg bg-white text-center hover:shadow-md no-underline p-3 cursor-pointer" type="button" on:click={() => {
openWindowWithPost("/pdf/ansichtsausweis", {
ausweis: JSON.stringify(ausweis),
aufnahme: JSON.stringify(aufnahme),
objekt: JSON.stringify(objekt),
bilder: JSON.stringify(bilder),
ausweis: ausweis,
aufnahme: aufnahme,
objekt: objekt,
bilder: bilder,
ausweisart
})
}}>

View File

@@ -14,13 +14,15 @@
ObjektClient,
VerbrauchsausweisGewerbeClient,
VerbrauchsausweisWohnenClient,
GEGNachweisWohnenClient,
} from "./types.js";
export let objekt: ObjektClient;
export let ausweis:
| VerbrauchsausweisWohnenClient
| VerbrauchsausweisGewerbeClient
| BedarfsausweisWohnenClient;
| BedarfsausweisWohnenClient
| GEGNachweisWohnenClient;
export let aufnahme: AufnahmeClient;
export let ausweisart: Enums.Ausweisart;
@@ -46,7 +48,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
data-cy="ausstellgrund"
>
<option disabled selected value={false}>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}
@@ -70,9 +72,9 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
bind:value={aufnahme.gebaeudetyp}
>
<option disabled selected>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
{#if ausweisart==Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisVerbrauchsausweisWohnen}
{#if ausweisart==Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisWohnen}
<option value="Einfamilienhaus">Einfamilienhaus</option>
<option value="Freistehendes Einfamilienhaus">Freistehendes Einfamilienhaus</option>
<option value="Freistehendes Zweifamilienhaus">Freistehendes Zweifamilienhaus</option>
@@ -222,7 +224,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
bind:value={aufnahme.saniert}
>
<option disabled selected>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

@@ -1,56 +0,0 @@
<script lang="ts">
import HelpLabel from "#components/labels/HelpLabel.svelte";
import Inputlabel from "#components/labels/InputLabel.svelte";
import ZipSearch from "#components/PlzSuche.svelte";
import { Bezahlmethoden, Enums } from "@ibcornelsen/database/client";
import PaymentOption from "#components/PaymentOption.svelte";
export let selectedPaymentType: Bezahlmethoden =
Enums.Bezahlmethoden.paypal;
</script>
<div id="bezahlung" class="bereich-box grid
grid-cols-5 justify-around justify-items-center items-center">
<PaymentOption
paymentType={Enums.Bezahlmethoden.paypal}
bind:selectedPaymentType
name={"PayPal"}
icon={"/images/paypal.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.sofort}
bind:selectedPaymentType
name={"Sofort"}
icon={"/images/sofort.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.giropay}
bind:selectedPaymentType
name={"Giropay"}
icon={"/images/giropay.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.creditcard}
bind:selectedPaymentType
name={"Kreditkarte"}
icon={"/images/creditcard.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.rechnung}
bind:selectedPaymentType
name={"Rechnung"}
icon={"/images/rechnung.png"}
></PaymentOption>
</div>

View File

@@ -1,6 +1,4 @@
<script lang="ts">
import Hilfe from "#components/Ausweis/Hilfe.svelte";
export let spaeterWeitermachen;
export let automatischAusfüllen;
</script>
@@ -18,13 +16,6 @@ sm:grid-cols-[1fr_min-content_min-content_min-content] sm:justify-self-end sm:mt
>Automatisch Ausfüllen
</button>
<Hilfe />
<button class="button" type="button" on:click={spaeterWeitermachen}
>Später Weitermachen
</button>
</div>

View File

@@ -1,39 +1,37 @@
<script lang="ts">
import Hilfe from "#components/Ausweis/Hilfe.svelte";
import { ausweisSpeichern } from "#client/lib/ausweisSpeichern.js";
import { validateAccessTokenClient } from "#client/lib/validateAccessToken.js";
import { AufnahmeClient, BedarfsausweisWohnenClient, BenutzerClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeClient, BedarfsausweisWohnenClient, BenutzerClient, GEGNachweisWohnenClient, ObjektClient, UnterlageClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import Overlay from "#components/Overlay.svelte";
import EmbeddedAuthFlowModule from "#modules/EmbeddedAuthFlowModule.svelte";
import { Enums } from "@ibcornelsen/database/client";
import { AusweisTyp, Enums } from "@ibcornelsen/database/client";
import { openWindowWithPost } from "#lib/helpers/window.js";
import { PRICES } from "#lib/constants.js";
import { nachweisSpeichern } from "#client/lib/nachweisSpeichern.js";
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient | GEGNachweisWohnenClient;
export let bilder: UploadedGebaeudeBild[];
export let unterlagen: UnterlageClient[];
export let user: BenutzerClient;
export let objekt: ObjektClient;
export let aufnahme: AufnahmeClient;
export let ausweisart: Enums.Ausweisart
export let showWeiter: boolean = true;
let ausweistyp: AusweisTyp = Enums.AusweisTyp.Standard;
async function ausweisAbschicken() {
loginAction = ausweisAbschicken
if (!await validateAccessTokenClient()) {
loginOverlayHidden = false;
return
}
loginOverlayHidden = true
const result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart);
if (result !== null) {
window.history.pushState(
{},
"",
`${location.pathname}?uid=${ausweis.uid}`
);
window.location.href = `/kundendaten?uid=${ausweis.uid}`;
}
openWindowWithPost("/kundendaten", {
ausweis,
objekt,
aufnahme,
bilder,
unterlagen,
ausweisart,
ausweistyp
}, "")
}
let loginAction: () => any = ausweisAbschicken;
@@ -47,7 +45,12 @@
loginOverlayHidden = true
const result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart);
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | null = null;
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)
}
if (result !== null) {
window.history.pushState(
@@ -56,10 +59,23 @@
`${location.pathname}?uid=${ausweis.uid}`
);
localStorage.clear()
window.location.href = `/speichern-erfolgreich?uid=${ausweis.uid}`
}
}
async function hilfeBestellen() {
openWindowWithPost("/kundendaten", {
ausweis,
objekt,
aufnahme,
bilder,
ausweisart,
ausweistyp
}, "")
}
let showHelp: boolean = false;
let loginOverlayHidden = true;
</script>
@@ -68,19 +84,100 @@ sm:grid-cols-[1fr_min-content_min-content_min-content] sm:justify-self-end sm:mt
<div></div>
<Hilfe />
<div>
<button class="button" type="button" on:click={() => (showHelp = !showHelp)}
>Hilfe anfordern</button
>
</div>
{#if showHelp}
<div class="col-start-1 row-start-2 col-span-4 mt-4">
<div
class="bereich-box grid relative
grid-cols-1 gap-x-4 gap-y-4
"
>
<div class="pr-12">
Gerne helfen wir Ihnen wenn Sie nicht weiterkommen oder Fragen
haben. Kurze Fragen zum Formular oder der Ausweisart werden
kostenfrei telefonisch unter <a href="tel:+4940209339850"
>040/209339850</a
> beantwortet (bis 5min). Sollten Sie Unterstützung bei der Erstellung
benötgen oder lieber die Arbeit von unserem Ingenieurbüro erledigen
lassen, bieten wir Ihnen folgende Hilfen an. Bitte treffen Sie Ihre
Auswahl und klicken auf weiter:
</div>
<hr class="m-0" />
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
<input
type="radio"
class=" accent-secondary w-[20px] h-[20px]"
id="Produkttb1"
value={Enums.AusweisTyp.Beratung}
name="Produkt"
bind:group={ausweistyp}
/>
<div class="justify-self-stretch">
Verbrauchsausweis online inkl. ausführlicher telefonischer
Beratung
</div>
<div class="text-right">
<b>{PRICES[ausweisart][Enums.AusweisTyp.Beratung]}</b> inkl. MwSt.
</div>
</div>
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
<input
type="radio"
class=" accent-secondary w-[20px] h-[20px]"
id="Produktof1"
value={Enums.AusweisTyp.Offline}
name="Produkt"
bind:group={ausweistyp}
/>
<div>
Verbrauchsausweis offline (Sie schicken uns 3
Verbrauchsabrechnungen zu)
</div>
<div class="text-right">
<b>{PRICES[ausweisart][Enums.AusweisTyp.Offline]}</b> inkl. MwSt.
</div>
</div>
<hr class="m-0" />
<button class="button" on:click={hilfeBestellen}>jetzt Hilfe bestellen</button>
<button
class="button absolute top-2 right-2 w-[30px] h-[30px] text-sm p-0"
type="button"
on:click={() => (showHelp = !showHelp)}>X</button
>
</div>
</div>
{/if}
<button class="button" type="button" on:click={spaeterWeitermachen}
>Später Weitermachen
</button>
{#if showWeiter}
<div>
<Overlay bind:hidden={loginOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm py-8">
<EmbeddedAuthFlowModule onLogin={loginAction}></EmbeddedAuthFlowModule>
<EmbeddedAuthFlowModule onLogin={loginAction} email={""}></EmbeddedAuthFlowModule>
</div>
</Overlay>
<button on:click={ausweisAbschicken} type="button" class="button" data-cy="weiter">Weiter</button>
</div>
{/if}
</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={false}>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
<option value={Enums.Heizungsstatus.NICHT_VORHANDEN}>nicht vorhanden</option>
<option value={Enums.Heizungsstatus.UNBEHEIZT}>unbeheizt</option>
<option value={Enums.Heizungsstatus.BEHEIZT}>beheizt</option>

View File

@@ -1,89 +0,0 @@
<script lang="ts">
import { PRICES } from "#lib/constants";
let showHelp: boolean = false;
</script>
<div>
<button class="button" type="button" on:click={() => (showHelp = !showHelp)}
>Hilfe anfordern</button>
</div>
{#if showHelp}
<div class="col-start-1 row-start-2 col-span-4 mt-4">
<div class="bereich-box grid relative
grid-cols-1 gap-x-4 gap-y-4
"
>
<div class="pr-12">
Gerne helfen wir Ihnen wenn Sie nicht weiterkommen oder Fragen
haben. Kurze Fragen zum Formular oder der Ausweisart werden
kostenfrei telefonisch unter <a href="tel:+4940209339850"
>040/209339850</a
> beantwortet (bis 5min). Sollten Sie Unterstützung bei der Erstellung
benötgen oder lieber die Arbeit von unserem Ingenieurbüro erledigen
lassen, bieten wir Ihnen folgende Hilfen an. Bitte treffen Sie Ihre
Auswahl und klicken auf weiter:
</div>
<hr class="m-0">
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
<input
type="radio"
class=" accent-secondary w-[20px] h-[20px]"
id="Produkttb1"
value="ptb"
name="Produkt"
/>
<div class="justify-self-stretch">
Verbrauchsausweis online inkl. ausführlicher telefonischer Beratung
</div>
<div class="text-right">
<b>{PRICES.VerbrauchsausweisWohnen[1]}</b> inkl. MwSt.
</div>
</div>
<div class="grid grid-cols-[30px_490px_200px_1fr] items-center">
<input
type="radio"
class=" accent-secondary w-[20px] h-[20px]"
id="Produktof1"
value="pof"
name="Produkt"
/>
<div>
Verbrauchsausweis offline (Sie schicken uns 3 Verbrauchsabrechnungen zu)
</div>
<div class="text-right">
<b>{PRICES.VerbrauchsausweisWohnen[2]}</b> inkl. MwSt.
</div>
</div>
<hr class="m-0">
<button class="button">jetzt Hilfe bestellen</button>
<button class="button absolute top-2 right-2 w-[30px] h-[30px] text-sm p-0" type="button" on:click={() => (showHelp = !showHelp)}>X</button>
</div>
</div>
{/if}

View File

@@ -29,7 +29,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
bind:value={aufnahme.gebaeudeteil}
required
>
<option disabled selected value={false}>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
<option value="Gesamtgebäude">Gesamtgebäude</option>
<option value="Wohnen">Wohnen</option>
</select>
@@ -79,7 +79,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
bind:value={aufnahme.lueftung}
>
<option disabled selected value={false}>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"
@@ -112,7 +112,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
bind:value={aufnahme.kuehlung}
>
<option disabled selected value={false}>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
<option value="1">vorhanden</option>
<option value="0">nicht vorhanden</option>
</select>

View File

@@ -30,8 +30,8 @@
</div>
<style lang="postcss">
<style lang="postcss">
.phase {
@apply grid grid-cols-1 items-center justify-items-center z-10;
.point {

View File

@@ -1,24 +1,30 @@
<script lang="ts">
import HelpLabel from "#components/labels/HelpLabel.svelte";
import Inputlabel from "#components/labels/InputLabel.svelte";
import ZipSearch from "#components/PlzSuche.svelte";
import { BenutzerClient, RechnungClient } from "./types.js";
export let user: BenutzerClient;
export let rechnung: Partial<RechnungClient>;
$: {
if (!rechnung.abweichende_versand_adresse) {
rechnung.versand_empfaenger = rechnung.empfaenger
rechnung.versand_ort = rechnung.ort
rechnung.versand_plz = rechnung.plz
rechnung.versand_strasse = rechnung.strasse
rechnung.versand_zusatzzeile = rechnung.zusatzzeile
}
}
</script>
<div id="rechnungsadresse" class="bereich-box grid
<div
id="rechnungsadresse"
class="bereich-box grid
grid-cols-1 gap-x-4 gap-y-8
sm:grid-cols-2 sm:gap-x-6 sm:gap-y-8
xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
">
"
>
<!-- Empfänger * -->
<div class="input-standard order-1 md:order-1 xl:order-1">
@@ -35,7 +41,8 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie den Empfänger ein, auf den die Rechnung ausgestellt wird.
Bitte geben Sie den Empfänger ein, auf den die Rechnung
ausgestellt wird.
</HelpLabel>
</div>
</div>
@@ -56,7 +63,8 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie die Strasse und Hausnummer, so wie Sie auf der Rechnung erscheinen soll, ein.
Bitte geben Sie die Strasse und Hausnummer, so wie Sie auf der
Rechnung erscheinen soll, ein.
</HelpLabel>
</div>
</div>
@@ -64,7 +72,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<!-- PLZ / ORT -->
<div class="grid grid-cols-[2fr_4fr] gap-x-4 order-3 md:order-3 xl:order-3">
<div class="input-noHelp">
<Inputlabel title="PLZ *"></Inputlabel>
<ZipSearch
@@ -72,8 +79,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
bind:zip={rechnung.plz}
bind:city={rechnung.ort}
/>
</div>
<div class="input-standard">
@@ -81,7 +86,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<input
name="rechnung_ort"
readonly
type="text"
required
value={rechnung.ort}
@@ -89,11 +93,11 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie die PLZ des Ortes, so wie Sie auf der Rechnung erscheinen soll, ein.
Bitte geben Sie die PLZ des Ortes, so wie Sie auf der
Rechnung erscheinen soll, ein.
</HelpLabel>
</div>
</div>
</div>
<!-- Zusatzzeile -->
@@ -111,7 +115,8 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie, falls erforderlich, zusätzliche nformationen ein.
Bitte geben Sie, falls erforderlich, zusätzliche nformationen
ein.
</HelpLabel>
</div>
</div>
@@ -121,11 +126,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="input-standard order-5 md:order-5 xl:order-5">
<Inputlabel title="E-mail *"></Inputlabel>
<input
name="rechnung_email"
bind:value={rechnung.email}
type="email"
/>
<input name="rechnung_email" bind:value={rechnung.email} type="email" />
<div class="help-label">
<HelpLabel>
@@ -154,9 +155,9 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
-->
<div class="col-span-3 order-7 md:order-7 xl:order-7">
<div class="grid grid-cols-[25px_max-content] items-center justify-items-start">
<div
class="grid grid-cols-[25px_max-content] items-center justify-items-start"
>
<input
id="abweichende_versand_adresse"
class="w-[15px] h-[15px]"
@@ -166,14 +167,12 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
/>
<label for="abweichende_versand_adresse" class="cursor-pointer"
>abweichende Versandadresse</label>
>abweichende Versandadresse</label
>
</div>
</div>
{#if rechnung.abweichende_versand_adresse}
<!-- Versand Empfänger * -->
<div class="input-standard order-8 md:order-8 xl:order-8">
@@ -213,15 +212,17 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie die Versand-Empfänger Strasse und Hausnummer ein, an die die Rechnung versandt wird.
Bitte geben Sie die Versand-Empfänger Strasse und Hausnummer
ein, an die die Rechnung versandt wird.
</HelpLabel>
</div>
</div>
<!-- PLZ / ORT -->
<div class="grid grid-cols-[2fr_4fr] gap-x-4 order-10 md:order-10 xl:order-10">
<div
class="grid grid-cols-[2fr_4fr] gap-x-4 order-10 md:order-10 xl:order-10"
>
<div class="input-noHelp">
<Inputlabel title="PLZ *"></Inputlabel>
<ZipSearch
@@ -230,8 +231,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
bind:zip={rechnung.versand_plz}
bind:city={rechnung.versand_ort}
/>
</div>
<div class="input-standard">
@@ -247,11 +246,11 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie die Versand-Empfänger PLZ des Ortes ein, an den die Rechnung versandt wird.
Bitte geben Sie die Versand-Empfänger PLZ des Ortes ein,
an den die Rechnung versandt wird.
</HelpLabel>
</div>
</div>
</div>
<!-- Zusatzzeile -->
@@ -270,7 +269,8 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie, falls erforderlich, zusätzliche nformationen ein.
Bitte geben Sie, falls erforderlich, zusätzliche
nformationen ein.
</HelpLabel>
</div>
</div>
@@ -288,7 +288,8 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="help-label">
<HelpLabel>
Bitte geben Sie die E-Mail Adresse des Versand-Empfängers ein.
Bitte geben Sie die E-Mail Adresse des Versand-Empfängers
ein.
</HelpLabel>
</div>
</div>
@@ -311,7 +312,5 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
</div>
</div>
-->
{/if}
</div>

View File

@@ -6,21 +6,14 @@
import VerbrauchsHelpLabel from "#components/labels/VerbrauchsHelpLabel.svelte";
import StromVerbrauchsHelpLabel from "#components/labels/StromVerbrauchsHelpLabel.svelte";
import SanierungsOption from "#components/Ausweis/SanierungsOption.svelte"
import Label from "../Label.svelte";
import moment from "moment";
import fuelList from "./brennstoffListe.js";
import { auditVerbrauchAbweichung } from "../Verbrauchsausweis/audits/VerbrauchAbweichung.js";
import {
AufnahmeClient,
ObjektClient,
VerbrauchsausweisGewerbeClient,
} from "./types.js";
import { addNotification } from "#components/Notifications/shared.js";
export let objekt: ObjektClient;
export let aufnahme: AufnahmeClient;
export let ausweis: VerbrauchsausweisGewerbeClient;
@@ -70,8 +63,8 @@
fuelMap[fuel[0]].push(fuel[1]);
}
let month = ausweis.startdatum?.getMonth();
let year = ausweis.startdatum?.getFullYear();
let month = moment(ausweis.startdatum).month();
let year = moment(ausweis.startdatum).year();
$: {
if (typeof month === "number" && typeof year === "number") {
@@ -86,6 +79,11 @@
}
}
$: {
console.log(aufnahme.brennstoff_1);
}
$: abweichung = auditVerbrauchAbweichung(ausweis, aufnahme);
</script>
@@ -216,7 +214,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<div class="grid grid-cols-2 gap-x-4 order-3 md:order-3 xl:order-3">
<div class="input-standard">
<Inputlabel title="primär Brennstoff *"></Inputlabel>
<Inputlabel title="primärer Brennstoff *"></Inputlabel>
<select
class="rounded-e-none"
@@ -225,7 +223,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
bind:value={aufnahme.brennstoff_1}
required
>
<option disabled selected value={false}>Bitte auswählen</option>
<option disabled selected value={null}>Bitte auswählen</option>
{#each Object.keys(fuelMap) as fuel}
<option value={fuel}>{fuel}</option>
{/each}
@@ -258,7 +256,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
disabled={!aufnahme.brennstoff_1}
required
>
<option disabled selected value={false}>Bitte auswählen</option>
<option disabled selected >Bitte auswählen</option>
{#each fuelMap.hasOwnProperty(aufnahme.brennstoff_1) ? fuelMap[aufnahme.brennstoff_1] : [] as unit}
<option value={unit}>{unit}</option>
{/each}
@@ -407,7 +405,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
bind:value={aufnahme.brennstoff_2}
required
>
<option disabled selected value={false}
<option disabled selected
>Bitte auswählen</option
>
{#each Object.keys(fuelMap) as fuel}
@@ -442,7 +440,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
disabled={!aufnahme.brennstoff_2}
required
>
<option disabled selected value={false}
<option disabled selected
>Bitte auswählen</option
>
{#each fuelMap.hasOwnProperty(aufnahme.brennstoff_2) ? fuelMap[aufnahme.brennstoff_2] : [] as unit}
@@ -644,11 +642,11 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<!-- Enthält Stromverbrauch für: -->
<SanierungsOption label="Heizung" name="stromverbrauch_enthaelt_heizung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_heizung}></SanierungsOption>
<SanierungsOption label="Warmwasser " name="stromverbrauch_enthaelt_warmwasser" help="" bind:checked={ausweis.stromverbrauch_enthaelt_warmwasser}></SanierungsOption>
<SanierungsOption label="Lüftung " name="stromverbrauch_enthaelt_lueftung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_lueftung}></SanierungsOption>
<SanierungsOption label="Beleuchtung" name="stromverbrauch_enthaelt_beleuchtung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_beleuchtung}></SanierungsOption>
<SanierungsOption label="Kühlung" name="stromverbrauch_enthaelt_kuehlung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_kuehlung}></SanierungsOption>
<SanierungsOption value="" label="Heizung" name="stromverbrauch_enthaelt_heizung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_heizung}></SanierungsOption>
<SanierungsOption value="" label="Warmwasser " name="stromverbrauch_enthaelt_warmwasser" help="" bind:checked={ausweis.stromverbrauch_enthaelt_warmwasser}></SanierungsOption>
<SanierungsOption value="" label="Lüftung " name="stromverbrauch_enthaelt_lueftung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_lueftung}></SanierungsOption>
<SanierungsOption value="" label="Beleuchtung" name="stromverbrauch_enthaelt_beleuchtung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_beleuchtung}></SanierungsOption>
<SanierungsOption value="" label="Kühlung" name="stromverbrauch_enthaelt_kuehlung" help="" bind:checked={ausweis.stromverbrauch_enthaelt_kuehlung}></SanierungsOption>
<div class="input-standard">
<Inputlabel title="Sonstige"></Inputlabel>

View File

@@ -117,14 +117,14 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
Verbräuche öffnet sich dann.</HelpLabel>
</div>
</div>
{#if !ausweis.zusaetzliche_heizquelle}
<div class="input-standard">
<div class="input-checkboxen">
<div
class="grid grid-cols-[25px_max-content] items-center justify-items-start"
>
{#if !ausweis.zusaetzliche_heizquelle}
<input
id="zusaetzliche_heizquelle_1"
type="checkbox"
@@ -137,7 +137,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
for="zusaetzliche_heizquelle_1"
class="cursor-pointer">zusätzliche Heizquelle</label
>
{/if}
</div>
</div>
<div class="help-label">
@@ -145,6 +144,8 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
gemacht werden, da alle 3 Verbrauchsjahre zusammenhängend sein sollen.</HelpLabel>
</div>
</div>
{/if}
</div>
@@ -235,7 +236,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
bind:value={aufnahme.brennstoff_1}
required
>
<option disabled selected value={false}>Bitte auswählen</option>
<option disabled selected >Bitte auswählen</option>
{#each Object.keys(fuelMap) as fuel}
<option value={fuel}>{fuel}</option>
{/each}
@@ -275,7 +276,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
disabled={!aufnahme.brennstoff_1}
required
>
<option disabled selected value={false}>Bitte auswählen</option>
<option disabled selected >Bitte auswählen</option>
{#each fuelMap.hasOwnProperty(aufnahme.brennstoff_1) ? fuelMap[aufnahme.brennstoff_1] : [] as unit}
<option value={unit}>{unit}</option>
{/each}
@@ -430,7 +431,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
required
data-cy="brennstoff_2"
>
<option disabled selected value={false}
<option disabled selected
>Bitte auswählen</option
>
{#each Object.keys(fuelMap) as fuel}
@@ -473,7 +474,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
disabled={!aufnahme.brennstoff_2}
required
>
<option disabled selected value={false}
<option disabled selected
>Bitte auswählen</option
>
{#each fuelMap.hasOwnProperty(aufnahme.brennstoff_2) ? fuelMap[aufnahme.brennstoff_2] : [] as unit}

View File

@@ -17,8 +17,8 @@ import { z, ZodSchema } from "zod";
export type OmitKeys<T, K extends keyof T> = Omit<T, K>;
export type UploadedGebaeudeBild = OmitKeys<Bild, "id" | "objekt_id"> & {
base64: string
export type UploadedGebaeudeBild = OmitKeys<Bild, "id" | "aufnahme_id"> & {
data: string
}
/**
@@ -148,28 +148,31 @@ export function getAusweisartFromUUID(uid: string): Enums.Ausweisart | null {
return Enums.Ausweisart.BedarfsausweisGewerbe
} else if (uid.startsWith("gnw")) {
return Enums.Ausweisart.GEGNachweisWohnen
} else if (uid.startsWith("gng")) {
return Enums.Ausweisart.GEGNachweisGewerbe
}
return null;
}
export type UnterlageClient = Omit<Unterlage, "id" | "objekt_id">
export type BildClient = Omit<Bild, "id" | "objekt_id">
export type UnterlageClient = Omit<Unterlage, "id" | "aufnahme_id">
export type BildClient = Omit<Bild, "id" | "aufnahme_id">
export type ObjektKomplettClient = ObjektClient & {
bilder: BildClient[],
unterlagen: UnterlageClient[],
aufnahmen: (AufnahmeClient & {
bedarfsausweis_wohnen?: BedarfsausweisWohnenClient,
verbrauchsausweis_wohnen?: VerbrauchsausweisWohnenClient,
verbrauchsausweis_gewerbe?: VerbrauchsausweisGewerbeClient
})[]
aufnahmen: AufnahmeKomplettClient[]
}
export type AufnahmeKomplettClient = AufnahmeClient & {
bedarfsausweis_wohnen: BedarfsausweisWohnenClient[],
verbrauchsausweis_wohnen: VerbrauchsausweisWohnenClient[],
verbrauchsausweis_gewerbe: VerbrauchsausweisGewerbeClient[]
bilder: BildClient[],
unterlagen: UnterlageClient[],
bedarfsausweise_wohnen: BedarfsausweisWohnenClient[],
verbrauchsausweise_wohnen: VerbrauchsausweisWohnenClient[],
verbrauchsausweise_gewerbe: VerbrauchsausweisGewerbeClient[],
geg_nachweise_wohnen: GEGNachweisWohnenClient[]
}
export type GEGNachweisWohnenClient = Omit<GEGNachweisWohnen, "id" | "aufnahme_id" | "benutzer_id">
export type GEGNachweisWohnenClient = Omit<GEGNachweisWohnen, "id" | "aufnahme_id" | "benutzer_id"> & {
uid_objekt: string,
uid_aufnahme: string,
uid_benutzer?: string
}

View File

@@ -9,7 +9,7 @@
VerbrauchsausweisWohnenClient,
} from "./Ausweis/types.js";
import AusweisPruefenTooltip from "./AusweisPruefenTooltip.svelte";
import { addNotification } from "./NotificationProvider/shared.js";
import { addNotification } from "#components/Notifications/shared.js";
import { CheckCircled, CrossCircled, Image } from "radix-svelte-icons";
import ChevronDown from "radix-svelte-icons/src/lib/icons/ChevronDown.svelte";
import { Event } from "@ibcornelsen/database/client";
@@ -31,7 +31,7 @@
async function ausweisAusstellen(uid: string) {
try {
await api.admin.ausstellen.GET.fetch({
uid
uid_ausweis: uid
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
@@ -39,8 +39,8 @@
})
} catch(e) {
addNotification({
title: "Das hat nicht geklappt.",
description: e.cause.statusText,
message: "Das hat nicht geklappt.",
subtext: e as string,
timeout: 3000,
type: "error",
})
@@ -49,7 +49,7 @@
const ausweisArt = getAusweisartFromUUID(ausweis.uid) // TODO: Das ist ein Platzhalter, hier muss die Ausweisart aus dem Ausweisobjekt kommen
const ausweisArt = getAusweisartFromUUID(ausweis.uid)
let verbrauchWWGesamt_1 = "";
let verbrauchWWGesamt_2 = "";
@@ -124,12 +124,12 @@
let Abgeschlossen: any;
if (aufnahme.erledigt) {
if (ausweis.ausgestellt) {
Ausweisbild = "/images/dashboard/ausweishaken.jpg";
DatenBlattBild = "/images/dashboard/datenblatthaken.jpg";
StatusIcon = "/images/dashboard/erledigt.svg";
Abgeschlossen = 0;
} else if (aufnahme.bestellt) {
} else if (ausweis.bestellt) {
Ausweisbild = "/images/dashboard/ausweis.jpg";
DatenBlattBild = "/images/dashboard/datenblatt.jpg";
StatusIcon = "/images/dashboard/bestellt.svg";
@@ -147,7 +147,7 @@
symbolPruefung = "/images/dashboard/kreiskreuz.png";
}
if (aufnahme.zurueckgestellt) {
if (ausweis.zurueckgestellt) {
zurueckGestellt =
"<img src='/images/dashboard/zurueckGestellt.svg' alt='Status' width=\"25\" height=\"25\"></img>";
} else {
@@ -456,16 +456,33 @@
// }
async function stornieren(ausweis: VerbrauchsausweisWohnenClient) {
try {
const response = await api.admin.stornieren.PUT.fetch({
uid_ausweis: ausweis.uid
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
addNotification({
title: "Ausweis wurde storniert",
message: "Ausweis wurde storniert",
type: "success",
dismissable: true,
timeout: 3000,
})
ausweis.aufnahme.storniert = true;
ausweis.storniert = true;
ausweis = ausweis;
} catch(e) {
addNotification({
message: "Ausweis konnte nicht storniert werden.",
subtext: e as string,
type: "error",
dismissable: true,
timeout: 3000,
})
}
}
let bilderModal: HTMLDialogElement;
@@ -473,6 +490,7 @@
async function registriernummerAnfordern(uid: string) {
try {
const result = await api.admin.registriernummer.GET.fetch({
uid
}, {
@@ -480,6 +498,15 @@
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
} catch(e) {
addNotification({
message: "Registriernummer anfordern fehlgeschlagen.",
subtext: e as string,
type: "error",
dismissable: true,
timeout: 3000,
})
}
}
</script>
@@ -909,4 +936,4 @@
</div>
</div>
<NotificationWrapper></NotificationWrapper>
<NotificationWrapper />

View File

@@ -0,0 +1,68 @@
<script lang="ts">
import { getZodBaseType } from "#client/lib/helpers.js";
import { filterAusweise } from "#lib/filters.js";
import { ZodTypeAny } from "astro:schema";
import { Cross1 } from "radix-svelte-icons";
import z, { ZodBoolean, ZodNativeEnum, ZodNumber } from "zod"
export let filters: { name: keyof z.infer<typeof filterAusweise>, type: ZodTypeAny, value: any }[] = []
</script>
{#each filters as filter, i}
{@const type = getZodBaseType(filter.type)}
<div class="flex flex-row bg-white gap-4 px-2 py-2 rounded-lg">
{#if i === 0}
<span class="badge">where</span>
{:else}
<span class="badge">and</span>
{/if}
<select on:change={function(e) {
delete filters[filter.name]
filter.name = e.target.value;
filter.type = filterAusweise._def.shape()[filter.name]
filters = filters.filter(Boolean);
}}>
<option value={filter.name} selected>{filter.name}</option>
{#each Object.keys(filterAusweise._def.shape()) as n}
{#if !filters.find(filter => filter.name === n)}
<option value={n}>{n}</option>
{/if}
{/each}
</select>
<span class="badge">equals</span>
{#if type instanceof ZodNumber}
<input type="number" bind:value={filter.value}>
{:else if type instanceof ZodBoolean}
<select bind:value={filter.value}>
<option value={true}>true</option>
<option value={false}>false</option>
</select>
{:else if type instanceof ZodNativeEnum}
<select bind:value={filter.value}>
{#each Object.entries(type._def.values) as [key, value]}
<option {value}>{key}</option>
{/each}
</select>
{:else}
<input type="text" bind:value={filter.value}>
{/if}
<Cross1 size={24} class="cursor-pointer"></Cross1>
</div>
{/each}
<button on:click={() => {
const entry = Object.entries(filterAusweise._def.shape())[0]
filters.push({
name: entry[0],
type: entry[1],
value: null
})
filters = filters
}}>Filter Hinzufügen</button>
<style>
.badge {
@apply rounded-lg px-2 py-1 bg-gray-500 text-white;
}
</style>

View File

@@ -13,11 +13,11 @@
import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
import { Enums, Objekt } from "@ibcornelsen/database/client";
export let ausweis: VerbrauchsausweisWohnenClient;
export let aufnahme: AufnahmeKomplettClient;
export let objekt: ObjektKomplettClient;
export let objekt: Objekt;
export let progress: number;
const ausweisart = getAusweisartFromUUID(ausweis.uid);
@@ -188,14 +188,14 @@
</div>
</div>
{/await}
<div class="card-actions justify-end mt-8">
<div class="flex flex-row justify-end gap-4 mt-4">
<a
class="btn btn-primary"
href="/energieausweis-erstellen/verbrauchsausweis-wohnen?uid={ausweis.uid}"
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid={ausweis.uid}"
>Bearbeiten</a
>
<a
class="btn btn-ghost"
class="p-2 rounded-lg hover:bg-gray-200"
title="PDF Herunterladen"
target="_blank"
href="/pdf/ansichtsausweis?uid={ausweis.uid}"
@@ -219,8 +219,8 @@
</p>
<p>
Falls sie dort nicht finden wonach sie suchen, rufen sie uns doch
unter <a href="tel:040-220-31-87">040 220 31 87</a> an oder
<a href="mailto:moritz.utcke@gmx.de">schreiben sie uns eine email</a
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>

View File

@@ -1,3 +1,5 @@
<script lang="ts"></script>
<div class="card lg:card-side bg-base-200 card-bordered border-base-300">
<figure class="lg:w-1/2 min-h-72 skeleton"></figure>
<div class="card-body lg:w-1/2">

View File

@@ -5,24 +5,40 @@
import { File, OpenInNewWindow } from "radix-svelte-icons";
export let objekt: ObjektKomplettClient;
// TODO
const objektBild = objekt.bilder.find(bild => bild.kategorie === Enums.BilderKategorie.Gebaeude);
</script>
<div class="border rounded-lg border-base-300 bg-white">
{#if objektBild}
<img src="/bilder/{objektBild.uid}.webp" class="w-full max-h-72 object-cover rounded-t-lg" alt="Gebäude">
<div class="border rounded-lg border-base-300 bg-white break-inside-avoid-column mb-4">
{#if objekt.aufnahmen.length > 0}
{@const bild = objekt.aufnahmen[0].bilder.find(bild => bild.kategorie === Enums.BilderKategorie.Gebaeude)}
{#if bild}
<img src="/bilder/{bild.uid}.webp" class="w-full max-h-72 object-cover rounded-t-lg" alt="Gebäude">
{/if}
{/if}
<div class="p-4">
<div class="flex flex-row justify-between">
<h3 class="text-lg font-medium">{objekt.adresse}</h3>
<div class="flex flex-row justify-between items-center">
<h3 class="text-lg font-medium">{objekt.adresse}, {objekt.plz} {objekt.ort}</h3>
<span class="text-sm opacity-70 font-medium">{moment(objekt.erstellungsdatum).format("DD.MM.YYYY")}</span>
</div>
<div class="flex flex-row justify-end">
<a href="/dashboard/objekt/{objekt.uid}" class="rounded-lg p-2.5 hover:bg-gray-200" target="_blank"><OpenInNewWindow size={20}></OpenInNewWindow></a>
<div class="flex flex-col gap-2 mt-4">
{#each objekt.aufnahmen as aufnahme}
<div class="border rounded-lg px-4 py-2">
<div class="flex flex-row justify-between items-center">
<span>Sanierungsstand vom {moment(aufnahme.erstellungsdatum).format("DD.MM.YYYY")}</span>
<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}
<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}
<a href="/dashboard/aufnahme/{aufnahme.uid}" class="rounded-lg p-2 hover:bg-gray-100 transition-all"><File size={20}></File></a>
{/if}
</div>
</div>
{/each}
</div>
</div>
</div>

View File

@@ -46,16 +46,12 @@
/></a
>
<div class="menu flex flex-col gap-2 mt-0 md:mt-12 px-0">
<div class="flex flex-col gap-2 mt-0 md:mt-12 px-0">
<a use:ripple={rippleOptions} class="button-tab" href="/dashboard">
<Home width={22} height={22} />
Home
</a>
<a use:ripple={rippleOptions} class="button-tab" href="/dashboard/ausweise">
<Reader width={22} height={22} />
Ausweise
Objekte
</a>
<button use:ripple={rippleOptions} class="button-tab">
<!-- <button use:ripple={rippleOptions} class="button-tab">
<EnvelopeClosed width={22} height={22} />
Kontakt
</button>
@@ -75,7 +71,7 @@
</button>
</li>
</ul>
</details></li>
</details></li> -->
{#if benutzer.rolle === "ADMIN"}
<li><details class="[&_.caret]:open:rotate-180">
<summary class="button-tab w-full outline-0 hover:outline-0 cursor-pointer">

View File

@@ -14,12 +14,12 @@
</script>
<button class="border-2 rounded-lg bg-white text-center hover:shadow-md no-underline p-3 cursor-pointer" on:click={() => {
<button class="border-2 rounded-lg bg-white text-center hover:shadow-md no-underline p-3 cursor-pointer" type="button" on:click={() => {
openWindowWithPost("/pdf/datenblatt", {
ausweis: JSON.stringify(ausweis),
aufnahme: JSON.stringify(aufnahme),
objekt: JSON.stringify(objekt),
bilder: JSON.stringify(bilder),
ausweis: ausweis,
aufnahme: aufnahme,
objekt: objekt,
bilder: bilder,
ausweisart
})
}}>

View File

@@ -1,16 +1,17 @@
<script lang="ts">
import { BedarfsausweisWohnenClient, ObjektClient, UnterlageClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
import { BedarfsausweisWohnenClient, GEGNachweisWohnenClient, ObjektClient, UnterlageClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
import { Trash, Upload } from "radix-svelte-icons";
import HelpLabel from "#components/labels/HelpLabel.svelte";
export let kategorie: string = "";
export let files: (UnterlageClient & { data: string | ArrayBuffer })[] = [];
export let files: UnterlageClient[] = [];
export let max: number = Infinity;
export let min: number = 1;
export let name: string = "";
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient | GEGNachweisWohnenClient;
export let objekt: ObjektClient;
import mime from "mime-types";
import { api } from "astro-typesafe-api/client";
function getAllFiles(this: HTMLInputElement) {
@@ -30,7 +31,7 @@
const reader = new FileReader();
reader.onload = () => {
reader.onload = async () => {
if (reader.readyState != reader.DONE) {
return;
}
@@ -41,7 +42,14 @@
const mimeType = mime.types[file.name.split(".").pop() as string]
files.push({ data: reader.result, kategorie, name: file.name, mime: mimeType });
const { uid } = await api.unterlage.PUT.fetch({
data: reader.result as string,
kategorie,
mime: mimeType,
name: file.name
})
files.push({ uid, kategorie, name: file.name, mime: mimeType });
files = files;
@@ -50,7 +58,7 @@
}
}
reader.readAsArrayBuffer(file);
reader.readAsDataURL(file);
}
}

View File

@@ -0,0 +1,287 @@
<script lang="ts">
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";
import { Enums } from "@ibcornelsen/database/client";
import {
AufnahmeClient,
ObjektClient,
GEGNachweisWohnenClient,
} from "../Ausweis/types.js";
export let objekt: ObjektClient;
export let ausweis:
GEGNachweisWohnenClient;
export let aufnahme: AufnahmeClient;
export let ausweisart: Enums.Ausweisart;
</script>
<div id="ausweisart" class="bereich-box grid
grid-cols-1 gap-x-4 gap-y-8
sm:grid-cols-2 sm:gap-x-6 sm:gap-y-8
xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
"
>
<!-- Anlass für Energieausweis -->
<div class="input-standard order-1 md:order-1 xl:order-1">
<Inputlabel title="Anlass *"></Inputlabel>
<select
id="ausstellgrund"
class="rounded-e-none"
name="ausstellgrund"
placeholder="Anlass"
bind:value={ausweis.ausstellgrund}
required
data-cy="ausstellgrund"
>
<option disabled selected value={null}>Bitte auswählen</option>
<option value={Enums.Ausstellgrund.Neubau}>Neubau</option>
<option value={Enums.Ausstellgrund.Modernisierung}>Modernisierung</option>
</select>
<div class="help-label">
<HelpLabel>Bitte wählen Sie aus wofür Sie den Energieausweis benötigen.
<strong>Vermietung, Verkauf oder sonstiges (z.B. zur Vorlage bei der Bank) ist als Anlass für den Verbrauchsausweis zulässig.</strong>
Neubau oder Modernisierung ist Sie hier nicht zulässig.</HelpLabel>
</div>
</div>
<!-- Gebäudetyp -->
<div class="input-standard order-2 md:order-3 xl:order-2">
<Inputlabel title="Gebäudetyp *"></Inputlabel>
<select
name="gebaeudetyp"
data-test="gebaeudetyp"
required
bind:value={aufnahme.gebaeudetyp}
>
<option disabled selected value={null}>Bitte auswählen</option>
{#if ausweisart === Enums.Ausweisart.GEGNachweisWohnen}
<option value="Einfamilienhaus">Einfamilienhaus</option>
<option value="Freistehendes Einfamilienhaus">Freistehendes Einfamilienhaus</option>
<option value="Freistehendes Zweifamilienhaus">Freistehendes Zweifamilienhaus</option>
<option value="Doppelhaushälfte">Doppelhaushälfte</option>
<option value="Reihenendhaus">Reihenendhaus</option>
<option value="Reihenmittelhaus">Reihenmittelhaus</option>
<option value="Mehrfamilienhaus">Mehrfamilienhaus</option>
<option value="Wohn- und Geschäftshaus">Wohn- und Geschäftshaus</option>
<option value="Atrium-Bungalow">Atrium-Bungalow</option>
<option value="Winkelbungalow">Winkelbungalow</option>
{:else if ausweisart==Enums.Ausweisart.VerbrauchsausweisGewerbe}
<option value="Verwaltungsgebäude (allgemein)">Verwaltungsgebäude (allgemein)</option>
<option value="Parlaments- und Gerichtsgebäude">Parlaments- und Gerichtsgebäude</option>
<option value="Ministerien u. Ämter u. Behörden">Ministerien u. Ämter u. Behörden</option>
<option value="Polizeidienstgebäude">Polizeidienstgebäude</option>
<option value="Gebäude für öffentliche Bereitschaftsdienste">Gebäude für öffentliche Bereitschaftsdienste</option>
<option value="Feuerwehrdienstgebäude">Feuerwehrdienstgebäude</option>
<option value="Bürogebäude">Bürogebäude</option>
<option value="Bürogebäude - überwiegend Großraumbüros">Bürogebäude - überwiegend Großraumbüros</option>
<option value="Bankgebäude">Bankgebäude</option>
<option value="Hochschule und Forschung (allgemein)">Hochschule und Forschung (allgemein)</option>
<option value="Gebäude für Lehre">Gebäude für Lehre</option>
<option value="Institute für Lehre und Forschung">Institute für Lehre und Forschung</option>
<option value="Gebäude für Forschung ohne Lehre">Gebäude für Forschung ohne Lehre</option>
<option value="Laborgebäude">Laborgebäude</option>
<option value="Gesundheitswesen (allgemein)">Gesundheitswesen (allgemein)</option>
<option value="Krankenhäuser (ohne Forschung und Lehre)">Krankenhäuser (ohne Forschung und Lehre)</option>
<option value="Krankenhäuser (ohne Forschung und Lehre) &amp; teilstationäre Versorgung">Krankenhäuser (ohne Forschung und Lehre) &amp; teilstationäre Versorgung</option>
<option value="Medizinische Einrichtungen für nicht stationäre Versorgung">Medizinische Einrichtungen für nicht stationäre Versorgung</option>
<option value="Gebäude für Reha">Gebäude für Reha</option>
<option value="Bildungseinrichtungen (allgemein)">Bildungseinrichtungen (allgemein)</option>
<option value="Schulen">Schulen</option>
<option value="Kinderbetreuungseinrichtungen">Kinderbetreuungseinrichtungen</option>
<option value="Kultureinrichtungen (allgemein)">Kultureinrichtungen (allgemein)</option>
<option value="Bibliotheken/Archive">Bibliotheken/Archive</option>
<option value="Ausstellungsgebäude">Ausstellungsgebäude</option>
<option value="Veranstaltungsgebäude">Veranstaltungsgebäude</option>
<option value="Gemeinschafts-/Gemeindehäuser">Gemeinschafts-/Gemeindehäuser</option>
<option value="Opern/Theater">Opern/Theater</option>
<option value="Sporteinrichtungen (allgemein)">Sporteinrichtungen (allgemein)</option>
<option value="Sporthallen">Sporthallen</option>
<option value="Fitnessstudios">Fitnessstudios</option>
<option value="Schwimmhallen">Schwimmhallen</option>
<option value="Gebäude für Sportaußenanlagen">Gebäude für Sportaußenanlagen</option>
<option value="Verpflegungseinrichtungen (allgemein)">Verpflegungseinrichtungen (allgemein)</option>
<option value="Beherbergungsstätten (allgemein)">Beherbergungsstätten (allgemein)</option>
<option value="Hotels/Pensionen">Hotels/Pensionen</option>
<option value="Jugendherbergen u. Ferienhäuser">Jugendherbergen u. Ferienhäuser</option>
<option value="Gaststätten">Gaststätten</option>
<option value="Mensen u. Kantinen">Mensen u. Kantinen</option>
<option value="Gewerbliche und industrielle Gebäude (allgemein)">Gewerbliche und industrielle Gebäude (allgemein)</option>
<option value="Gewerbliche und industrielle Gebäude - schwere Arbeit">Gewerbliche und industrielle Gebäude - schwere Arbeit</option>
<option value="Gewerbliche und industrielle Gebäude - Mischung aus leichter u. schwerer Arbeit">Gewerbliche und industrielle Gebäude - Mischung aus leichter u. schwerer Arbeit</option>
<option value="Gewerbliche und industrielle Gebäude - leichte Arbeit">Gewerbliche und industrielle Gebäude - leichte Arbeit</option>
<option value="Gebäude für Lagerung">Gebäude für Lagerung</option>
<option value="Verkaufsstätten (allgemein)">Verkaufsstätten (allgemein)</option>
<option value="Kaufhäuser">Kaufhäuser</option>
<option value="Kaufhauszentren/Einkaufszentren">Kaufhauszentren/Einkaufszentren</option>
<option value="Märkte">Märkte</option>
<option value="Märkte mit sehr hohem Anteil von Kühlung für Lebensmittel">Märkte mit sehr hohem Anteil von Kühlung für Lebensmittel</option>
<option value="Läden">Läden</option>
<option value="Läden mit sehr hohem Anteil von Kühlung für Lebensmittel">Läden mit sehr hohem Anteil von Kühlung für Lebensmittel</option>
<option value="Fernmeldetechnik">Fernmeldetechnik</option>
{/if}
</select>
<div class="help-label">
<HelpLabel><strong>Der Energieausweis bezieht sich immer auf das gesamte Gebäude</strong> oder den gesamten Wohnteil eines Mischgebäudes.
Für einzelne Wohnungen kann kein Energieausweis ausgestellt werden.</HelpLabel>
</div>
</div>
{#if ausweisart=="VerbrauchsausweisWohnen"}
<!-- Anzahl der Wohnungen -->
<div class="input-standard order-3 md:order-5 xl:order-3">
<Inputlabel title="Anzahl Wohnungen *"></Inputlabel>
<input
id="einheiten"
class="rounded-e-none"
name="einheiten"
type="number"
required
autocomplete="off"
data-msg="Pflichtfeld"
maxlength="3"
bind:value={aufnahme.einheiten}
/>
<div class="help-label">
<HelpLabel>
Bitte geben Sie hier die Anzahl der Wohnungen ein, die sich im
Gebäude befinden.
</HelpLabel>
</div>
</div>
{:else if ausweisart=="VerbrauchsausweisGewerbe"}
<!-- Baujahr Klimaanlage -->
<div class="input-standard order-3 md:order-5 xl:order-3">
<Inputlabel title="Baujahr Klimaanlage *"></Inputlabel>
<TagInput
name="baujahr_klimaanlage"
type="number"
onlyUnique={true}
minlength={4}
maxlength={4}
onFocusIn={() => {
addNotification({
message: "Info",
subtext:
"Wussten sie, dass sie weitere Jahre angeben können? Z.B. das Baujahr der Erneuerung wesentlicher Komponenten ihrer Heizung. Drücken sie dafür einfach <kbd>Enter</kbd> oder <kbd>Space</kbd> nach jedem Jahr.",
dismissable: true,
uid: "KLIMAANLAGE_BAUJAHR",
timeout: 0,
type: "info",
});
}}
onFocusOut={() => {
deleteNotification("KLIMAANLAGE_BAUJAHR");
}}
className={auditHeizungGebaeudeBaujahr(aufnahme)
? "linked"
: ""}
bind:tags={aufnahme.baujahr_klima}
/>
<div class="help-label">
<HelpLabel>
Bitte geben Sie hier das Baujahr der Heizungsanlage ein. Sollten
unterschiedliche Baujahre vorliegen, können Sie mehrere Jahre eingeben.
</HelpLabel>
</div>
</div>
{/if}
<!-- Baujahr -->
<div class="input-standard order-5 md:order-4 xl:order-5">
<Inputlabel title="Baujahr *"></Inputlabel>
<TagInput
name="baujahr_gebaeude"
type="number"
minlength={4}
maxlength={4}
onlyUnique={true}
onFocusIn={() => {
addNotification({
message: "Info",
subtext:
"Wussten sie, dass sie mehrere Jahre angeben können in denen z.B. Renovierungen an ihrem Gebäude durchgeführt wurden. Drücken sie dafür einfach <kbd>Enter</kbd> oder <kbd>Space</kbd> nach jedem Jahr.",
dismissable: true,
uid: "GEBAEUDE_BAUJAHR",
timeout: 0,
type: "info",
});
}}
onFocusOut={() => {
deleteNotification("GEBAEUDE_BAUJAHR");
}}
className={auditHeizungGebaeudeBaujahr(aufnahme)
? "linked"
: ""}
bind:tags={aufnahme.baujahr_gebaeude}
/>
<div class="help-label">
<HelpLabel>
Bitte geben Sie hier das Baujahr des Gebäudes ein. Sollte eine grundlegende Sanierung stattgefunden haben, dann geben Sie das Sanierungsjahr ebenfalls an.
</HelpLabel>
</div>
</div>
<!-- Baujahr Heizung -->
<div class="input-standard order-6 md:order-6 xl:order-6">
<Inputlabel title="Baujahr Heizung *"></Inputlabel>
<TagInput
name="baujahr_heizung"
type="number"
onlyUnique={true}
minlength={4}
maxlength={4}
onFocusIn={() => {
addNotification({
message: "Info",
subtext:
"Wussten sie, dass sie weitere Jahre angeben können? Z.B. das Baujahr der Erneuerung wesentlicher Komponenten ihrer Heizung. Drücken sie dafür einfach <kbd>Enter</kbd> oder <kbd>Space</kbd> nach jedem Jahr.",
dismissable: true,
uid: "HEIZUNG_BAUJAHR",
timeout: 0,
type: "info",
});
}}
onFocusOut={() => {
deleteNotification("HEIZUNG_BAUJAHR");
}}
className={auditHeizungGebaeudeBaujahr(aufnahme)
? "linked"
: ""}
bind:tags={aufnahme.baujahr_heizung}
/>
<div class="help-label">
<HelpLabel>
Bitte geben Sie hier das Baujahr der Heizungsanlage ein. Sollten
unterschiedliche Baujahre vorliegen, können Sie mehrere Jahre eingeben.
</HelpLabel>
</div>
</div>
</div>

View File

@@ -1,10 +1,10 @@
<script lang="ts">
import UploadImages from "./UploadImages.svelte";
import type { Enums } from "@ibcornelsen/database/client";
import { BedarfsausweisWohnenClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
import { BedarfsausweisWohnenClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
import { RotateCounterClockwise, Trash, Upload } from "radix-svelte-icons";
export let images: UploadedGebaeudeBild[] = [];
export let images: BildClient[] = [];
export let max: number = Infinity;
export let min: number = 1;
export let name: string = "";
@@ -15,7 +15,7 @@
async function rotateImage(image: UploadedGebaeudeBild): Promise<UploadedGebaeudeBild> {
return new Promise((resolve, reject) => {
let img = new Image();
img.src = image.base64 ? image.base64 : `/bilder/${image.uid}.webp`;
img.src = image.data ? image.data : `/bilder/${image.uid}.webp`;
img.onload = () => {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
@@ -25,7 +25,7 @@
ctx?.rotate((-90 * Math.PI) / 180);
ctx?.drawImage(img, -img.width / 2, -img.height / 2);
const clone = Object.assign({}, image)
clone.base64 = canvas.toDataURL("image/webp");
clone.data = canvas.toDataURL("image/webp");
clone.update = true;
resolve(clone)
};
@@ -42,7 +42,7 @@
{#if image.kategorie == kategorie}
<div class="relative group">
<img
src={image.base64 ? image.base64 : `/bilder/${image.uid}.webp`}
src="/bilder/{image.uid}.webp"
alt={kategorie}
class="h-full max-h-96 w-full rounded-lg border-2 group-hover:contrast-50 object-cover transition-all"
/>

View File

@@ -0,0 +1,33 @@
<script lang="ts">
import { ChevronLeft, ChevronRight } from "radix-svelte-icons";
export let pages: number;
export let current: number
export let next: string;
export let prev: string;
</script>
<div class='flex items-center justify-center gap-2 my-4'>
<a href={prev}
class:disabled={current === 1 ? true : false}
aria-label="left arrow icon"
aria-describedby="prev"
class="flex p-2 hover:bg-gray-200 rounded-lg">
<ChevronLeft></ChevronLeft>
</a>
<p>{current} of {pages}</p>
<a href={next}
class:disabled={current === pages ? true : false}
aria-label="right arrow icon"
aria-describedby="next"
class="flex p-2 hover:bg-gray-200 rounded-lg">
<ChevronRight></ChevronRight>
</a>
</div>
<style>
.disabled {
@apply pointer-events-none cursor-default text-gray-500;
}
</style>

View File

@@ -1,33 +1,27 @@
<script lang="ts">
import type { Bezahlmethoden } from "@ibcornelsen/database/client";
import Input from "radix-svelte-icons/src/lib/icons/Input.svelte";
export let name: string;
export let icon: string;
export let paymentType: Bezahlmethoden;
export let selectedPaymentType: Bezahlmethoden;
export let bezahlmethode: Bezahlmethoden;
export let aktiveBezahlmethode: Bezahlmethoden;
</script>
<div>
<input
type="radio"
data-cy={bezahlmethode}
id={bezahlmethode}
name="paymentType"
on:change={() => (aktiveBezahlmethode = bezahlmethode)}
/>
<input type="radio" data-cy={paymentType} id={paymentType} name="paymentType" on:change={() => selectedPaymentType = paymentType} />
<label for={paymentType}>
<div class="grid grid-rows-[1fr_20px] justify-items-center items-center cursor-pointer">
<label for={bezahlmethode}>
<div
class="grid grid-rows-[1fr_20px] justify-items-center items-center cursor-pointer"
>
<img src={icon} alt={name} />
{name}
</div>
</label>
</div>
<!--
<button type="button" class="bg-white px-4 py-2" on:click={() => selectedPaymentType = paymentType}>
<div class="grid grid-rows-[max-content-max-content] w-fit">
<img src={icon} alt={name} />
<span aria-label={name}>
{name}
</span>
</div>
</button>
-->

View File

@@ -67,7 +67,7 @@
<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}>
{#each zipCodes as zipCode}
<button class="hover:bg-gray-100 cursor-pointer px-2 py-1 text-nowrap" tabindex="-1" on:click={() => {
<button class="hover:bg-gray-100 cursor-pointer px-2 py-1 text-nowrap" type="button" tabindex="-1" on:click={() => {
zip = zipCode.plz;
city = zipCode.stadt;
hideZipDropdown = true;

View File

@@ -43,7 +43,7 @@
<div>
<h4>Kategorie *</h4>
<select class="select select-bordered" bind:value={category}>
<option value="" disabled selected>Bitte Auswählen</option>
<option value={null} disabled selected>Bitte Auswählen</option>
<option value="Verständnisproblem">Verständnisproblem</option>
<option value="Technischer Fehler">Technischer Fehler</option>
<option value="Feature anfordern">Feature anfordern</option>

View File

@@ -4,20 +4,31 @@
export let max: number = 2;
export let min: number = 1;
export let name: string = ""
export let name: string = "";
// Array of base64 encoded images read into the input.
import { BedarfsausweisWohnenClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./Ausweis/types.js";
import {
BedarfsausweisWohnenClient,
BildClient,
ObjektClient,
UploadedGebaeudeBild,
VerbrauchsausweisGewerbeClient,
VerbrauchsausweisWohnenClient,
} from "./Ausweis/types.js";
import { api } from "astro-typesafe-api/client";
export let images: UploadedGebaeudeBild[] = [];
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let images: BildClient[] = [];
export let ausweis:
| VerbrauchsausweisWohnenClient
| VerbrauchsausweisGewerbeClient
| BedarfsausweisWohnenClient;
export let objekt: ObjektClient;
export let kategorie: Enums.BilderKategorie;
function getAllImages(this: HTMLInputElement) {
const files = this.files || [];
if (images.length == max) {
if (images.filter((img) => img.kategorie === kategorie).length == max) {
this.value = "";
return;
}
@@ -25,8 +36,7 @@
for (let i = 0; i < files.length; i++) {
const file = files[i];
if ((file.type !== "image/jpeg") && (file.type !== "image/png")) {
i--;
if (file.type !== "image/jpeg" && file.type !== "image/png") {
continue;
}
@@ -59,22 +69,32 @@
if (!ctx) {
return;
}
ctx.drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight);
ctx.drawImage(
image,
0,
0,
image.naturalWidth,
image.naturalHeight
);
// Get the scaled-down data from the canvas in the desired output format and quality
const dataURL = canvas.toDataURL("image/jpeg", 0.8);
images.push({ base64: dataURL as string, kategorie });
const { uid } = await api.bild.PUT.fetch({
data: dataURL,
kategorie
})
images.push({ uid, kategorie });
images = images;
if (i == (Math.min(files.length, max) - 1)) {
if (i == Math.min(files.length, max) - 1) {
this.value = "";
}
}
};
image.src = url;
}
};
reader.readAsArrayBuffer(file);
}
@@ -83,31 +103,44 @@
let fileUpload: HTMLInputElement;
export const upload = () => {
fileUpload.click()
}
fileUpload.click();
};
</script>
<!-- Falls die maximale Anzahl Bilder erreicht wurde grauen wir den input aus und zeigen einen Hilfstext -->
{#if images.filter((image) => image.kategorie === kategorie).length === max}
<span class="bg-base-200 border px-4 py-2">Maximale Anzahl Bilder wurde erreicht.</span>
<span class="bg-base-200 border px-4 py-2"
>Maximale Anzahl Bilder wurde erreicht.</span
>
{:else if max > 1}
<div class="input-standard">
<input type="file" class="file-input file-input-ghost h-[38px]" bind:this={fileUpload} {name} multiple on:change={getAllImages} />
<input
type="file"
class="file-input file-input-ghost h-[38px]"
bind:this={fileUpload}
{name}
multiple
on:change={getAllImages}
/>
<div class="help-label">
<HelpLabel>
<slot />
</HelpLabel>
</div>
</div>
{:else}
<div class="input-standard">
<input type="file" class="file-input file-input-ghost h-[38px]" bind:this={fileUpload} {name} on:change={getAllImages} />
<input
type="file"
class="file-input file-input-ghost h-[38px]"
bind:this={fileUpload}
{name}
on:change={getAllImages}
/>
<div class="help-label">
<HelpLabel>
<slot />
</HelpLabel>
</div>
</div>
{/if}

View File

@@ -2,6 +2,7 @@
import { PRICES } from "#lib/constants";
export let bullets;
export let title;
import { Enums } from "@ibcornelsen/database/client";
bullets = [
["Prüfung durch Dipl.&nbsp;Ing.<br>Registrierung beim DiBt<br>rechtssicher nach&nbsp;GEG",true, true, true],
@@ -43,9 +44,9 @@
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center sm:text-[1.25rem]">
<div class="price justify-self-start pl-2">Preis inkl. MwSt.</div>
<div class="price"><b>{PRICES.BedarfsausweisGewerbe[0]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisGewerbe[1]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisGewerbe[2]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Beratung]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Offline]}&nbsp;</b></div>
</div>
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center">

View File

@@ -2,6 +2,7 @@
import { PRICES } from "#lib/constants";
export let bullets;
export let title;
import { Enums } from "@ibcornelsen/database/client";
bullets = [
["Prüfung durch Dipl.&nbsp;Ing.<br>Registrierung beim DiBt<br>rechtssicher nach&nbsp;GEG",true, true, true],
@@ -43,9 +44,9 @@
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center sm:text-[1.25rem]">
<div class="price justify-self-start pl-2">Preis inkl. MwSt.</div>
<div class="price"><b>{PRICES.BedarfsausweisWohnen[0]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisWohnen[1]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisWohnen[2]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Beratung]}&nbsp;</b></div>
<div class="price"><b>{PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Offline]}&nbsp;</b></div>
</div>
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center">

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
import { Enums } from "@ibcornelsen/database/client";
export let bullets;
export let title;
@@ -43,9 +44,9 @@
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center sm:text-[1.25rem]">
<div class="price justify-self-start pl-2">Preis inkl. MwSt.</div>
<div class="price"><b>{PRICES.VerbrauchsausweisGewerbe[0]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisGewerbe[1]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisGewerbe[2]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Beratung]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Offline]}&nbsp;</b></div>
</div>
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center">

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
<script lang="ts">
import { PRICES } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
export let bullets;
export let title;
@@ -43,9 +44,9 @@ bullets = [
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center sm:text-[1.25rem]">
<div class="price justify-self-start pl-2">Preis inkl. MwSt.</div>
<div class="price"><b>{PRICES.VerbrauchsausweisWohnen[0]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisWohnen[1]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisWohnen[2]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Beratung]}&nbsp;</b></div>
<div class="price"><b>{PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Offline]}&nbsp;</b></div>
</div>
<div class="zeile grid grid-cols-subgrid col-span-4 py-4 border-b-[0px] justify-items-center items-center">

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
import { Enums } from "@ibcornelsen/database/client";
</script>
<div class="mt-6 mb-6 m-auto w-[99%] relative">
@@ -22,7 +23,7 @@
<div class="orange">
<div class="price">
ab <b> {PRICES.VerbrauchsausweisWohnen[0]} </b>€ inkl. 19% MwSt.
ab <b> {PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]} </b>€ inkl. 19% MwSt.
</div>
</div>
@@ -53,7 +54,7 @@
<div class="orange">
<div class="price">
<b>ab {PRICES.BedarfsausweisWohnen[0]} €</b> inkl. 19% MwSt.
<b>ab {PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]} €</b> inkl. 19% MwSt.
</div>
</div>

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
import { Enums } from "@ibcornelsen/database/client";
</script>
<div class="mt-6 mb-6 m-auto w-[99%] relative">
@@ -21,7 +22,7 @@
<div class="orange">
<div class="price">
ab <b> {PRICES.VerbrauchsausweisGewerbe[0]} </b>€ inkl. 19% MwSt.
ab <b> {PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]} </b>€ inkl. 19% MwSt.
</div>
</div>
@@ -52,7 +53,7 @@
<div class="orange">
<div class="price">
<b>ab {PRICES.BedarfsausweisGewerbe[0]} €</b> inkl. 19% MwSt.
<b>ab {PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]} €</b> inkl. 19% MwSt.
</div>
</div>

View File

@@ -4,6 +4,7 @@ import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.sve
import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte";
import { PRICES } from "#lib/constants";
import { Enums } from "@ibcornelsen/database/client";
---
@@ -11,8 +12,8 @@ import { PRICES } from "#lib/constants";
<NavigationCard client:load/>
<CardProduktSidebar art="Verbrauchsausweis Gewerbe" price={PRICES.VerbrauchsausweisGewerbe[0]}></CardProduktSidebar>
<CardProduktSidebar art="Verbrauchsausweis Gewerbe" price={PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}></CardProduktSidebar>
<CardPriceiInfo />
<CardProduktSidebar art="Bedarfsausweis Wohnen" price={PRICES.BedarfsausweisWohnen[0]}></CardProduktSidebar>
<CardProduktSidebar art="Bedarfsausweis Wohnen" price={PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]}></CardProduktSidebar>
</div>

View File

@@ -4,6 +4,7 @@ import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.sve
import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte";
import { PRICES } from "#lib/constants";
import { Enums } from "@ibcornelsen/database/client";
---
<div class="hidden 2xl:block">
@@ -11,9 +12,9 @@ import { PRICES } from "#lib/constants";
<CardContact />
<CardProduktSidebar art="Verbrauchsausweis Wohnen" price={PRICES.VerbrauchsausweisWohnen[0]}></CardProduktSidebar>
<CardProduktSidebar art="Verbrauchsausweis Wohnen" price={PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}></CardProduktSidebar>
<CardPriceiInfo />
<CardProduktSidebar art="Bedarfsausweis Gewerbe" price={PRICES.BedarfsausweisGewerbe[0]}></CardProduktSidebar>
<CardProduktSidebar art="Bedarfsausweis Gewerbe" price={PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}></CardProduktSidebar>
</div>

View File

@@ -218,7 +218,7 @@
on:mouseover={hover}
on:mouseleave={hoverout}
>
<a href={undefined} class="nav-element-child"
<a href="/verbrauchsausweis/" class="nav-element-child"
>Verbrauchsausweis<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
@@ -227,11 +227,11 @@
{#if innerWidth < 1023}
<li><a href="index">Verbrauchsausweis</a></li>
{/if}
<li><a href="index">Verbrauchsausweis Wohngebäude</a></li>
<li><a href="index">Verbrauchsausweis online erstellen</a></li>
<li><a href="index">Häufige Fragen zum Verbrauchsausweis</a></li>
<li><a href="/verbrauchsausweis/verbrauchsausweis-wohngebaeude">Verbrauchsausweis Wohngebäude</a></li>
<li><a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/">Verbrauchsausweis online erstellen</a></li>
<li><a href="/verbrauchsausweis/haeufige-fragen-zum-verbrauchsausweis/">Häufige Fragen zum Verbrauchsausweis</a></li>
<li>
<a href="index">Statistiken zum Verbrauchsausweis Wohngebäude</a
<a href="/verbrauchsausweis/statistiken-zum-verbrauchsausweis/">Statistiken zum Verbrauchsausweis Wohngebäude</a
>
</li>
<li><a href="index">Verbrauchsausweis Gewerbe</a></li>
@@ -255,7 +255,7 @@
on:mouseover={hover}
on:mouseleave={hoverout}
>
<a href={undefined} class="nav-element-child"
<a href="/bedarfsausweis/" class="nav-element-child"
>Bedarfsausweis<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
@@ -293,7 +293,7 @@
on:mouseover={hover}
on:mouseleave={hoverout}
>
<a href={undefined} class="nav-element-child"
<a href="/" class="nav-element-child"
>Energieausweis<span class="dd-symbol-clone"></span><span
class="dd-symbol"></span
></a
@@ -308,12 +308,12 @@
</ul>
</div>
<div class="nav-element">
<!-- <div class="nav-element">
<a
class="no-dropdown nav-element-child"
href="/energieausweis-aussteller">Energieberater finden</a
>
</div>
</div> -->
<div class="nav-element bg-secondary/5 py-1 pl-2 text-xs font-bold">
FAQ & Hilfe
@@ -393,12 +393,12 @@
>Kundenbewertungen</a
>
</div>
<div class="nav-element">
<!-- <div class="nav-element">
<a
class="no-dropdown nav-element-child lg:!rounded-b-lg xl:!rounded-b-xl"
href="/fuer-entwickler/">Für Entwickler</a
>
</div>
</div> -->
</nav>
<style lang="scss">

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
<script lang="ts">
import { PRICES } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
</script>
<div id ="cardBAGpromo"
@@ -10,7 +11,7 @@ class=" box card">
<h2>Bedarfssausweis Gewerbe</h2>
<hr class="mb-4">
<img class="w-[70%] justify-self-center !min-w-[100px] mb-[1rem]" src="/images/right-sidebar/UMBE_gewerbegebaeude.svg" alt="Gewerbe Bedarfsausweis"/>
<p class="promo tracking-tighter text-[2rem] text-gray-700 pl-6">ab<span class="promo pl-[0.2rem]">{PRICES.BedarfsausweisGewerbe[0]}</span></p>
<p class="promo tracking-tighter text-[2rem] text-gray-700 pl-6">ab<span class="promo pl-[0.2rem]">{PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}</span></p>
<a href="./energieausweis-erstellen/bedarfsausweis-gewerbe/" id="link-BA-promo"
class=" w-[90%] justify-self-center text-center text-white font-[700] bg-secondary rounded-md px-3 py-1 mt-2 no-underline text-[1rem]
hover:bg-primary

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
<script lang="ts">
import { PRICES } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
</script>
<div id ="cardBApromo"
@@ -10,7 +11,7 @@ class=" box card">
<h2>Bedarfssausweis Wohngebäude</h2>
<hr class="mb-4">
<img class="w-[70%] justify-self-center !min-w-[100px] mb-[1rem]" src="/images/right-sidebar/UMBE_wohngebaeude.svg" alt="Wohnhaus Verbrauchsausweis"/>
<p class="promo tracking-tighter text-[2rem] text-gray-700 pl-6">ab<span class="promo pl-[0.2rem]">{PRICES.BedarfsausweisWohnen[0]}</span></p>
<p class="promo tracking-tighter text-[2rem] text-gray-700 pl-6">ab<span class="promo pl-[0.2rem]">{PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]}</span></p>
<a href="./energieausweis-erstellen/bedarfsausweis-wohngebaeude/" id="link-BA-promo"
class=" w-[90%] justify-self-center text-center text-white font-[700] bg-secondary rounded-md px-3 py-1 mt-2 no-underline text-[1rem]
hover:bg-primary

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
import { Enums } from "@ibcornelsen/database/client";
</script>
<div id ="cardPriceinfo" class="box card hidden lg:block">
@@ -8,23 +9,23 @@
<div>Verbrauchsausweis Wohngebäude</div>
<div>ab&nbsp;<span class="price">{PRICES.VerbrauchsausweisWohnen[0]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<div>ab&nbsp;<span class="price">{PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<hr class="trenner">
<div>Bedarfsausweis Wohngebäude</div>
<div>ab&nbsp;<span class="price">{PRICES.BedarfsausweisWohnen[0]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<div>ab&nbsp;<span class="price">{PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<hr class="trenner">
<div>Verbrauchsausweis Gewerbe</div>
<div>ab&nbsp;<span class="price">{PRICES.VerbrauchsausweisGewerbe[0]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<div>ab&nbsp;<span class="price">{PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<hr class="trenner">
<div>Bedarfsausweis Gewerbe</div>
<div>ab&nbsp;<span class="price">{PRICES.BedarfsausweisGewerbe[0]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<div>ab&nbsp;<span class="price">{PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<hr class="trenner">
<div>GEG-Nachweis Wohngebäude</div>
<div>ab&nbsp;<span class="price">{PRICES.GEGNachweisWohnen[0]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<div>ab&nbsp;<span class="price">{PRICES.GEGNachweisWohnen[Enums.AusweisTyp.Standard]}€</span>&nbsp;inkl.&nbsp;MwSt.</div>
<hr class="trenner">
<div>GEG-Nachweis Gewerbe</div>

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import { PRICES } from "#lib/constants";
import { PRICES } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
</script>
<div id ="cardVAGpromo"
@@ -10,7 +11,7 @@
<h2>Verbrauchsausweis Gewerbe</h2>
<hr class="mb-4">
<img class="w-[70%] justify-self-center !min-w-[100px]" src="/images/right-sidebar/UMBE_gewerbegebaeude.svg" alt="Gewerbe Verbrauchsausweis"/>
<p class="promo tracking-tighter text-[2rem] text-gray-700 pl-6">ab<span class="promo pl-2">{PRICES.VerbrauchsausweisGewerbe[0]}</span></p>
<p class="promo tracking-tighter text-[2rem] text-gray-700 pl-6">ab<span class="promo pl-2">{PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}</span></p>
<a href="./energieausweis-erstellen/verbrauchsausweis-gewerbe/" id="link-VA-promo"
class=" w-[90%] justify-self-center text-center text-white font-[700] bg-gradient-to-br from-secondary to-secondary-grad rounded-md px-3 py-1 mt-2 no-underline text-[1rem]
hover:bg-primary

View File

@@ -1,5 +1,6 @@
<script>
import { PRICES } from "#lib/constants";
<script lang="ts">
import { PRICES } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
</script>
@@ -14,7 +15,7 @@
alt="Wohnhaus Verbrauchsausweis"
/>
<p class="promo tracking-tighter text-[2rem] text-gray-700 pl-6">
ab<span class="promo pl-2">{PRICES.VerbrauchsausweisWohnen[0]}</span
ab<span class="promo pl-2">{PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}</span
>
</p>
<a

View File

@@ -2,6 +2,7 @@
import { fade } from "svelte/transition";
import WidgetCardTemplate from "#components/widgets/WidgetCardTemplate_IBC.svelte";
import { PRICES } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
let gebaeudetyp: string = "bitte auswählen";
let anlass: string = "bitte auswählen";
@@ -200,7 +201,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Verbrauchsausweis Wohngebäude"
price={PRICES.VerbrauchsausweisWohnen[0]}
price={PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/widget/wohngebaeude.svg"
alt="Wohnhaus Verbrauchsausweis"
variant="einfach"
@@ -226,7 +227,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Bedarfsausweis Wohngebäude"
price={PRICES.BedarfsausweisWohnen[0]}
price={PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/widget/wohngebaeude.svg"
alt="Wohnhaus Bedarfsausweis"
variant="fundiert"
@@ -252,7 +253,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Verbrauchsausweis Gewerbegebäude"
price={PRICES.VerbrauchsausweisGewerbe[0]}
price={PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/widget/gewerbegebaeude.svg"
alt="Gewerbe Verbrauchsausweis"
variant="einfach"
@@ -280,7 +281,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Bedarfsausweis Gewerbegebäude"
price={PRICES.BedarfsausweisGewerbe[0]}
price={PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/widget/gewerbegebaeude.svg"
alt="Gewerbe Bedarfsausweis"
variant="fundiert"
@@ -307,7 +308,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="GEG-Nachweis Wohngebäude"
price={PRICES.GEGNachweisWohnen[0]}
price={PRICES.GEGNachweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/widget/wohngebaeude.svg"
alt="Gewerbe Bedarfsausweis"
variant="Bauvorlage"
@@ -336,7 +337,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="GEG-Nachweis Gewerbegebäude"
price={PRICES.GEGNachweisGewerbe[0]}
price={PRICES.GEGNachweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/widget/gewerbegebaeude.svg"
alt="Gewerbe Bedarfsausweis"
variant="Bauvorlage"

View File

@@ -2,6 +2,7 @@
import { fade } from "svelte/transition";
import WidgetCardTemplate from "#components/widgets/immowelt/WidgetCardTemplate_immowelt.svelte";
import { PRICES } from "#lib/constants.js";
import { Enums } from "@ibcornelsen/database/client";
let gebaeudetyp: string = "bitte auswählen";
let anlass: string = "bitte auswählen";
@@ -205,7 +206,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Verbrauchsausweis Wohngebäude"
price={PRICES.VerbrauchsausweisWohnen[0]}
price={PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/immowelt/wohngebaeude_immowelt.svg"
alt="Wohnhaus Verbrauchsausweis"
variant="einfach"
@@ -231,7 +232,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Bedarfsausweis Wohngebäude"
price={PRICES.BedarfsausweisWohnen[0]}
price={PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/immowelt/wohngebaeude_immowelt.svg"
alt="Wohnhaus Bedarfsausweis"
variant="fundiert"
@@ -257,7 +258,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Verbrauchsausweis Gewerbegebäude"
price={PRICES.VerbrauchsausweisGewerbe[0]}
price={PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/immowelt/gewerbegebaeude_immowelt.svg"
alt="Gewerbe Verbrauchsausweis"
variant="einfach"
@@ -285,7 +286,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="Bedarfsausweis Gewerbegebäude"
price={PRICES.BedarfsausweisGewerbe[0]}
price={PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/immowelt/gewerbegebaeude_immowelt.svg"
alt="Gewerbe Bedarfsausweis"
variant="fundiert"
@@ -312,7 +313,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="GEG-Nachweis Wohngebäude"
price={PRICES.GEGNachweisWohnen[0]}
price={PRICES.GEGNachweisWohnen[Enums.AusweisTyp.Standard]}
src="/images/immowelt/wohngebaeude_immowelt.svg"
alt="Gewerbe Bedarfsausweis"
variant="Bauvorlage"
@@ -341,7 +342,7 @@ threeBOX = ((ausnahme === true) && (gebaeudetyp === "Mischgebäude") && (twoBo
>
<WidgetCardTemplate
name="GEG-Nachweis Gewerbegebäude"
price={PRICES.GEGNachweisGewerbe[0]}
price={PRICES.GEGNachweisGewerbe[Enums.AusweisTyp.Standard]}
src="/images/immowelt/gewerbegebaeude_immowelt.svg"
alt="Gewerbe Bedarfsausweis"
variant="Bauvorlage"

View File

@@ -15,10 +15,13 @@ const { title } = Astro.props;
---
<script>
window.addEventListener("scroll", (event) => {
const skala = document.getElementById("skala");
if (!skala?.classList.contains("no-scroll")) {
window.addEventListener("scroll", (event) => {
if (skala?.classList.contains("no-scroll")) {
return;
}
let scroll = window.scrollY;
if (scroll >= 400) {
if (skala) {
@@ -63,7 +66,6 @@ const { title } = Astro.props;
?.classList.remove("2xl:mt-[370px]");
}
});
}
</script>
<html lang="de">

View File

@@ -99,12 +99,13 @@ export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis:
// Endenergieverbrauch
// Um den EEV auszurechnen, müssen die Verbräuche zu kWh konvertiert werden.
let brennstoff_1 = { coe: 0, energietraeger: "", einheit: "", umrechnungsfaktor: 0, primaerenergiefaktor: 0 }, brennstoff_2 = { coe: 0, energietraeger: "", einheit: "", umrechnungsfaktor: 0, primaerenergiefaktor: 0 };
if (ausweis.brennstoff_1 && ausweis.einheit_1) {
brennstoff_1 = getHeizwertfaktor(ausweis.brennstoff_1, ausweis.einheit_1);
if (aufnahme.brennstoff_1 && ausweis.einheit_1) {
brennstoff_1 = getHeizwertfaktor(aufnahme.brennstoff_1, ausweis.einheit_1);
}
if (ausweis.brennstoff_2 && ausweis.einheit_2) {
brennstoff_2 = getHeizwertfaktor(ausweis.brennstoff_2, ausweis.einheit_2);
if (aufnahme.brennstoff_2 && ausweis.einheit_2) {
brennstoff_2 = getHeizwertfaktor(aufnahme.brennstoff_2, ausweis.einheit_2);
}
let energieVerbrauchGesamt_1 = ((ausweis.verbrauch_1 || 0) + (ausweis.verbrauch_2 || 0) + (ausweis.verbrauch_3 || 0)) * brennstoff_1?.umrechnungsfaktor;
@@ -136,7 +137,7 @@ export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis:
}
let kuehlungsZuschlag_1: number = 0, kuehlungsZuschlag_2: number = 0;
if (ausweis.wird_gekuehlt) {
if (aufnahme.kuehlung) {
kuehlungsZuschlag_1 = energieVerbrauchGesamt_1 * ((ausweis.anteil_kuehlung_1 || 0) / 100);
kuehlungsZuschlag_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_kuehlung_2 || 0) / 100);
}

View File

@@ -148,7 +148,7 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
energieVerbrauchHeizung_2 * durchschnittsKlimafaktor;
let kuehlungsZuschlag = 0;
if (ausweis.wird_gekuehlt) {
if (aufnahme.kuehlung) {
kuehlungsZuschlag = 6 * 3 * energetischeNutzflaeche;
}

View File

@@ -39,7 +39,7 @@ export function verbrauchsausweisWohnenCalculateFormProgress(ausweis: Verbrauchs
title: "Fehlendes Baujahr",
description: "Eines ihrer Gebäude hat noch kein Baujahr angegeben. Beheben sie dies indem sie auf den untenstehenden Link klicken.",
severity: "warning",
resolvehref: `/energieausweis-erstellen/verbrauchsausweis-wohnen?uid=${ausweis.uid}`
resolvehref: `/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid=${ausweis.uid}`
});
}

View File

@@ -16,7 +16,7 @@ export function getEmpfehlungen(ausweis: VerbrauchsausweisWohnenClient | Verbrau
let Keller = aufnahme.keller;
let Kellerdecke_Kalraeume_gedaemmt = aufnahme.keller_decke_gedaemmt;
let Brennwertkessel = aufnahme.brennwert_kessel;
let baujahr_anlagesanlage = aufnahme.baujahr_heizung[0];
let baujahr_anlagesanlage = aufnahme.baujahr_heizung && aufnahme.baujahr_heizung[0];
let Zentralheizung = aufnahme.zentralheizung;
let photovoltaik = aufnahme.photovoltaik;
let Brennstoff = aufnahme.brennstoff_1;

View File

@@ -18,20 +18,50 @@ export enum VALID_UUID_PREFIXES {
"inv" = "Rechnung",
"tkt" = "Ticket",
"pln" = "Gebäude Plan",
"gnw" = "GEG Nachweis Wohnen"
"gnw" = "GEG Nachweis Wohnen",
"gng" = "GEG Nachweis Gewerbe",
"gge" = "GEG Einpreisung",
}
/**
* Ein Objekt welches alle definierten Preise für unsere Basisprodukte enthält.
*/
export const PRICES: Record<Enums.Ausweisart, [number, number, number]> = {
export const PRICES: Record<Enums.Ausweisart, Record<Enums.AusweisTyp, number>> = {
// per E-Mail , inkl.Beratung, offline
BedarfsausweisWohnen: [95, 125, 295],
VerbrauchsausweisWohnen: [65, 95, 180],
VerbrauchsausweisGewerbe: [95, 125, 360],
BedarfsausweisGewerbe: [500, 700, 1000],
GEGNachweisWohnen: [500, 700, 1000],
GEGNachweisGewerbe: [800, 1000, 1300]
BedarfsausweisWohnen: {
[Enums.AusweisTyp.Standard]: 95,
[Enums.AusweisTyp.Beratung]: 125,
[Enums.AusweisTyp.Offline]: 295
},
VerbrauchsausweisWohnen: {
[Enums.AusweisTyp.Standard]: 65,
[Enums.AusweisTyp.Beratung]: 95,
[Enums.AusweisTyp.Offline]: 180
},
VerbrauchsausweisGewerbe: {
[Enums.AusweisTyp.Standard]: 95,
[Enums.AusweisTyp.Beratung]: 125,
[Enums.AusweisTyp.Offline]: 360
},
BedarfsausweisGewerbe: {
[Enums.AusweisTyp.Standard]: 500,
[Enums.AusweisTyp.Beratung]: 700,
[Enums.AusweisTyp.Offline]: 1000
},
GEGNachweisWohnen: {
[Enums.AusweisTyp.Standard]: 500,
[Enums.AusweisTyp.Beratung]: 700,
[Enums.AusweisTyp.Offline]: 1000
}
};
export const SERVICES: Record<

11
src/lib/filters.ts Normal file
View File

@@ -0,0 +1,11 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { Enums } from "@ibcornelsen/database/client";
import { z } from "zod";
export const filterAusweise = z.object({
uid: UUidWithPrefix.optional(),
ausgestellt: z.boolean().optional(),
ausstellgrund: z.nativeEnum(Enums.Ausstellgrund).optional(),
bestellt: z.boolean().optional(),
zurueckgestellt: z.boolean().optional()
})

View File

@@ -1,17 +1,22 @@
export function openWindowWithPost(url: string, data: Record<string, any>) {
var form = document.createElement("form");
form.target = "_blank";
export function openWindowWithPost(url: string, data: Record<string, any>, target = "_blank") {
const form = document.createElement("form");
form.target = target;
form.method = "POST";
form.action = url;
form.style.display = "none";
for (var key in data) {
var input = document.createElement("input");
const createInput = (name: string, value: any) => {
const input = document.createElement("input");
input.type = "hidden";
input.name = key;
input.value = data[key];
form.appendChild(input);
}
input.name = name;
input.value = JSON.stringify(value);
return input;
};
Object.entries(data).forEach(([key, value]) => {
form.appendChild(createInput(key, value));
});
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);

View File

@@ -0,0 +1,79 @@
import { PDFPage, PDFFont, rgb, RGB, PDFImage } from 'pdf-lib';
import { PDFElement, Size } from './PDFElement.js';
import { Margin, Padding } from './Layout.js';
import * as fs from "fs"
export interface ImageOptions {
margin?: Margin,
width?: number,
height?: number,
src?: string,
data?: string
}
export class Image extends PDFElement {
private options: ImageOptions
protected _width: number;
protected _height: number;
public margin: Margin
constructor(options: ImageOptions) {
super();
this._width = options.width || 0;
this._height = options.height || 0;
this.options = options;
this.margin = this.options.margin || { top: 0, left: 0, right: 0, bottom: 0}
}
addChild(...children: PDFElement[]): void {
throw new Error("Cannot add child element to Image")
}
get height() {
return this._height;
}
get width() {
return this._width;
}
async draw(page: PDFPage, x: number, y: number) {
let embed: PDFImage;
if (this.options.src) {
const img = fs.readFileSync(this.options.src)
if (this.options.src.split(".").pop() === "png") {
embed = await page.doc.embedPng(img)
} else {
embed = await page.doc.embedJpg(img)
}
} else if (this.options.data) {
embed = await page.doc.embedJpg(this.options.data)
} else {
return
}
if (this._height === 0) {
if (this._width) {
this._height = embed.height * (this._width / embed.width)
}
}
if (this._width === 0) {
if (this._height) {
this._width = embed.width * (this._height / embed.height)
}
}
page.drawImage(embed, {
x: x + this.margin.left + this.padding.left,
y: y - this.height - this.margin.top - this.padding.top,
height: this.height,
width: this.width,
})
}
}

View File

@@ -2,6 +2,7 @@ import * as txml from "#lib/helpers/txml.js"
import { PDFDocument, PDFFont, rgb, StandardFonts } from "pdf-lib"
import { Checkbox, Flex, Text } from "./index.js"
import { Layout } from "./Layout.js"
import { Image } from "./Image.js"
import { PDFElement } from "./PDFElement.js"
export function xml2pdf(xml: string, fonts: Record<string, PDFFont> & { "default": PDFFont }) {
@@ -90,6 +91,21 @@ export function xml2pdf(xml: string, fonts: Record<string, PDFFont> & { "default
iterateChildren(child.children, layout)
parent.addChild(layout)
} else if (child.tagName === "img") {
const image = new Image({
width: parseFloat(child.attributes.width),
height: parseFloat(child.attributes.height),
margin: {
bottom: parseFloat(child.attributes.marginBottom) || 0,
left: parseFloat(child.attributes.marginLeft) || 0,
right: parseFloat(child.attributes.marginRight) || 0,
top: parseFloat(child.attributes.marginTop) || 0,
},
src: child.attributes.src,
data: child.attributes.data
})
parent.addChild(image)
}
}
}

View File

@@ -1,4 +1,4 @@
import { AufnahmeClient, BenutzerClient, ObjektClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeClient, BenutzerClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import * as fs from "fs"
import { PDFDocument, rgb, StandardFonts, TextAlignment } from "pdf-lib";
@@ -6,12 +6,16 @@ import { xml2pdf } from "./elements/xml2pdf.js";
import moment from "moment";
import { Heizungsstatus } from "@ibcornelsen/database/server";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { fileURLToPath } from "url";
import { copyPage } from "./utils/copyPage.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, benutzer: BenutzerClient) {
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 pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const page3 = copyPage(pdf.getPages()[0]);
pdf.addPage(page3);
const pages = pdf.getPages()
// const template = VerbrauchsausweisWohnen2016Template as Template;
@@ -135,7 +139,7 @@ export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: Verbrauchsa
</flex>
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
<text size="12" lineHeight="14">Anlage zur Kühlung:</text>
<text size="12" lineHeight="14">${ausweis.wird_gekuehlt ? "Ja" : "Nein"}</text>
<text size="12" lineHeight="14">${aufnahme.kuehlung ? "Ja" : "Nein"}</text>
</flex>
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
<text size="12" lineHeight="14">Leerstand:</text>
@@ -348,8 +352,39 @@ export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: Verbrauchsa
bold
})
const images: string[][] = []
for (const bild of bilder) {
let badge: string[];
let image: string = "";
if (bild.uid) {
image = `<img src="${fileURLToPath(new URL(`../../../../persistent/images/${bilder[0].uid}.webp`, 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 {
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="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())
// const containerWidth = width - marginX;

View File

@@ -1,19 +1,24 @@
import { AufnahmeClient, BenutzerClient, ObjektClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeClient, BenutzerClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import * as fs from "fs"
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 { Heizungsstatus } from "@ibcornelsen/database/server";
import { BilderKategorie, Heizungsstatus } from "@ibcornelsen/database/server";
import { fileURLToPath } from "url";
import { copyPage } from "./utils/copyPage.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, benutzer: BenutzerClient) {
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 pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const page3 = copyPage(pdf.getPages()[0]);
pdf.addPage(page3);
const pages = pdf.getPages()
// const template = VerbrauchsausweisWohnen2016Template as Template;
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt);
@@ -290,8 +295,46 @@ export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: Verbrauchsau
bold
})
const images: 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/images/${bilder[0].uid}.webp`, 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 (c.kategorie in acc) {
acc[c.kategorie].push(img)
} else {
acc[c.kategorie] = [img];
}
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>`
}
const layoutPage3 = xml2pdf(`<layout height="${pages[2].getHeight()}" width="${pages[2].getWidth()}" marginTop="150" marginLeft="60" marginRight="60">
${text}
</layout>`, { "default": font, bold })
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

@@ -29,23 +29,6 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
const form = pdf.getForm()
form.updateFieldAppearances(font)
const fillFormField = (name: string, value: string, fontSize: number = 8, alignment: TextAlignment = TextAlignment.Left) => {
const field = form.getTextField(name)
field.setFontSize(fontSize)
field.setText(value)
field.setAlignment(alignment)
}
const toggleCheck = (name: string, checked: boolean = true) => {
const field = form.getCheckBox(name)
if (checked) {
field.check()
} else {
field.uncheck()
}
}
pages[0].drawText(aufnahme.gebaeudetyp || "", {
x: 211,
y: height - 166,
@@ -132,7 +115,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
}
// Kühlung
if (ausweis.wird_gekuehlt) {
if (aufnahme.kuehlung) {
addCheckMark(pages[0], 213, height - 362.5)
} else {
addCheckMark(pages[0], 355, height - 373.5)
@@ -159,9 +142,9 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
if (gebaeudeBild) {
let image: PDFImage;
try {
image = await pdf.embedJpg(gebaeudeBild?.base64)
image = await pdf.embedJpg(gebaeudeBild?.data)
} catch(e) {
image = await pdf.embedPng(gebaeudeBild?.base64)
image = await pdf.embedPng(gebaeudeBild?.data)
}
pages[0].drawImage(image, {
x: 460.5,
@@ -342,8 +325,8 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
addCheckMark(pages[2], 492, height - 456)
}
addText(pages[2], berechnungen?.primaerEnergieVerbrauchGesamt.toString() || "", 475, height - 614, 10, font)
addText(pages[2], berechnungen?.co2EmissionenGesamt.toString() || "", 475, height - 633, 10, font)
addText(pages[2], berechnungen?.primaerEnergieVerbrauchGesamt.toString() || "", 475, height - 637, 10, font)
addText(pages[2], berechnungen?.co2EmissionenGesamt.toString() || "", 475, height - 656, 10, font)
// const primaerenergiebedarfIst = fillFormField("primaerenergiebedarf_ist", berechnungen?.primaerEnergieVerbrauchGesamt.toString())
@@ -478,6 +461,73 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
);
}
// TODO
// if (!ausweis.warmwasser_enthalten) {
// /**
// * Dezentrale Warmwasserversorgung - Pauschale Erhöhung um 20kWh/m²
// * @link https://www.bundesanzeiger.de/pub/publication/MRYM4nI84Sdlr0EIvvW?2
// */
// addVerbrauch(
// moment(ausweis.startdatum).format("MM.YYYY"),
// moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
// "Warmwasserzuschlag",
// berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
// Math.round(berechnungen?.energieVerbrauchWarmwasser_1 || 0).toString(),
// Math.round(berechnungen?.energieVerbrauchWarmwasser_1 || 0).toString(),
// 0,
// "0"
// );
// }
// if (aufnahme.leerstand && aufnahme.leerstand > 0) {
// /**
// * Leerstandszuschlag
// * @link https://www.bundesanzeiger.de/pub/publication/MRYM4nI84Sdlr0EIvvW?2
// */
// if (ausweis.warmwasser_enthalten && ausweis.warmwasser_anteil_bekannt) {
// addVerbrauch(
// moment(ausweis.startdatum).format("MM.YYYY"),
// moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
// "Leerstandszuschlag",
// berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
// Math.round((berechnungen?.leerstandsZuschlagHeizung || 0) + (berechnungen?.leerstandsZuschlagWarmwasser || 0)).toString(),
// Math.round((berechnungen?.leerstandsZuschlagWarmwasser || 0)).toString(),
// Math.round((berechnungen?.leerstandsZuschlagHeizung || 0)),
// berechnungen?.durchschnittsKlimafaktor.toString()
// );
// } else {
// addVerbrauch(
// moment(ausweis.startdatum).format("MM.YYYY"),
// moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
// "Leerstandszuschlag",
// berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
// Math.round((berechnungen?.leerstandsZuschlagHeizung || 0) + (berechnungen?.leerstandsZuschlagWarmwasser || 0)).toString(),
// "0",
// 0,
// berechnungen?.durchschnittsKlimafaktor.toString()
// );
// }
// }
// if (aufnahme.kuehlung) {
// /**
// * Kühlungszuschlag - Pauschale Erhöhung um 6kWh/m²
// * Primärenergiefaktor Strom
// * @link https://www.bundesanzeiger.de/pub/publication/MRYM4nI84Sdlr0EIvvW?2
// */
// addVerbrauch(
// moment(ausweis.startdatum).format("MM.YYYY"),
// moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
// "Kühlungszuschlag",
// berechnungen?.primaerfaktorww.toString(),
// Math.round(berechnungen?.kuehlungsZuschlag || 0).toString(),
// "0",
// "0",
// ""
// );
// }
/* -------------------------------- Seite 4 -------------------------------- */
const splitToSize = (text: string, size: number, font: PDFFont, fontSize: number) => {

View File

@@ -86,9 +86,9 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
if (gebaeudeBild) {
let image: PDFImage;
try {
image = await pdf.embedJpg(gebaeudeBild?.base64)
image = await pdf.embedJpg(gebaeudeBild?.data)
} catch(e) {
image = await pdf.embedPng(gebaeudeBild?.base64)
image = await pdf.embedPng(gebaeudeBild?.data)
}
pages[0].drawImage(image, {
x: 460.5,
@@ -147,6 +147,35 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
height: 50
})
const erneuerbareEnergienVerwendung = []
if (ausweis.alternative_heizung) {
erneuerbareEnergienVerwendung.push("Heizung")
}
if (ausweis.alternative_kuehlung) {
erneuerbareEnergienVerwendung.push("Kühlung")
}
if (ausweis.alternative_lueftung) {
erneuerbareEnergienVerwendung.push("Lüftung")
}
if (ausweis.alternative_warmwasser) {
erneuerbareEnergienVerwendung.push("Warmwasser")
}
pages[0].drawText(erneuerbareEnergienVerwendung.join(", "), {
x: 358,
y: height - 337,
size: 8
})
// Kühlung
if (aufnahme.kuehlung) {
addCheckMark(pages[0], 354, height - 376.5)
}
/* -------------------------------- Seite 2 -------------------------------- */
@@ -439,12 +468,12 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
addVerbrauch(
moment(ausweis.startdatum).format("MM.YYYY"),
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
"Leerstandszuschlag",
"Kühlungszuschlag",
berechnungen?.primaerfaktorww.toString(),
Math.round(berechnungen?.kuehlungsZuschlag || 0).toString(),
"0",
"0",
"1.8"
""
);
}

View File

@@ -0,0 +1,12 @@
import { PDFPage, PDFName } from "pdf-lib";
export function copyPage(originalPage: PDFPage) {
const cloneNode = originalPage.node.clone();
const { Contents } = originalPage.node.normalizedEntries();
if (Contents) cloneNode.set(PDFName.of('Contents'), Contents.clone());
const cloneRef = originalPage.doc.context.register(cloneNode);
const clonePage = PDFPage.of(cloneNode, cloneRef, originalPage.doc);
return clonePage;
}

View File

@@ -1,4 +1,8 @@
import { getAusweisartFromUUID } from "#components/Ausweis/types.js";
import { AufnahmeClient, BedarfsausweisWohnenClient, BenutzerClient, BildClient, getAusweisartFromUUID, ObjektClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { pdfDatenblattVerbrauchsausweisGewerbe } from "#lib/pdf/pdfDatenblattVerbrauchsausweisGewerbe.js";
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 "@ibcornelsen/database/server";
/**
@@ -16,3 +20,39 @@ export function getPrismaAusweisAdapter(uid: string) {
return prisma.bedarfsausweisWohnen
}
}
/**
* Gibt den richtigen Ansichtsausweis basierend auf der Ausweisart zurück.
* @param ausweis
*/
export async function getAnsichtsausweis(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, ausweisart = getAusweisartFromUUID(ausweis.uid)) {
if (!ausweisart) {
return null
}
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
return await pdfVerbrauchsausweisWohnen(ausweis, aufnahme, objekt, bilder, user)
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
return await pdfVerbrauchsausweisGewerbe(ausweis, aufnahme, objekt, bilder, user)
}
return null
}
/**
* Gibt das richtige Datenblatt basierend auf der Ausweisart zurück.
* @param ausweis
*/
export async function getDatenblatt(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, ausweisart = getAusweisartFromUUID(ausweis.uid)) {
if (!ausweisart) {
return null
}
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
return await pdfDatenblattVerbrauchsausweisWohnen(ausweis, aufnahme, objekt, bilder, user)
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
return await pdfDatenblattVerbrauchsausweisGewerbe(ausweis, aufnahme, objekt, bilder, user)
}
return null
}

View File

@@ -0,0 +1,47 @@
import { transport } from "#lib/mail.js";
import {
Benutzer,
GEGNachweisWohnen,
} from "@ibcornelsen/database/client";
export async function sendGEGBestellungsMail(
nachweis: GEGNachweisWohnen,
user: Benutzer,
) {
await transport.sendMail({
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${nachweis.uid})`,
cc: {
address: user.email || "",
name: user.name || "",
},
bcc: "info@online-energieausweis.org",
html: `<p>Sehr geehrte/r ${user.vorname} ${user.name},
<br>
<br>
vielen Dank für ihre Bestellung. Wir werden Ihnen Originalausweis und Rechnung nach Prüfung zuschicken. Die Ausstellung erfolgt nach aktuellem GEG und Ihr Ausweis wird beim DIBT registriert.<br><br>
Den Rechnungsbetrag haben Sie bereits bezahlt. Vielen Dank.</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

@@ -0,0 +1,122 @@
import { getAusweisartFromUUID } from "#components/Ausweis/types.js";
import { BASE_URI } from "#lib/constants.js";
import { transport } from "#lib/mail.js";
import {
Benutzer,
Enums,
Rechnung,
VerbrauchsausweisWohnen,
} from "@ibcornelsen/database/client";
import { prisma } from "@ibcornelsen/database/server";
import { getAnsichtsausweis } from "../ausweis.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,
},
include: {
objekt: true,
bilder: true,
},
});
if (!aufnahme) {
return;
}
const ausweisart = getAusweisartFromUUID(ausweis.uid);
const attachments: any[] = [];
if (ausweisart != Enums.Ausweisart.BedarfsausweisWohnen) {
const ansichtsausweis = await getAnsichtsausweis(
ausweis,
aufnahme,
aufnahme.objekt,
aufnahme.bilder,
user,
ausweisart
);
if (ansichtsausweis) {
attachments.push([
{
filename: "Ansichtsausweis.pdf",
encoding: "binary",
content: Buffer.from(ansichtsausweis),
contentType: "application/pdf",
contentDisposition: "attachment",
},
]);
}
}
await transport.sendMail({
attachments,
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${ausweis.uid})`,
cc: {
address: rechnung.email || "",
name: rechnung.empfaenger || "",
},
bcc: "info@online-energieausweis.org",
html: `<p>Sehr geehrte*r ${user.vorname} ${user.name},</p>
<p>im Anhang finden Sie Ihren geprüften Energieusweis inkl. Rechnung als PDF-Datei. Nachfolgend finden Sie unsere Bankverbindung. Bitte geben Sie als Verwendungszweck die Rechnungsnummer an (siehe unten). Vielen Dank.</p>
<br>
<table>
<tr><td>Kreditinstitut</td><td>:</td><td>\t Commerzbank AG</td>
<tr><td>Empfänger</td><td>:</td><td>\t IB Cornelsen</td>
<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>
</table>
<br>
<p>
Alternativ können Sie auch direkt online zahlen indem Sie auf den entsprechenden Link klicken:
</p>
<br>
<table>
<tr><td>Per Einzuglastschrift zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.uid}&p=SEPA'>jetzt per ELV bezahlen</a></td></tr>
<tr><td>Per Sofortüberweisung zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.uid}&p=Sofort'>jetzt per Sofortüberweisung bezahlen</a></td></tr>
<tr><td>Über PayPal zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.uid}&p=PayPal'>jetzt per Paypal bezahlen</a></td></tr>
<tr><td>Per Giropay zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.uid}&p=Giropay'>jetzt per Giropay bezahlen</a></td></tr>
<tr><td>Per Visa oder MasterCard zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.uid}&p=Kreditkarte'>jetzt per Kreditkarte bezahlen</a></td></tr>
</table>
<br>
<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

@@ -0,0 +1,100 @@
import { getAusweisartFromUUID } from "#components/Ausweis/types.js";
import { transport } from "#lib/mail.js";
import {
Benutzer,
Enums,
Rechnung,
VerbrauchsausweisWohnen,
} from "@ibcornelsen/database/client";
import { prisma } from "@ibcornelsen/database/server";
import { getAnsichtsausweis } from "../ausweis.js";
export async function sendPaymentSuccessMail(
ausweis: VerbrauchsausweisWohnen,
rechnung: Rechnung,
user: Benutzer
) {
const aufnahme = await prisma.aufnahme.findUnique({
where: {
id: ausweis.aufnahme_id,
},
include: {
objekt: true,
bilder: true,
},
});
if (!aufnahme) {
return;
}
let info: string = "";
const ausweisart = getAusweisartFromUUID(ausweis.uid);
const attachments: any[] = [];
if (ausweisart != Enums.Ausweisart.BedarfsausweisWohnen) {
const ansichtsausweis = await getAnsichtsausweis(
ausweis,
aufnahme,
aufnahme.objekt,
aufnahme.bilder,
user,
ausweisart
);
if (ansichtsausweis) {
attachments.push([
{
filename: "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.";
} else {
info =
"Die Erstellung des Bedarfsausweises dauert momentan leider etwas länger. Bitte kontaktieren Sie uns in dringenden Fällen telefonisch (9 - 12 Uhr).";
}
await transport.sendMail({
attachments,
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${ausweis.uid})`,
cc: {
address: rechnung.email || "",
name: rechnung.empfaenger || "",
},
bcc: "info@online-energieausweis.org",
html: `<p>Sehr geehrte/r ${user.name},
<br>
<br>
vielen Dank für ihre Bestellung. Wir werden Ihnen Originalausweis und Rechnung nach Prüfung zuschicken. ${info} Die Ausstellung erfolgt nach aktuellem GEG und Ihr Ausweis wird beim DIBT registriert.<br><br>
Den Rechnungsbetrag haben Sie bereits bezahlt. Vielen Dank.</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

@@ -8,16 +8,16 @@ export async function getObjektKomplettClient(uid: string): Promise<ObjektKomple
uid
},
include: {
bilder: true,
aufnahmen: {
include: {
bedarfsausweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
verbrauchsausweis_wohnen: true,
bilder: true,
unterlagen: true,
bedarfsausweise_wohnen: true,
verbrauchsausweise_gewerbe: true,
verbrauchsausweise_wohnen: true,
events: true
}
},
unterlagen: true
}
})
@@ -26,27 +26,29 @@ export async function getObjektKomplettClient(uid: string): Promise<ObjektKomple
}
return {
...omit(objekt, ["benutzer_id", "id", "aufnahmen", "bilder"]),
...omit(objekt, ["benutzer_id", "id"]),
aufnahmen: objekt.aufnahmen.map(aufnahme => ({
...omit(aufnahme, ["id", "objekt_id", "benutzer_id", "bedarfsausweis_wohnen", "verbrauchsausweis_gewerbe", "verbrauchsausweis_wohnen"]),
bedarfsausweis_wohnen: (aufnahme.bedarfsausweis_wohnen && {
...omit(aufnahme.bedarfsausweis_wohnen, ["id", "aufnahme_id", "benutzer_id"]),
...omit(aufnahme, ["id", "objekt_id", "benutzer_id", "bedarfsausweise_wohnen", "verbrauchsausweise_gewerbe", "verbrauchsausweise_wohnen"]),
bedarfsausweise_wohnen: aufnahme.bedarfsausweise_wohnen.map(ausweis => ({
...omit(ausweis, ["id", "aufnahme_id", "benutzer_id"]),
uid_aufnahme: aufnahme.uid,
uid_objekt: objekt.uid
}) || undefined,
verbrauchsausweis_wohnen: (aufnahme.verbrauchsausweis_wohnen && {
...omit(aufnahme.verbrauchsausweis_wohnen, ["id", "aufnahme_id", "benutzer_id"]),
uid_aufnahme: aufnahme.uid,
uid_objekt: objekt.uid
}) || undefined,
verbrauchsausweis_gewerbe: (aufnahme.verbrauchsausweis_gewerbe && {
...omit(aufnahme.verbrauchsausweis_gewerbe, ["id", "aufnahme_id", "benutzer_id"]),
uid_aufnahme: aufnahme.uid,
uid_objekt: objekt.uid
}) || undefined,
uid_objekt: objekt.uid,
})),
bilder: objekt.bilder.map(bild => omit(bild, ["id", "objekt_id"])),
unterlagen: objekt.unterlagen.map(unterlage => omit(unterlage, ["id", "objekt_id"]))
verbrauchsausweise_wohnen:
aufnahme.verbrauchsausweise_wohnen.map(ausweis => ({
...omit(ausweis, ["id", "aufnahme_id", "benutzer_id"]),
uid_aufnahme: aufnahme.uid,
uid_objekt: objekt.uid
})),
verbrauchsausweise_gewerbe:
aufnahme.verbrauchsausweise_gewerbe.map(ausweis => ({
...omit(ausweis, ["id", "aufnahme_id", "benutzer_id"]),
uid_aufnahme: aufnahme.uid,
uid_objekt: objekt.uid
})),
uid_objekt: objekt.uid,
bilder: aufnahme.bilder.map(bild => omit(bild, ["id", "aufnahme_id"])),
unterlagen: aufnahme.unterlagen.map(unterlage => omit(unterlage, ["id", "aufnahme_id"]))
}))
}
}

View File

@@ -175,7 +175,7 @@ lg:grid-cols-2 lg:gap-x-6
<div id="progress-box" class="w-full box relative px-4 py-3 text-center order-2 self-stretch">
<h1 class="text-secondary text-3xl m-0">Energiesausweis erstellen</h1>
<h2 class="text-primary text-xl">{ausweisart} {PRICES.VerbrauchsausweisWohnen[0]}</h2>
<h2 class="text-primary text-xl">{ausweisart} {PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard]}</h2>
<ProgressBar step1={'step'}/>
</div>

View File

@@ -0,0 +1,44 @@
<script lang="ts">
import { AufnahmeKomplettClient, BenutzerClient } from "#components/Ausweis/types.js";
import Carousel from "#components/Carousel.svelte";
import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte";
import { Objekt } from "@ibcornelsen/database/client";
import { ChevronLeft, ChevronRight, Plus } from "radix-svelte-icons";
export let user: BenutzerClient;
export let aufnahme: AufnahmeKomplettClient;
export let objekt: Objekt;
</script>
<h1 class="text-4xl font-medium mb-8">{objekt.adresse}, {objekt.plz} {objekt.ort}</h1>
<div class="bg-white rounded-lg">
{#if aufnahme.bilder.length > 0}
<Carousel perPage={1}>
{#each aufnahme.bilder as bild, i (i)}
<img src="/bilder/{bild.uid}.webp" alt={bild.kategorie} class="max-h-[60vh] h-full w-full object-contain">
{/each}
<span slot="left-control" class="p-2.5 bg-opacity-50 bg-white block rounded-full"><ChevronLeft size={24}></ChevronLeft></span>
<span slot="right-control" class="p-2.5 bg-opacity-50 bg-white block rounded-full"><ChevronRight size={24}></ChevronRight></span>
</Carousel>
{/if}
</div>
<div class="flex flex-row gap-4">
<button class="button flex flex-row rounded-lg gap-2"><Plus size={20}></Plus> Verbrauchsausweis Wohnen Erstellen</button>
<button class="button flex flex-row rounded-lg gap-2"><Plus size={20}></Plus> Verbrauchsausweis Gewerbe Erstellen</button>
<button class="button flex flex-row rounded-lg gap-2"><Plus size={20}></Plus> Bedarfsausweis Erstellen</button>
</div>
<div class="my-8 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>
{/each}
{#each aufnahme.bedarfsausweise_wohnen as ausweis}
<DashboardAusweis {ausweis} {aufnahme} {objekt} progress={0}></DashboardAusweis>
{/each}
{#each aufnahme.verbrauchsausweise_gewerbe as ausweis}
<DashboardAusweis {ausweis} {aufnahme} {objekt} progress={0}></DashboardAusweis>
{/each}
</div>

View File

@@ -62,7 +62,7 @@
{#if ausweise.length == 0}
<div class="">
<h1 class="text-2xl">Es konnten keine Ausweise gefunden werden.</h1>
<p>Erstellen sie einen Verbrauchsausweis für ihr Wohngebäude <a href="/energieausweis-erstellen/verbrauchsausweis-wohnen">hier</a></p>
<p>Erstellen sie einen Verbrauchsausweis für ihr Wohngebäude <a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude">hier</a></p>
</div>
{:else}
{#each ausweise as ausweis, i}

View File

@@ -1,26 +1,43 @@
<script lang="ts">
import {
AufnahmeClient,
ObjektClient,
UploadedGebaeudeBild,
VerbrauchsausweisWohnenClient,
} from "#components/Ausweis/types.js";
import AusweisPruefenBox from "#components/AusweisPruefenBox.svelte";
import NotificationProvider from "#components/NotificationProvider/NotificationProvider.svelte";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import AusweisPruefenNotification from "#components/AusweisPruefenNotification.svelte";
import DashboardAusweisSkeleton from "#components/Dashboard/DashboardAusweisSkeleton.svelte"
import { Event } from "@ibcornelsen/database/client";
import Pagination from "#components/Pagination.svelte";
import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie"
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js"
import AusweisePruefenFilter from "#components/Dashboard/AusweisePruefenFilter.svelte";
import { z, ZodTypeAny } from "zod";
import { filterAusweise } from "#lib/filters.js";
export let ausweise: {
ausweis: VerbrauchsausweisWohnenClient,
aufnahme: AufnahmeClient,
objekt: ObjektClient,
bilder: UploadedGebaeudeBild[],
events: Event[]
}[];
export let page: number;
export let totalPages: number;
let filters: { name: keyof z.infer<typeof filterAusweise>, type: ZodTypeAny, value: any }[] = []
</script>
<div class="flex flex-col mb-4">
<AusweisePruefenFilter bind:filters={filters}></AusweisePruefenFilter>
</div>
<div class="gap-4 flex flex-col">
{#await api.ausweise.GET.fetch({
limit: 10,
skip: (page - 1) * 10,
filters: filters.reduce((acc, filter) => {
acc[filter.name] = filter.value
return acc
}, {})
}, {
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})}
<DashboardAusweisSkeleton></DashboardAusweisSkeleton>
{:then ausweise}
{#each ausweise as { ausweis, objekt, aufnahme, bilder, events }}
{#await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt)}
<div class="rounded-lg border w-full h-20 p-2.5 gap-4 flex flex-row items-center">
@@ -98,16 +115,11 @@
<AusweisPruefenBox {ausweis} {aufnahme} {objekt} {bilder} {events} {calculations}></AusweisPruefenBox>
{/await}
{/each}
{/await}
</div>
<div class="flex items-center justify-center mt-12">
<div class="join">
<button class="join-item btn btn-ghost shadow-none">1</button>
<button class="join-item btn btn-ghost shadow-none">2</button>
<button class="join-item btn btn-ghost shadow-none">3</button>
<button class="join-item btn btn-ghost shadow-none">4</button>
</div>
</div>
<Pagination pages={totalPages} current={page} prev="/dashboard/admin/ausweise-pruefen/{page - 1}" next="/dashboard/admin/ausweise-pruefen/{page + 1}"></Pagination>
<div class="fixed bottom-8 right-8 flex flex-col gap-4">
<NotificationProvider component={AusweisPruefenNotification}></NotificationProvider>

View File

@@ -161,7 +161,7 @@
<style>
:global(.tab-list) {
@apply menu flex flex-col gap-2 px-0 bg-base-200 rounded-lg border border-base-300;
@apply flex flex-col gap-2 px-0 bg-base-200 rounded-lg border;
}
@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");
@@ -171,15 +171,15 @@
}
:global(.tab.selected) {
@apply bg-base-300;
@apply bg-gray-200;
}
:global(.tab) {
@apply btn btn-primary btn-ghost rounded-none px-8 justify-start outline-0 gap-4 items-center text-base font-normal text-base-content no-animation;
@apply rounded-none px-8 justify-start outline-0 gap-4 items-center text-base font-normal text-base-content;
}
:global(.tab:hover) {
@apply bg-base-300 outline-0;
@apply bg-gray-200 outline-0;
}
:global(.tab:focus) {

View File

@@ -13,7 +13,7 @@
</p>
<h1 class="text-4xl font-medium my-8">Gebäude</h1>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
<div class="columns columns-1 md:columns-2 lg:columns-3 gap-4">
{#each objekte as objekt}
<DashboardObjekt {objekt}></DashboardObjekt>
{/each}

View File

@@ -1,33 +0,0 @@
<script lang="ts">
import { BenutzerClient, ObjektKomplettClient } from "#components/Ausweis/types.js";
import Carousel from "#components/Carousel.svelte";
import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte";
import { ChevronLeft, ChevronRight } from "radix-svelte-icons";
export let user: BenutzerClient;
export let objekt: ObjektKomplettClient;
</script>
<h1 class="text-4xl font-medium mb-8">{objekt.adresse}</h1>
<div class="bg-white rounded-lg">
<Carousel perPage={1}>
{#each objekt.bilder as bild, i (i)}
<img src="/bilder/{bild.uid}.webp" alt={bild.kategorie} class="max-h-[60vh] h-full w-full object-contain">
{/each}
<span slot="left-control" class="p-2.5 bg-opacity-50 bg-white block rounded-full"><ChevronLeft size={24}></ChevronLeft></span>
<span slot="right-control" class="p-2.5 bg-opacity-50 bg-white block rounded-full"><ChevronRight size={24}></ChevronRight></span>
</Carousel>
</div>
<div class="my-8 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
{#each objekt.aufnahmen as aufnahme}
{@const ausweis = aufnahme.verbrauchsausweis_wohnen ?? aufnahme.verbrauchsausweis_gewerbe ?? aufnahme.bedarfsausweis_wohnen}
{#if !ausweis}
<p>Diese Aufnahme hat noch keinen Ausweis.</p>
{:else}
<DashboardAusweis {ausweis} {aufnahme} {objekt} progress={0}></DashboardAusweis>
{/if}
{/each}
</div>

View File

@@ -4,6 +4,8 @@
import EmbeddedRegisterModule from "./EmbeddedRegisterModule.svelte"
export let onLogin: (response: Awaited<ReturnType<typeof loginClient>>) => any;
export let email: string = "";
export let password: string = "";
let route: "login" | "signup" = "login"
@@ -12,16 +14,16 @@
}
const loginData = {
email: "",
email,
passwort: "",
}
</script>
{#if route == "login"}
<EmbeddedLoginModule onLogin={onLogin} data={loginData} {navigate} />
<EmbeddedLoginModule onLogin={onLogin} bind:email bind:password {navigate} />
{:else}
<EmbeddedRegisterModule onRegister={(response) => {
loginData.email = response.email
<EmbeddedRegisterModule bind:email bind:password onRegister={(response) => {
email = response.email
navigate("login")
}} {navigate} />
{/if}

View File

@@ -3,13 +3,14 @@
import { loginClient } from "#lib/login.js";
export let navigate: (target: string) => void;
export let data: { email: string; passwort: string };
export let email: string;
export let password: string;
export let onLogin: (response: Awaited<ReturnType<typeof loginClient>>) => any;
async function login(e: SubmitEvent) {
e.preventDefault()
const response = await loginClient(data.email, data.passwort)
const response = await loginClient(email, password)
if (response === null) {
addNotification({
@@ -35,7 +36,7 @@
type="email"
placeholder="Email"
name="email"
bind:value={data.email}
bind:value={email}
required
/>
</div>
@@ -46,7 +47,7 @@
type="password"
placeholder="********"
name="passwort"
bind:value={data.passwort}
bind:value={password}
required
/>
</div>

View File

@@ -4,8 +4,8 @@
export let navigate: (target: string) => void;
export let onRegister: (response: { email: string, name: string, vorname: string }) => void;
let passwort: string;
let email: string;
export let password: string;
export let email: string;
let vorname: string;
let name: string;
@@ -14,7 +14,7 @@
try {
const response = await api.user.PUT.fetch({
email,
passwort,
passwort: password,
vorname,
name,
});
@@ -82,7 +82,7 @@
placeholder="********"
name="passwort"
class="px-2.5 py-1.5 rounded-lg border bg-gray-50"
bind:value={passwort}
bind:value={password}
required
/>
</div>

View File

@@ -16,7 +16,7 @@
export let ausweis:
| VerbrauchsausweisWohnenClient;
// TODO: überarbeiten und zu inferProcedureOutput machen
let rechnung: RechnungClient = {
let rechnung: Partial<RechnungClient> = {
email: user.email,
empfaenger: user.vorname + " " + user.name,
strasse: user.adresse,
@@ -56,7 +56,7 @@
},
];
export let selectedPaymentType: Bezahlmethoden =
export let aktiveBezahlmethode: Bezahlmethoden =
Enums.Bezahlmethoden.paypal;
async function createPayment(e: SubmitEvent) {
@@ -67,14 +67,14 @@
...rechnung,
ausweisart: Enums.Ausweisart.VerbrauchsausweisWohnen,
ausweis_uid: ausweis.uid,
bezahlmethode: selectedPaymentType,
bezahlmethode: aktiveBezahlmethode,
services: services
.filter((service) => service.selected)
.map((service) => service.id),
});
if (selectedPaymentType === Enums.Bezahlmethoden.rechnung) {
window.location.href = `/payment/success?uid=${response.uid}`
if (aktiveBezahlmethode === Enums.Bezahlmethoden.rechnung) {
window.location.href = `/payment/success?r=${response.uid}&a=${ausweis.uid}`
} else {
window.location.href = response.checkout_url as string;
}
@@ -315,32 +315,32 @@
class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-row gap-4 justify-between"
>
<PaymentOption
paymentType={Enums.Bezahlmethoden.paypal}
bind:selectedPaymentType
bezahlmethode={Enums.Bezahlmethoden.paypal}
bind:aktiveBezahlmethode
name={"PayPal"}
icon={"/images/paypal.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.sofort}
bind:selectedPaymentType
bezahlmethode={Enums.Bezahlmethoden.sofort}
bind:aktiveBezahlmethode
name={"Sofort"}
icon={"/images/sofort.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.giropay}
bind:selectedPaymentType
bezahlmethode={Enums.Bezahlmethoden.giropay}
bind:aktiveBezahlmethode
name={"Giropay"}
icon={"/images/giropay.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.creditcard}
bind:selectedPaymentType
bezahlmethode={Enums.Bezahlmethoden.creditcard}
bind:aktiveBezahlmethode
name={"Kreditkarte"}
icon={"/images/mastercard.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.rechnung}
bind:selectedPaymentType
bezahlmethode={Enums.Bezahlmethoden.rechnung}
bind:aktiveBezahlmethode
name={"Rechnung"}
icon={"/images/rechnung.png"}
></PaymentOption>

View File

@@ -4,29 +4,44 @@
import Bereich from "#components/labels/Bereich.svelte";
import Ansprechpartner from "#components/Ausweis/Ansprechpartner.svelte";
import Rechnungsadresse from "#components/Ausweis/Rechnungsadresse.svelte";
import Bezahlung from "#components/Ausweis/Bezahlung.svelte";
import type { Bezahlmethoden } from "@ibcornelsen/database/client";
import { Enums } from "@ibcornelsen/database/client";
import { dialogs } from "svelte-dialogs";
import LoginDialog from "#components/LoginDialog.svelte";
import { API_ACCESS_TOKEN_COOKIE_NAME, PRICES } from "#lib/constants.js";
import {
API_ACCESS_TOKEN_COOKIE_NAME,
PRICES,
} from "#lib/constants.js";
import Cookies from "js-cookie";
import {
AufnahmeClient,
BenutzerClient,
getAusweisartFromUUID,
BildClient,
ObjektClient,
RechnungClient,
UnterlageClient,
VerbrauchsausweisWohnenClient,
} from "#components/Ausweis/types.js";
import { validateAccessTokenClient } from "src/client/lib/validateAccessToken.js";
import { api } from "astro-typesafe-api/client";
import PaymentOption from "#components/PaymentOption.svelte";
import Overlay from "#components/Overlay.svelte";
import EmbeddedAuthFlowModule from "./EmbeddedAuthFlowModule.svelte";
import { ausweisSpeichern } from "#client/lib/ausweisSpeichern.js";
import { addNotification } from "#components/Notifications/shared.js";
import NotificationWrapper from "#components/Notifications/NotificationWrapper.svelte";
import { nachweisSpeichern } from "#client/lib/nachweisSpeichern.js";
import { EnterFullScreen } from "radix-svelte-icons";
export let user: BenutzerClient;
export let user: Partial<BenutzerClient>;
export let ausweis: VerbrauchsausweisWohnenClient;
export let aufnahme: AufnahmeClient;
export let objekt: ObjektClient;
export let bilder: BildClient[];
export let unterlagen: UnterlageClient[];
export let ausweisart: Enums.Ausweisart;
export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal;
export let ausweistyp: Enums.AusweisTyp = Enums.AusweisTyp.Standard;
let rechnung: Partial<RechnungClient> = {
email: user.email,
@@ -39,9 +54,14 @@
versand_plz: user.plz,
versand_ort: user.ort,
telefon: user.telefon,
}
};
let services: { name: string, id: Enums.Service, price: number, selected: boolean }[] = [
let services: {
name: string;
id: Enums.Service;
price: number;
selected: boolean;
}[] = [
{
name: "Qualitätsdruck per Post (zusätzlich zur PDF Version)",
id: Enums.Service.Qualitaetsdruck,
@@ -68,12 +88,9 @@
},
];
export let bezahlmethode: Bezahlmethoden =
Enums.Bezahlmethoden.paypal;
let prices = PRICES[ausweisart];
let basePrice: number = prices[0];
let basePrice: number = prices[ausweistyp];
$: price =
basePrice +
@@ -83,12 +100,21 @@
);
const zurueck = {
[Enums.Ausweisart.VerbrauchsausweisWohnen]: `/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid=${ausweis.uid}`,
[Enums.Ausweisart.VerbrauchsausweisGewerbe]: `/energieausweis-erstellen/verbrauchsausweis-gewerbe?uid=${ausweis.uid}`,
[Enums.Ausweisart.BedarfsausweisWohnen]: `/energieausweis-erstellen/bedarfsausweis-wohnen?uid=${ausweis.uid}`,
[Enums.Ausweisart.BedarfsausweisGewerbe]: `/energieausweis-erstellen/bedarfsausweis-gewerbe?uid=${ausweis.uid}`,
[Enums.Ausweisart.GEGNachweisWohnen]: `/angebot-anfragen/geg-nachweis-wohnen-anfragen?uid=${ausweis.uid}`,
}[ausweisart]
[Enums.Ausweisart.VerbrauchsausweisWohnen]:
`/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?uid=${ausweis.uid}`,
[Enums.Ausweisart.VerbrauchsausweisGewerbe]:
`/energieausweis-erstellen/verbrauchsausweis-gewerbe?uid=${ausweis.uid}`,
[Enums.Ausweisart.BedarfsausweisWohnen]:
`/energieausweis-erstellen/bedarfsausweis-wohnen?uid=${ausweis.uid}`,
[Enums.Ausweisart.BedarfsausweisGewerbe]:
`/energieausweis-erstellen/bedarfsausweis-gewerbe?uid=${ausweis.uid}`,
[Enums.Ausweisart.GEGNachweisWohnen]:
`/angebot-anfragen/geg-nachweis-wohnen-anfragen?uid=${ausweis.uid}`,
[Enums.Ausweisart.GEGNachweisGewerbe]:
`/angebot-anfragen/geg-nachweis-gewerbe-anfragen?uid=${ausweis.uid}`,
[Enums.Ausweisart.GEGNachweisBedarfsausweis]:
`/angebot-anfragen/bedarfsausweis-gewerbe-anfragen?uid=${ausweis.uid}`,
}[ausweisart];
async function speichern(e: SubmitEvent) {
e.preventDefault();
@@ -109,21 +135,49 @@
// uid: ausweis.uid,
// });
localStorage.clear();
window.location.href = `/kaufabschluss?uid=${ausweis.uid}`;
}
async function anfordern() {
// TODO Angebot anfordern
if (!form.checkValidity()) {
addNotification({
dismissable: true,
message: "Fehlende Daten.",
subtext: "Nicht alle notwendigen Felder sind ausgefüllt, bitte füllen sie diese aus bevor sie es erneut versuchen.."
})
form.reportValidity();
return;
}
async function bestellen() {
const ausweisart = getAusweisartFromUUID(ausweis.uid) as Enums.Ausweisart;
if (!await validateAccessTokenClient()) {
loginAction = bestellen
rechnung = rechnung
loginOverlayHidden = false;
return
}
loginOverlayHidden = true
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | null = null;
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)
}
if (result === null) {
addNotification({
dismissable: true,
message: "Ups... Das hat nicht geklappt.",
subtext: "Der Nachweis konnte nicht gespeichert werden, bitte versuchen sie es erneut oder kontaktieren sie unseren Support."
})
}
try {
const { uid, checkout_url } = await api.rechnung.PUT.fetch({
ausweisart,
bezahlmethode,
services: services.filter(service => service.selected).map(service => service.id),
const { uid } = await api.rechnung.anfordern.PUT.fetch(
{
email: rechnung.email,
empfaenger: rechnung.empfaenger,
strasse: rechnung.strasse,
@@ -134,23 +188,109 @@
versand_plz: rechnung.versand_plz,
versand_ort: rechnung.versand_ort,
telefon: rechnung.telefon,
ausweis_uid: ausweis.uid
}, {
nachweis_uid: ausweis.uid,
},
{
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
}
);
// Alle alten Ausweisdateien im localStorage löschen.
localStorage.clear();
window.location.href = `/einpreisung/success?e=${uid}&a=${ausweis.uid}`;
} catch (e) {
addNotification({
dismissable: true,
message: "Ups... Das hat nicht geklappt.",
subtext: "Beim erstellen des Nachweises ist etwas schiefgelaufen, bitte versuchen sie es erneut oder kontaktieren sie unseren Support."
})
}
}
async function bestellen() {
if (!form.checkValidity()) {
addNotification({
dismissable: true,
message: "Fehlende Daten.",
subtext: "Nicht alle notwendigen Felder sind ausgefüllt, bitte füllen sie diese aus bevor sie es erneut versuchen.."
})
if (bezahlmethode === Enums.Bezahlmethoden.rechnung) {
window.location.href = `/payment/success?uid=${uid}`
form.reportValidity();
return;
}
if (!await validateAccessTokenClient()) {
loginAction = bestellen
rechnung = rechnung
loginOverlayHidden = false;
return
}
loginOverlayHidden = true
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | null = null;
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)
}
if (result === null) {
addNotification({
dismissable: true,
message: "Ups... Das hat nicht geklappt.",
subtext: "Der Ausweis konnte nicht gespeichert werden, bitte versuchen sie es erneut oder kontaktieren sie unseren Support."
})
}
try {
const { uid, checkout_url } = await api.rechnung.PUT.fetch(
{
ausweisart,
bezahlmethode: aktiveBezahlmethode,
services: services
.filter((service) => service.selected)
.map((service) => service.id),
email: rechnung.email,
empfaenger: rechnung.empfaenger,
strasse: rechnung.strasse,
plz: rechnung.plz,
ort: rechnung.ort,
versand_empfaenger: rechnung.versand_empfaenger,
versand_strasse: rechnung.versand_strasse,
versand_plz: rechnung.versand_plz,
versand_ort: rechnung.versand_ort,
telefon: rechnung.telefon,
ausweis_uid: ausweis.uid,
ausweistyp,
},
{
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
}
);
// Alle alten Ausweisdateien im localStorage löschen.
localStorage.clear();
if (aktiveBezahlmethode === Enums.Bezahlmethoden.rechnung) {
window.location.href = `/payment/success?r=${uid}&a=${ausweis.uid}`;
} else {
window.location.href = checkout_url as string;
}
} catch (e) {
addNotification({
dismissable: true,
message: "Ups... Das hat nicht geklappt.",
subtext: "Beim erstellen des Ausweises ist etwas schiefgelaufen, bitte versuchen sie es erneut oder kontaktieren sie unseren Support."
})
}
}
/**
* TODO
* Ausschlusskriterien: Neubau, Modernisierung
@@ -162,11 +302,30 @@
Fehlende Angaben zum Sanierungsstand (Bei F mindestens 2 Haken), (Bei G mindestens 1 Haken)
*/
let bestellenNichtMoeglich = false;
if (((ausweis.ausstellgrund === "Neubau" || ausweis.ausstellgrund === "Modernisierung") && aufnahme.baujahr_gebaeude[0] < 1978 && aufnahme.saniert === false && aufnahme.einheiten && aufnahme.einheiten > 4) || (new Date().getFullYear() - aufnahme.baujahr_heizung[0] < 3) || (!ausweis.verbrauch_1 || !ausweis.verbrauch_2 || !ausweis.verbrauch_3) || (aufnahme.leerstand && aufnahme.leerstand > 30)) {
bestellenNichtMoeglich = true
if (
((ausweis.ausstellgrund === "Neubau" ||
ausweis.ausstellgrund === "Modernisierung") &&
aufnahme.baujahr_gebaeude[0] < 1978 &&
aufnahme.saniert === false &&
aufnahme.einheiten &&
aufnahme.einheiten > 4) ||
new Date().getFullYear() - aufnahme.baujahr_heizung[0] < 3 ||
!ausweis.verbrauch_1 ||
!ausweis.verbrauch_2 ||
!ausweis.verbrauch_3 ||
(aufnahme.leerstand && aufnahme.leerstand > 30)
) {
bestellenNichtMoeglich = true;
}
const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis) || (ausweisart === Enums.Ausweisart.GEGNachweisGewerbe)
const gegAnfrage =
ausweisart === Enums.Ausweisart.GEGNachweisWohnen ||
ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis ||
ausweisart === Enums.Ausweisart.GEGNachweisGewerbe;
let loginOverlayHidden = true;
let loginAction = () => {};
let form: HTMLFormElement;
</script>
<div
@@ -177,11 +336,14 @@ const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (auswe
"
>
{#if !gegAnfrage}
<div id="performance-box" class="w-full box relative px-4 order-1 self-stretch grid grid-cols-1">
<div
id="performance-box"
class="w-full box relative px-4 order-1 self-stretch grid grid-cols-1"
>
<PerformanceScore
bind:ausweis
bind:aufnahme={aufnahme}
bind:objekt={objekt}
bind:aufnahme
bind:objekt
{ausweisart}
/>
</div>
@@ -193,17 +355,21 @@ const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (auswe
>
<h1 class="text-secondary text-3xl m-0">Energiesausweis erstellen</h1>
<h2 class="text-primary text-xl">
{ausweisart} {prices[0]}
{ausweisart}
{prices[ausweistyp]}
</h2>
{#if gegAnfrage}
<Progressbar active={1} steps={["Gebäudedaten", "Kundendaten", "Bestätigung"]}/>
<Progressbar
active={1}
steps={["Gebäudedaten", "Kundendaten", "Bestätigung"]}
/>
{:else}
<Progressbar active={1} />
{/if}
</div>
</div>
<div id="formInput-2">
<form id="formInput-2" bind:this={form}>
<div id="formular-box" class="formular-boxen ring-0">
<Bereich
bereich="1"
@@ -213,12 +379,47 @@ const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (auswe
>
<Bereich bereich="2" title="Rechnungsadresse">
<Rechnungsadresse bind:user bind:rechnung /></Bereich
<Rechnungsadresse bind:rechnung /></Bereich
>
{#if !gegAnfrage}
<Bereich bereich="3" title="Bezahlmethode">
<Bezahlung bind:selectedPaymentType={bezahlmethode} /></Bereich
<div
id="bezahlung"
class="bereich-box grid
grid-cols-5 justify-around justify-items-center items-center"
>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.paypal}
bind:aktiveBezahlmethode
name={"PayPal"}
icon={"/images/paypal.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.sofort}
bind:aktiveBezahlmethode
name={"Sofort"}
icon={"/images/sofort.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.giropay}
bind:aktiveBezahlmethode
name={"Giropay"}
icon={"/images/giropay.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.creditcard}
bind:aktiveBezahlmethode
name={"Kreditkarte"}
icon={"/images/creditcard.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.rechnung}
bind:aktiveBezahlmethode
name={"Rechnung"}
icon={"/images/rechnung.png"}
></PaymentOption>
</div></Bereich
>
<div class="grid grid-cols-2 gap-x-6 my-6">
<div class="zusaetze bereich-box bg-white">
@@ -243,8 +444,14 @@ const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (auswe
<div class="ProduktKostenTabelle">
<div class="zeile betrag">
<div>Netto-Preis Energieausweis</div>
<div>:</div>
{#if ausweistyp === Enums.AusweisTyp.Standard}
<span>Netto-Preis Energieausweis</span>
{:else if ausweistyp === Enums.AusweisTyp.Beratung}
<span>Energieausweis inkl. Beratung</span>
{:else if ausweistyp === Enums.AusweisTyp.Offline}
<span>Energieausweis Offline</span>
{/if}
<span>:</span>
<div class="text-right">
<b>{(price * 0.81).toFixed(2) + " €"}</b>
</div>
@@ -275,8 +482,8 @@ const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (auswe
<div>:</div>
<div class="justify-self-end">
<img
src="images/{bezahlmethode}.png"
alt={bezahlmethode}
src="images/{aktiveBezahlmethode}.png"
alt={aktiveBezahlmethode}
/>
</div>
</div>
@@ -292,16 +499,35 @@ const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (auswe
<div></div>
<button class="button">Speichern</button>
<button class="button" type="button">Speichern</button>
{#if gegAnfrage}
<button class="button cursor-pointer" data-cy="bestellen" on:click={anfordern} >Angebot anfordern</button>
<button
class="button cursor-pointer"
type="button"
data-cy="bestellen"
on:click={anfordern}>Angebot anfordern</button
>
{:else}
<button class="button cursor-pointer" data-cy="bestellen" on:click={bestellen} >Kostenpflichtig bestellen</button>
<button
class="button cursor-pointer"
data-cy="bestellen"
type="button"
on:click={bestellen}>Kostenpflichtig bestellen</button
>
{/if}
</div>
</div>
<Overlay bind:hidden={loginOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm py-8">
<EmbeddedAuthFlowModule onLogin={loginAction} email={rechnung.email}></EmbeddedAuthFlowModule>
</div>
</Overlay>
</form>
<NotificationWrapper></NotificationWrapper>
<!--
<div class="bereich-box pr-12 mt-6">
@@ -434,7 +660,6 @@ const gegAnfrage = (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) || (auswe
<!-- <ButtonZurueckSpeichernKaufabschluss bind:ausweis bind:aufnahme bind:objekt bind:bilder bind:user /> -->
<style lang="postcss">
h3 {
@apply text-[1.25rem] ml-0 font-bold mb-6;

View File

@@ -21,14 +21,59 @@
import GebaeudeDaten from "#components/Ausweis/GebaeudeDaten.svelte";
import { Enums } from "@ibcornelsen/database/client";
import moment from "moment";
import {
AuditType,
hidden,
} from "#components/Verbrauchsausweis/audits/hidden.js";
import { auditBedarfsausweisBenoetigt } from "#components/Verbrauchsausweis/audits/BedarfsausweisBenoetigt.js";
import { auditEndEnergie } from "#components/Verbrauchsausweis/audits/EndEnergie.js";
import { auditHeizungGebaeudeBaujahr } from "#components/Verbrauchsausweis/audits/HeizungGebaeudeBaujahr.js";
import { auditHeizungJuengerDreiJahre } from "#components/Verbrauchsausweis/audits/HeizungJuengerDreiJahre.js";
import { auditKlimaFaktoren } from "#components/Verbrauchsausweis/audits/KlimaFaktoren.js";
import { auditLeerStand } from "#components/Verbrauchsausweis/audits/LeerStand.js";
import { auditPlzNichtErkannt } from "#components/Verbrauchsausweis/audits/PlzNichtErkannt.js";
import { auditVerbrauchAbweichung } from "#components/Verbrauchsausweis/audits/VerbrauchAbweichung.js";
import { auditWarmWasser } from "#components/Verbrauchsausweis/audits/WarmWasser.js";
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";
export let ausweis: VerbrauchsausweisGewerbeClient;
export let user: BenutzerClient = {} as BenutzerClient;
export let objekt: ObjektClient = {} as ObjektClient;
export let aufnahme: AufnahmeClient = {} as AufnahmeClient;
export let bilder: UploadedGebaeudeBild[] = [];
export let user: BenutzerClient;
export let objekt: ObjektClient;
export let aufnahme: AufnahmeClient;
export let bilder: UploadedGebaeudeBild[];
export let ausweisart = Enums.Ausweisart.VerbrauchsausweisGewerbe;
if (Object.keys(ausweis).length === 0) {
const localStorageAusweis = localStorage.getItem("ausweis");
if (localStorageAusweis) {
ausweis = JSON.parse(localStorageAusweis)
}
}
if (Object.keys(aufnahme).length === 0) {
const localStorageAufnahme = localStorage.getItem("aufnahme");
if (localStorageAufnahme) {
aufnahme = JSON.parse(localStorageAufnahme)
}
}
if (Object.keys(objekt).length === 0) {
const localStorageObjekt = localStorage.getItem("objekt");
if (localStorageObjekt) {
objekt = JSON.parse(localStorageObjekt)
}
}
if (Object.keys(bilder).length === 0) {
const localStorageBilder = localStorage.getItem("bilder");
if (localStorageBilder) {
bilder = JSON.parse(localStorageBilder)
}
}
function automatischAusfüllen() {
aufnahme.baujahr_gebaeude = [1952];
aufnahme.baujahr_heizung = [1952];
@@ -62,7 +107,12 @@
ausweis = ausweis;
}
async function spaeterWeitermachen() {
$: {
localStorage.setItem("ausweis", JSON.stringify(ausweis))
localStorage.setItem("aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("objekt", JSON.stringify(objekt))
localStorage.setItem("bilder", JSON.stringify(bilder))
}
</script>
@@ -84,7 +134,7 @@
<div id="progress-box" class="w-full box relative px-4 py-3 text-center order-1 2xl:order-2 self-stretch">
<h1 class="text-secondary text-3xl m-0">Energiesausweis erstellen</h1>
<h2 class="text-primary text-xl">Verbrauchsausweis Gewerbe {PRICES.VerbrauchsausweisGewerbe[0]}</h2>
<h2 class="text-primary text-xl">Verbrauchsausweis Gewerbe {PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard]}</h2>
<Progressbar active={0} />
</div>
@@ -97,7 +147,16 @@
<form id="formInput-1" data-cy="ausweis" name="ausweis">
<div id="formular-box" class="formular-boxen ring-0">
<ButtonSpaeterHilfe {automatischAusfüllen} {spaeterWeitermachen} />
<ButtonWeiterHilfe
bind:ausweis
bind:bilder
bind:user
bind:objekt
bind:aufnahme
ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen}
showWeiter={false}
>
</ButtonWeiterHilfe>
<!-- A Prüfung der Ausweisart -->
@@ -130,7 +189,6 @@
title="Eingabe von 3 zusammenhängenden Verbrauchsjahren"
>
<StromVerbrauch
bind:objekt
bind:aufnahme
bind:ausweis
/>
@@ -201,7 +259,7 @@
</div>
<ButtonWeiterHilfe {spaeterWeitermachen}
<ButtonWeiterHilfe
bind:ausweis
bind:bilder
bind:user
@@ -213,3 +271,267 @@
</form>
<RawNotificationWrapper class="fixed left-8 bottom-8 max-w-[400px] flex flex-col gap-4 z-50">
{#each Object.entries($notifications) as [uid, notification] (uid)}
<RawNotification notification={{ ...notification, uid }}>
{@html notification.subtext}
</RawNotification>
{/each}
{#if auditBedarfsausweisBenoetigt(ausweis, aufnahme)}
<RawNotification
notification={{
message: "Bedarfsausweis benötigt!",
timeout: 0,
uid: "BEDARFSAUSWEIS",
dismissable: false,
type: "info",
}}
>
Sie benötigen einen Bedarfsausweis. <a href="/energieausweis-erstellen/bedarfsausweis-erstellen"
>Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort</a
>.
</RawNotification>
{/if}
{#if typeof aufnahme.einheiten === "number" && aufnahme.einheiten < 1}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "ANZAHL_EINHEITEN",
dismissable: false,
type: "warning",
selector: "input[name='einheiten']"
}}
>
Die Anzahl der Wohneinheiten muss mindestens 1 betragen.
</RawNotification>
{/if}
{#await auditPlzNichtErkannt(objekt) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "PLZ_NICHT_ERKANNT",
dismissable: false,
type: "warning",
}}
>
Die Postleitzahl konnte nicht zugeordnet werden. Bitte prüfen
Sie die Eingabe. Sollte die Postleitzahl korrekt eingegeben
sein, werden wir den Ort händisch zuordnen.
</RawNotification>
{/if}
{/await}
{#if auditHeizungGebaeudeBaujahr(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "HEIZUNG_GEBAEUDE_BAUJAHR",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR);
aufnahme = aufnahme;
},
type: "warning",
}}
>
Sie haben angegeben, dass ihre Heizung vor ihrem Gebäude konstruiert
wurde. Sind sie sich sicher, dass das stimmt?
</RawNotification>
{/if}
{#if auditHeizungJuengerDreiJahre(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "HEIZUNG_JUENGER_DREI_JAHRE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.HEIZUNG_JUENGER_DREI_JAHRE);
aufnahme = aufnahme;
},
type: "warning",
}}
>
Ihre Heizungsanlage ist jünger als 3 Jahre. Für den
Verbrauchsausweis müssen Sie mindestens 3 Verbrauchsjahre eingeben
die den aktuellen Stand des Gebäudes abbilden. Ein Verbrauchsausweis
ist daher nicht möglich. Bitte klicken Sie
<a href="/bedarfsausweis">hier</a> um zum Eingabeformular für den Bedarfsausweis
zu gelangen.
</RawNotification>
{/if}
{#if auditZeitraumAktuell(ausweis, objekt)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "ZEITRAUM_AKTUELL",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.ZEITRAUM_AKTUELL);
objekt = objekt;
ausweis = ausweis
},
type: "warning",
}}
>
Die Verbrauchszeiträume sind nicht aktuell genug. Das Ende des
letzten Verbrauchszeitraumes darf nicht mehr als 18 Monate
zurückliegen. Ein Verbrauchsausweis ist mit diesen Zeiträumen daher
nicht möglich. Bitte klicken Sie <a href="/bedarfsausweis">hier</a> um
zum Eingabeformular für den Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{#await auditKlimaFaktoren(ausweis, objekt) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "KLIMA_FAKTOREN",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.KLIMA_FAKTOREN);
objekt = objekt;
ausweis = ausweis;
},
type: "warning",
}}
>
Die Verbrauchszeiträume sind zu aktuell und es liegen noch keine
Klimafaktoren dazu vor. Bitte verschieben Sie die
Verbrauchszeiträume 1 Jahr nach hinten. Wenn das nicht möglich
ist, klicken Sie
<a href="/bedarfsausweis">hier</a> um zum Eingabeformular für den
Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{/await}
{#if auditWohnFlaeche(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WOHN_FLAECHE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WOHN_FLAECHE);
aufnahme = aufnahme;
},
type: "warning",
}}
>
Die Wohnfläche ist viel zu klein. Bitte überprüfen Sie Ihre Eingabe
nochmal und stellen sicher, daß sich Ihre Angaben auf das gesamte
Gebäude beziehen.
</RawNotification>
{/if}
{#if auditWarmWasser(ausweis)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WARM_WASSER",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.WARM_WASSER);
ausweis = ausweis;
},
type: "warning",
}}
>
Bitte überprüfen Sie nochmal die Höhe des Warmwasseranteils. Dieser
scheint nicht ganz im Rahmen zu liegen.
</RawNotification>
{/if}
{#if auditLeerStand(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "LEER_STAND",
dismissable: false,
type: "warning",
}}
>
Bei Leerstand größer als 30% darf kein Verbrauchsausweis ausgestellt
werden. Bitte klicken Sie <a href="/bedarfsausweis">hier</a> um zum Eingabeformular
für den Bedarfsausweis zu gelangen.
</RawNotification>
{/if}
{@const abweichung = auditVerbrauchAbweichung(ausweis, aufnahme)}
{#if abweichung.length > 0}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "VERBRAUCH_ABWEICHUNG",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.VERBRAUCH_ABWEICHUNG);
objekt = objekt;
ausweis = ausweis;
},
type: "warning",
}}
>
Die Abweichung der Verbräuche zwischen Zeitraum {abweichung[0]} und {abweichung[1]} beträgt mehr als 30% und sie haben keinen Leerstand angegeben.
Sind sie sich sicher, dass das stimmt?
</RawNotification>
{/if}
{#await auditEndEnergie(ausweis, objekt, aufnahme) then result}
{#if result}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "END_ENERGIE",
dismissable: true,
onUserDismiss: () => {
hidden.add(AuditType.END_ENERGIE);
objekt = objekt;
},
type: "warning",
}}
>
Die Endenergie liegt außerhalb des normalen Rahmens. Bitte
nochmal überprüfen. Bei Passivhäusern oder ganz alten
unsanierten Gebäuden ist so eine Abweichung durchaus möglich.
</RawNotification>
{/if}
{/await}
{#if auditWohnflaecheGroesserGesamtflaeche(aufnahme)}
<RawNotification
notification={{
message: "Plausibilitätsprüfung",
timeout: 0,
uid: "WOHNFLAECHE_GROESSER_GESAMTFLAECHE",
dismissable: false,
type: "error",
selector: "input[name='nutzflaeche']"
}}
>
Die Wohnfläche darf nicht größer als die Nutzfläche sein.
</RawNotification>
{/if}
</RawNotificationWrapper>

View File

@@ -51,7 +51,6 @@
AufnahmeClient,
} from "#components/Ausweis/types.js";
import { Enums } from "@ibcornelsen/database/client";
import { onMount } from "svelte";
// 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...
@@ -82,28 +81,11 @@
}
}
async function spaeterWeitermachen() {
// TODO FIX
// const result = await ausweisSpeichern(
// ausweis,
// objekt,
// aufnahme,
// bilder
// );
// if (result !== null) {
// // Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
// // Sonst müsste er alles neu eingeben...
// ausweis.uid = result.uid_ausweis;
// objekt.uid = result.uid_objekt;
// aufnahme.uid = result.uid_aufnahme;
// window.history.pushState(
// {},
// "",
// `${location.pathname}?uid=${result.uid_ausweis}`
// );
// speichernOverlayHidden = false;
// }
if (Object.keys(bilder).length === 0) {
const localStorageBilder = localStorage.getItem("bilder");
if (localStorageBilder) {
bilder = JSON.parse(localStorageBilder)
}
}
function automatischAusfüllen() {
@@ -139,43 +121,14 @@
ausweis = ausweis;
}
async function ausweisAbschicken(e: SubmitEvent) {
// if (e && e.preventDefault) e.preventDefault();
// const result = await ausweisSpeichern(
// ausweis,
// objekt,
// aufnahme,
// bilder
// );
// if (result !== null) {
// // Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
// // Sonst müsste er alles neu eingeben...
// ausweis.uid = result.uid_ausweis;
// objekt.uid = result.uid_objekt;
// aufnahme.uid = result.uid_aufnahme;
// window.history.pushState(
// {},
// "",
// `${location.pathname}?uid=${result.uid_ausweis}`
// );
// // window.location.href = `/kundendaten?uid=${result.uid_ausweis}`;
// }
}
let waitOverlayHidden = true;
let speichernOverlayHidden = true;
$: {
if (ausweis.uid && objekt.uid && aufnahme.uid) {
localStorage.setItem(ausweis.uid, JSON.stringify(ausweis))
localStorage.setItem(objekt.uid, JSON.stringify(objekt))
localStorage.setItem(aufnahme.uid, JSON.stringify(aufnahme))
} else {
localStorage.setItem("ausweis", JSON.stringify(ausweis))
localStorage.setItem("aufnahme", JSON.stringify(aufnahme))
localStorage.setItem("objekt", JSON.stringify(objekt))
}
localStorage.setItem("bilder", JSON.stringify(bilder))
}
$: {
@@ -190,7 +143,7 @@
}
}
const ausweisart: Enums.Ausweisart = "VerbrauchsausweisWohnen"
const ausweisart = Enums.Ausweisart.VerbrauchsausweisWohnen
</script>
@@ -211,10 +164,7 @@ const ausweisart: Enums.Ausweisart = "VerbrauchsausweisWohnen"
<div id="skala" class="bg-white grid grid-cols-1 p-4
lg:grid-cols-2 lg:gap-x-6
">
<div id="skala" class="bg-white grid grid-cols-1 p-4 lg:grid-cols-2 lg:gap-x-6">
<div id="performance-box" class="w-full box relative px-4 order-1 self-stretch grid grid-cols-1">
<PerformanceScore
@@ -228,7 +178,7 @@ lg:grid-cols-2 lg:gap-x-6
<div id="progress-box" class="w-full box relative px-4 py-3 text-center order-2 self-stretch">
<h1 class="text-secondary text-3xl m-0">Energieausweis erstellen</h1>
<h2 class="text-primary text-xl">{ausweisart} {PRICES.VerbrauchsausweisWohnen[0]}</h2>
<h2 class="text-primary text-xl">{ausweisart} {PRICES[ausweisart][Enums.AusweisTyp.Standard]}</h2>
<Progressbar active={0}/>
</div>
@@ -236,10 +186,19 @@ lg:grid-cols-2 lg:gap-x-6
<form id="formInput-1" on:submit={ausweisAbschicken} name="ausweis" data-test="ausweis">
<div id="formInput-1" data-test="ausweis">
<div id="formular-box" class="formular-boxen ring-0">
<ButtonSpaeterHilfe {automatischAusfüllen} {spaeterWeitermachen} />
<ButtonWeiterHilfe
bind:ausweis
bind:bilder
bind:user
bind:objekt
bind:aufnahme
ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen}
showWeiter={false}
>
</ButtonWeiterHilfe>
<!-- A Prüfung der Ausweisart -->
@@ -349,7 +308,7 @@ lg:grid-cols-2 lg:gap-x-6
</form>
</div>
<RawNotificationWrapper class="fixed left-8 bottom-8 max-w-[400px] flex flex-col gap-4 z-50">
{#each Object.entries($notifications) as [uid, notification] (uid)}
@@ -368,7 +327,7 @@ lg:grid-cols-2 lg:gap-x-6
type: "info",
}}
>
Sie benötigen einen Bedarfsausweis. <a href="/bedarfsausweis"
Sie benötigen einen Bedarfsausweis. <a href="/energieausweis-erstellen/bedarfsausweis-erstellen"
>Bitte führen Sie hier Ihre Eingabe für den Bedarfsausweis fort</a
>.
</RawNotification>

Some files were not shown because too many files have changed in this diff Show More