Bedarfsausweis gewerbe

This commit is contained in:
Moritz Utcke
2025-03-12 18:14:13 -03:00
parent 5f5cdc5728
commit 00015b30cd
32 changed files with 1182 additions and 108 deletions

View File

@@ -108,6 +108,22 @@ Table Aufnahme {
Table BedarfsausweisGewerbe {
id Int [pk, increment]
uid String [unique, not null]
ausstellgrund Ausstellgrund [note: '@zod.describe("Ausstellgrund wie z.B. Vermietung oder Verkauf")']
keller_beheizt Boolean [note: '@zod.describe("Falls der Keller des Gebäudes beheizt wird, sollte dieser Wert auf true stehen")']
storniert Boolean [default: false, note: '@zod.describe("Falls die Nachweisanfrage storniert wurde, sollte dieser Wert auf true stehen")']
bestellt Boolean [default: false, note: '@zod.describe("Falls der Nachweis bestellt wurde, sollte dieser Wert auf true stehen")']
zurueckgestellt Boolean [default: false, note: '@zod.describe("Falls der Nachweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen")']
abluftanlage Boolean [default: false]
zu_abluftanlage Boolean [default: false]
konditionierung_der_zuluft Boolean [default: false]
luftheizung Boolean [default: false]
hallenheizung Boolean [default: false]
dunkelstrahler Boolean [default: false]
direktheizung Boolean [default: false]
infrarotstrahler Boolean [default: false]
fussbodenheizung Boolean [default: false]
bauteilaktivierung Boolean [default: false]
klimatisierung Boolean [default: false]
benutzer_id Int [note: '@zod.describe("Die ID des Benutzers, welchem dieser Ausweis gehört")']
benutzer benutzer
aufnahme_id Int [unique, not null]
@@ -571,6 +587,7 @@ Enum BilderKategorie {
Fenster
Gebaeude
Daemmung
AnlagenTechnik
}
Enum Einpreisungsstatus {
@@ -631,7 +648,6 @@ Enum Ausweisart {
BedarfsausweisWohnen
BedarfsausweisGewerbe
GEGNachweisWohnen
GEGNachweisBedarfsausweis
GEGNachweisGewerbe
}

View File

@@ -0,0 +1,66 @@
-- AlterEnum
ALTER TYPE "BilderKategorie" ADD VALUE 'AnlagenTechnik';
-- AlterTable
ALTER TABLE "Anteilshaber" ALTER COLUMN "uid" SET DEFAULT 'ant-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Aufnahme" ALTER COLUMN "uid" SET DEFAULT 'auf-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisGewerbe" ADD COLUMN "abluftanlage" BOOLEAN DEFAULT false,
ADD COLUMN "ausstellgrund" "Ausstellgrund",
ADD COLUMN "bauteilaktivierung" BOOLEAN DEFAULT false,
ADD COLUMN "bestellt" BOOLEAN DEFAULT false,
ADD COLUMN "direktheizung" BOOLEAN DEFAULT false,
ADD COLUMN "dunkelstrahler" BOOLEAN DEFAULT false,
ADD COLUMN "fussbodenheizung" BOOLEAN DEFAULT false,
ADD COLUMN "hallenheizung" BOOLEAN DEFAULT false,
ADD COLUMN "infrarotstrahler" BOOLEAN DEFAULT false,
ADD COLUMN "keller_beheizt" BOOLEAN,
ADD COLUMN "klimatisierung" BOOLEAN DEFAULT false,
ADD COLUMN "konditionierung_der_zuluft" BOOLEAN DEFAULT false,
ADD COLUMN "luftheizung" BOOLEAN DEFAULT false,
ADD COLUMN "storniert" BOOLEAN DEFAULT false,
ADD COLUMN "zu_abluftanlage" BOOLEAN DEFAULT false,
ADD COLUMN "zurueckgestellt" BOOLEAN DEFAULT false,
ALTER COLUMN "uid" SET DEFAULT 'bag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'baw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Bild" ALTER COLUMN "uid" SET DEFAULT 'img-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "uid" SET DEFAULT 'evt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGEinpreisung" ALTER COLUMN "uid" SET DEFAULT 'gge-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'gng-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Objekt" ALTER COLUMN "uid" SET DEFAULT 'obj-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Rechnung" ALTER COLUMN "uid" SET DEFAULT 'inv-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Tickets" ALTER COLUMN "uid" SET DEFAULT 'tkt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Unterlage" ALTER COLUMN "uid" SET DEFAULT 'pln-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'vag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'vaw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "benutzer" ALTER COLUMN "uid" SET DEFAULT 'usr-' || gen_random_uuid();

View File

@@ -0,0 +1,62 @@
/*
Warnings:
- The values [GEGNachweisBedarfsausweis] on the enum `Ausweisart` will be removed. If these variants are still used in the database, this will fail.
*/
-- AlterEnum
BEGIN;
CREATE TYPE "Ausweisart_new" AS ENUM ('VerbrauchsausweisWohnen', 'VerbrauchsausweisGewerbe', 'BedarfsausweisWohnen', 'BedarfsausweisGewerbe', 'GEGNachweisWohnen', 'GEGNachweisGewerbe');
ALTER TABLE "Aufnahme" ALTER COLUMN "ausweisart" TYPE "Ausweisart_new" USING ("ausweisart"::text::"Ausweisart_new");
ALTER TYPE "Ausweisart" RENAME TO "Ausweisart_old";
ALTER TYPE "Ausweisart_new" RENAME TO "Ausweisart";
DROP TYPE "Ausweisart_old";
COMMIT;
-- AlterTable
ALTER TABLE "Anteilshaber" ALTER COLUMN "uid" SET DEFAULT 'ant-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Aufnahme" ALTER COLUMN "uid" SET DEFAULT 'auf-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'bag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "BedarfsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'baw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Bild" ALTER COLUMN "uid" SET DEFAULT 'img-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Event" ALTER COLUMN "uid" SET DEFAULT 'evt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGEinpreisung" ALTER COLUMN "uid" SET DEFAULT 'gge-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'gng-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "GEGNachweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'gnw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Objekt" ALTER COLUMN "uid" SET DEFAULT 'obj-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Rechnung" ALTER COLUMN "uid" SET DEFAULT 'inv-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Tickets" ALTER COLUMN "uid" SET DEFAULT 'tkt-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "Unterlage" ALTER COLUMN "uid" SET DEFAULT 'pln-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ALTER COLUMN "uid" SET DEFAULT 'vag-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "VerbrauchsausweisWohnen" ALTER COLUMN "uid" SET DEFAULT 'vaw-' || gen_random_uuid();
-- AlterTable
ALTER TABLE "benutzer" ALTER COLUMN "uid" SET DEFAULT 'usr-' || gen_random_uuid();

View File

@@ -1,16 +1,39 @@
model BedarfsausweisGewerbe {
id Int @id @default(autoincrement())
id Int @id @default(autoincrement())
uid String @unique @default(dbgenerated("'bag-' || gen_random_uuid()"))
/// @zod.describe("Die ID des Benutzers, welchem dieser Ausweis gehört")
/// @zod.describe("Ausstellgrund wie z.B. Vermietung oder Verkauf")
ausstellgrund Ausstellgrund?
/// @zod.describe("Falls der Keller des Gebäudes beheizt wird, sollte dieser Wert auf true stehen")
keller_beheizt Boolean?
/// @zod.describe("Falls die Nachweisanfrage storniert wurde, sollte dieser Wert auf true stehen")
storniert Boolean? @default(false)
/// @zod.describe("Falls der Nachweis bestellt wurde, sollte dieser Wert auf true stehen")
bestellt Boolean? @default(false)
/// @zod.describe("Falls der Nachweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen")
zurueckgestellt Boolean? @default(false)
abluftanlage Boolean? @default(false)
zu_abluftanlage Boolean? @default(false)
konditionierung_der_zuluft Boolean? @default(false)
luftheizung Boolean? @default(false)
hallenheizung Boolean? @default(false)
dunkelstrahler Boolean? @default(false)
direktheizung Boolean? @default(false)
infrarotstrahler Boolean? @default(false)
fussbodenheizung Boolean? @default(false)
bauteilaktivierung Boolean? @default(false)
klimatisierung Boolean? @default(false)
/// @zod.describe("Die ID des Benutzers, welchem dieser Ausweis gehört")
benutzer_id Int?
benutzer Benutzer? @relation(fields: [benutzer_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
aufnahme_id Int @unique
aufnahme_id Int @unique
aufnahme Aufnahme @relation(fields: [aufnahme_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
rechnung_id Int? @unique
rechnung_id Int? @unique
rechnung Rechnung? @relation(fields: [rechnung_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
geg_einpreisung_id Int? @unique
geg_einpreisung GEGEinpreisung? @relation(fields: [geg_einpreisung_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
}

View File

@@ -4,6 +4,7 @@ enum BilderKategorie {
Fenster
Gebaeude
Daemmung
AnlagenTechnik
}
model Bild {

View File

@@ -23,7 +23,7 @@ model GEGNachweisGewerbe {
aufnahme_id Int @unique
aufnahme Aufnahme @relation(fields: [aufnahme_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
rechnung_id Int? @unique
rechnung_id Int? @unique
rechnung Rechnung? @relation(fields: [rechnung_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
geg_einpreisung_id Int? @unique
geg_einpreisung GEGEinpreisung? @relation(fields: [geg_einpreisung_id], references: [id], onDelete: NoAction, onUpdate: NoAction)

View File

@@ -53,7 +53,6 @@ enum Ausweisart {
BedarfsausweisWohnen
BedarfsausweisGewerbe
GEGNachweisWohnen
GEGNachweisBedarfsausweis
GEGNachweisGewerbe
}

View File

@@ -5,7 +5,6 @@ export const createCaller = createCallerFactory({
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
"unterlage": await import("../src/pages/api/unterlage.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.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"),
@@ -13,13 +12,15 @@ export const createCaller = createCallerFactory({
"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"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"),
"auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"bedarfsausweis-gewerbe/[uid]": await import("../src/pages/api/bedarfsausweis-gewerbe/[uid].ts"),
"bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/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"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"bilder/[uid]": await import("../src/pages/api/bilder/[uid].ts"),
"geg-nachweis-gewerbe/[uid]": await import("../src/pages/api/geg-nachweis-gewerbe/[uid].ts"),
"geg-nachweis-gewerbe": await import("../src/pages/api/geg-nachweis-gewerbe/index.ts"),
@@ -30,12 +31,12 @@ export const createCaller = createCallerFactory({
"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"),
"verbrauchsausweis-gewerbe/[uid]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[uid].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-wohnen/[uid]": await import("../src/pages/api/verbrauchsausweis-wohnen/[uid].ts"),
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
"verbrauchsausweis-gewerbe/[uid]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[uid].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"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"),

View File

@@ -58,9 +58,4 @@ export function getZodBaseType(schema: ZodType<any>): ZodType<any> {
return getZodBaseType(schema._def.schema)
}
return schema;
}
export const sqids = new Sqids({
alphabet: "0123456789abcdefghijklmnopqrstuvw",
minLength: 8
})
}

View File

@@ -184,6 +184,9 @@ export async function nachweisSpeichern(
} else if (ausweisart === Enums.Ausweisart.GEGNachweisGewerbe) {
patchRoute = api["geg-nachweis-gewerbe"]._uid.PATCH
putRoute = api["geg-nachweis-gewerbe"].PUT
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
patchRoute = api["bedarfsausweis-gewerbe"]._uid.PATCH
putRoute = api["bedarfsausweis-gewerbe"].PUT
}
if (nachweis.uid) {

View File

@@ -0,0 +1,110 @@
<script lang="ts">
import {
AufnahmeClient,
ObjektClient,
UploadedGebaeudeBild,
} from "./types.js";
import SanierungsOption from "#components/Ausweis/SanierungsOption.svelte";
import AnlagenTechnikImage from "./AnlagenTechnikImage.svelte";
import { BedarfsausweisGewerbe } from "#lib/client/prisma.js";
export let objekt: ObjektClient;
export let aufnahme: AufnahmeClient;
export let ausweis: BedarfsausweisGewerbe;
export let images: UploadedGebaeudeBild[];
</script>
<div
id="sanierungszustand"
class="bereich-box grid
grid-cols-1 gap-x-4 gap-y-2
sm:grid-cols-1 sm:gap-x-6 sm:gap-y-1
md:grid-cols-2 md:gap-x-6 md:gap-y-8
xl:grid-cols-2 xl:gap-x-8 xl:gap-y-8
2xl:grid-cols-3 2xl:gap-x-8 2xl:gap-y-2
"
>
<SanierungsOption
label="Abluftanlage"
name="abluftanlage"
help=""
value="AWD"
bind:checked={ausweis.abluftanlage}
></SanierungsOption>
<SanierungsOption
label="Zu- und Abluftanlage"
name="zu_abluftanlage"
help=""
value="KWD"
bind:checked={ausweis.zu_abluftanlage}
></SanierungsOption>
<SanierungsOption
label="Konditionierung der Zuluft"
name="konditionierung_der_zuluft"
help=""
value="KDD"
bind:checked={ausweis.konditionierung_der_zuluft}
></SanierungsOption>
<SanierungsOption
label="Luftheizung"
name="luftheizung"
help=""
value="DGD"
bind:checked={ausweis.luftheizung}
></SanierungsOption>
<SanierungsOption
label="Hallenheizung"
name="hallenheizung"
help=""
value="DGD"
bind:checked={ausweis.hallenheizung}
></SanierungsOption>
<SanierungsOption
label="Dunkelstrahler"
name="dunkelstrahler"
help=""
value="DGD"
bind:checked={ausweis.dunkelstrahler}
></SanierungsOption>
<SanierungsOption
label="Direktheizung"
name="direktheizung"
help=""
value="DGD"
bind:checked={ausweis.direktheizung}
></SanierungsOption>
<SanierungsOption
label="Infrarotstrahler"
name="infrarotstrahler"
help=""
value="DGD"
bind:checked={ausweis.infrarotstrahler}
></SanierungsOption>
<SanierungsOption
label="Fußbodenheizung"
name="fussbodenheizung"
help=""
value="DGD"
bind:checked={ausweis.fussbodenheizung}
></SanierungsOption>
<SanierungsOption
label="Bauteilaktivierung"
name="bauteilaktivierung"
help=""
value="DGD"
bind:checked={ausweis.bauteilaktivierung}
></SanierungsOption>
<SanierungsOption
label="Klimatisierung"
name="klimatisierung"
help=""
value="DGD"
bind:checked={ausweis.klimatisierung}
></SanierungsOption>
</div>
<AnlagenTechnikImage bind:images bind:ausweis bind:objekt />
<style lang="postcss">
</style>

View File

@@ -0,0 +1,39 @@
<script lang="ts">
import ImageGrid from "../ImageGrid.svelte";;
import { BedarfsausweisGewerbe, Enums } from "#lib/client/prisma.js";
import { BildClient, ObjektClient } from "./types.js";
export let images: BildClient[] = [];
export let ausweis: BedarfsausweisGewerbe;
export let objekt: ObjektClient;
</script>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-x-6 mt-6 p-2 sm:px-0">
<div class="md:box md:card mb-0 bereich-box">
<div class="font-bold mb-2">
<span class="text-red-500">WICHTIG:</span>
Bild Upload - Anlagentechnik
</div>
</div>
<div class="md:box md:card mb-0 mt-6 md:mt-0">
<div>
Diese Bilder erscheinen <span class="text-red-500">nicht</span> auf Ihrem
Energieausweis!<br />
</div>
<ImageGrid
max={4}
min={0}
name={"anlagen_technik_image"}
kategorie={Enums.BilderKategorie.AnlagenTechnik}
bind:images
bind:ausweis
bind:objekt
>
TEXT FEHLT
</ImageGrid>
</div>
</div>

View File

@@ -70,7 +70,7 @@
loginOverlayHidden = true
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | Awaited<ReturnType<typeof nachweisSpeichern>> | null = null;
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis) {
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)

View File

@@ -1,6 +1,6 @@
<script lang="ts">
import ImageGrid from "../ImageGrid.svelte";;
import { Enums } from "#lib/client/prisma";
import { Enums } from "#lib/client/prisma.js";
import { BedarfsausweisWohnenClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "./types.js";
export let images: UploadedGebaeudeBild[] = [];

View File

@@ -15,6 +15,7 @@
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { Enums, Objekt } from "#lib/client/prisma.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { shortenUID } from "#server/lib/hash.js";
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let aufnahme: AufnahmeKomplettClient;
@@ -24,6 +25,8 @@
const ausweisart = getAusweisartFromUUID(ausweis.uid);
const id = shortenUID(ausweis.uid)
async function ausweisStornieren() {
const result = await dialogs.confirm({
title: "Ausweis Stornieren",
@@ -202,7 +205,7 @@
<div class="flex flex-row justify-between">
<span>ID</span>
<span class="font-bold text-base-content"
>{ausweis.uid}</span
>{id}</span
>
</div>
</div>

View File

@@ -59,7 +59,7 @@
<div class="text-lg font-semibold">
GEG Nachweis Gewerbe
</div>
{:else if ausweisart == Enums.Ausweisart.GEGNachweisBedarfsausweis}
{:else if ausweisart == Enums.Ausweisart.BedarfsausweisGewerbe}
<div class="text-lg font-semibold">
Bedarfsausweis Gewerbe
</div>

View File

@@ -79,7 +79,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<option value="Atrium-Bungalow">Atrium-Bungalow</option>
<option value="Winkelbungalow">Winkelbungalow</option>
{:else if ausweisart==Enums.Ausweisart.VerbrauchsausweisGewerbe}
{:else if ausweisart==Enums.Ausweisart.VerbrauchsausweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe}
<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>

View File

@@ -28,6 +28,7 @@ export const BilderKategorie = {
Fenster: "Fenster",
Gebaeude: "Gebaeude",
Daemmung: "Daemmung",
AnlagenTechnik: "AnlagenTechnik",
} as const;
export type BilderKategorie = (typeof BilderKategorie)[keyof typeof BilderKategorie];
@@ -104,7 +105,6 @@ export const Ausweisart = {
BedarfsausweisWohnen: "BedarfsausweisWohnen",
BedarfsausweisGewerbe: "BedarfsausweisGewerbe",
GEGNachweisWohnen: "GEGNachweisWohnen",
GEGNachweisBedarfsausweis: "GEGNachweisBedarfsausweis",
GEGNachweisGewerbe: "GEGNachweisGewerbe",
} as const;

View File

@@ -1,8 +1,25 @@
import * as z from "zod"
import { Ausstellgrund } from "@prisma/client"
export const BedarfsausweisGewerbeSchema = z.object({
id: z.number().int(),
uid: z.string(),
ausstellgrund: z.nativeEnum(Ausstellgrund).describe("Ausstellgrund wie z.B. Vermietung oder Verkauf").nullish(),
keller_beheizt: z.boolean().describe("Falls der Keller des Gebäudes beheizt wird, sollte dieser Wert auf true stehen").nullish(),
storniert: z.boolean().describe("Falls die Nachweisanfrage storniert wurde, sollte dieser Wert auf true stehen").nullish(),
bestellt: z.boolean().describe("Falls der Nachweis bestellt wurde, sollte dieser Wert auf true stehen").nullish(),
zurueckgestellt: z.boolean().describe("Falls der Nachweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen").nullish(),
abluftanlage: z.boolean().nullish(),
zu_abluftanlage: z.boolean().nullish(),
konditionierung_der_zuluft: z.boolean().nullish(),
luftheizung: z.boolean().nullish(),
hallenheizung: z.boolean().nullish(),
dunkelstrahler: z.boolean().nullish(),
direktheizung: z.boolean().nullish(),
infrarotstrahler: z.boolean().nullish(),
fussbodenheizung: z.boolean().nullish(),
bauteilaktivierung: z.boolean().nullish(),
klimatisierung: z.boolean().nullish(),
benutzer_id: z.number().int().describe("Die ID des Benutzers, welchem dieser Ausweis gehört").nullish(),
aufnahme_id: z.number().int(),
rechnung_id: z.number().int().nullish(),

View File

@@ -1,10 +1,10 @@
import { AufnahmeClient, BenutzerClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { AufnahmeClient, BenutzerClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { getEmpfehlungen } from "#lib/XML/getEmpfehlungen.js";
import { Enums } from "#lib/server/prisma.js";
import * as fs from "fs"
import moment from "moment";
import { PDFDocument, PDFFont, PDFImage, PDFName, PDFNumber, PDFPage, rgb, RotationTypes, StandardFonts, TextAlignment } from "pdf-lib";
import { PDFDocument, PDFFont, PDFImage, PDFPage, StandardFonts } from "pdf-lib";
import { addCheckMark } from "./utils/checkbox.js";
import { addText } from "./utils/text.js";
import { addAnsichtsausweisLabel, addDatumGEG } from "./utils/helpers.js";
@@ -469,70 +469,70 @@ 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 (!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.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",
// ""
// );
// }
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_1 || 0).toString(),
"0",
0,
""
);
}
/* -------------------------------- Seite 4 -------------------------------- */

View File

@@ -10,7 +10,7 @@ import {
import { prisma } from "#lib/server/prisma.js";
import { getAnsichtsausweis } from "../ausweis.js";
import Mail from "nodemailer/lib/mailer/index.js";
import { sqids } from "#client/lib/helpers.js";
import { shortenUID } from "#server/lib/hash.js";
export async function sendInvoiceMail(
ausweis: VerbrauchsausweisWohnen,
@@ -35,6 +35,9 @@ export async function sendInvoiceMail(
const attachments: Mail.Attachment[] = [];
const id = shortenUID(ausweis.uid)
if (ausweisart != Enums.Ausweisart.BedarfsausweisWohnen) {
const ansichtsausweis = await getAnsichtsausweis(
ausweis,
@@ -48,7 +51,7 @@ export async function sendInvoiceMail(
if (ansichtsausweis) {
attachments.push(
{
filename: `ID_${ausweis.id}_Ansichtsausweis.pdf`,
filename: `ID_${id}_Ansichtsausweis.pdf`,
encoding: "binary",
content: Buffer.from(ansichtsausweis),
contentType: "application/pdf",
@@ -62,7 +65,7 @@ export async function sendInvoiceMail(
attachments,
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${ausweis.id})`,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${id})`,
cc: {
address: rechnung.email || "",
name: rechnung.empfaenger || "",

View File

@@ -8,8 +8,8 @@ import {
} from "#lib/client/prisma.js";
import { prisma } from "#lib/server/prisma.js";
import { getAnsichtsausweis } from "../ausweis.js";
import { sqids } from "#client/lib/helpers.js";
import Mail from "nodemailer/lib/mailer/index.js";
import { shortenUID } from "#server/lib/hash.js";
export async function sendPaymentSuccessMail(
ausweis: VerbrauchsausweisWohnen,
@@ -34,6 +34,8 @@ export async function sendPaymentSuccessMail(
const ausweisart = getAusweisartFromUUID(ausweis.uid);
const attachments: Mail.Attachment[] = [];
const id = shortenUID(ausweis.uid)
if (ausweisart != Enums.Ausweisart.BedarfsausweisWohnen) {
const ansichtsausweis = await getAnsichtsausweis(
ausweis,
@@ -47,7 +49,7 @@ export async function sendPaymentSuccessMail(
if (ansichtsausweis) {
attachments.push(
{
filename: `ID_${ausweis.id}_Ansichtsausweis.pdf`,
filename: `ID_${id}_Ansichtsausweis.pdf`,
encoding: "binary",
content: Buffer.from(ansichtsausweis),
contentType: "application/pdf",
@@ -66,7 +68,7 @@ export async function sendPaymentSuccessMail(
attachments,
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${ausweis.id})`,
subject: `Bestellbestätigung vom IBCornelsen (ID: ${id})`,
cc: {
address: rechnung.email || "",
name: rechnung.empfaenger || "",

View File

@@ -130,13 +130,11 @@
`/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]:
[Enums.Ausweisart.BedarfsausweisGewerbe]:
`/angebot-anfragen/bedarfsausweis-gewerbe-anfragen?uid=${ausweis.uid}`,
}[ausweisart];
@@ -219,7 +217,7 @@
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | Awaited<ReturnType<typeof nachweisSpeichern>> | null = null;
try {
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) {
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)
@@ -265,14 +263,14 @@
loginOverlayHidden = true
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | Awaited<ReturnType<typeof nachweisSpeichern>> | null = null;
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis) {
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, ausweisart)
}
if (result === null) {
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis) {
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
addNotification({
dismissable: true,
message: "Ups... Das hat nicht geklappt.",
@@ -396,7 +394,7 @@
const gegAnfrage =
ausweisart === Enums.Ausweisart.GEGNachweisWohnen ||
ausweisart === Enums.Ausweisart.GEGNachweisBedarfsausweis ||
ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe ||
ausweisart === Enums.Ausweisart.GEGNachweisGewerbe;
let loginOverlayHidden = true;
@@ -484,7 +482,7 @@
<div class="input-standard order-3 md:order-3 xl:order-3">
<InputLabel title="Telefonnummer *"></InputLabel>
<input name="telefon" bind:value={$telefon} type="text" />
<input name="telefon" bind:value={$telefon} type="text" required />
<div class="help-label">
<HelpLabel>

View File

@@ -59,7 +59,7 @@
export let bilder: UploadedGebaeudeBild[];
export let ausweistyp: Enums.AusweisTyp;
if (moment(localStorage.getItem("verbrauchsausweis-wohnen.updated_at") || new Date()).isAfter(ausweis.updated_at)) {
if (!ausweis.updated_at || moment(localStorage.getItem("verbrauchsausweis-wohnen.updated_at") || new Date()).isAfter(ausweis.updated_at)) {
const localStorageAusweis = localStorage.getItem("verbrauchsausweis-wohnen.ausweis");
if (localStorageAusweis) {
ausweis = JSON.parse(localStorageAusweis)

View File

@@ -0,0 +1,233 @@
<script lang="ts">
import GebaeudeDaten from "#components/Ausweis/GebaeudeDaten.svelte";
import {
ObjektClient,
AufnahmeClient,
BenutzerClient,
UnterlageClient,
GEGNachweisWohnenClient,
BildClient,
} from "#components/Ausweis/types.js";
import Bereich from "#components/labels/Bereich.svelte";
import { Enums } from "#lib/client/prisma.js";
import Progressbar from "#components/Ausweis/Progressbar.svelte";
import FileGrid from "#components/FileGrid.svelte";
import ButtonWeiterHilfe from "#components/Ausweis/ButtonWeiterHilfe.svelte";
import GEGAusweisart from "#components/GEGNachweis/GEGAusweisart.svelte";
import SanierungszustandHeizungsanlage from "#components/Ausweis/SanierungszustandHeizungsanlage.svelte";
import SanierungszustandFensterTueren from "#components/Ausweis/SanierungszustandFensterTueren.svelte";
import SanierungszustandWaermedammung from "#components/Ausweis/SanierungszustandWaermedammung.svelte";
import AnlagenTechnik from "#components/Ausweis/AnlagenTechnik.svelte";
export let nachweis: GEGNachweisWohnenClient;
export let objekt: ObjektClient;
export let aufnahme: AufnahmeClient;
export let user: BenutzerClient = {} as BenutzerClient;
export let bilder: BildClient[] = [];
export let plaene: UnterlageClient[] = [];
export let unterlagen: UnterlageClient[] = [];
if (Object.keys(nachweis).length === 0) {
const localStorageAusweis = localStorage.getItem(
"geg-nachweis-wohnen.ausweis"
);
if (localStorageAusweis) {
nachweis = JSON.parse(localStorageAusweis);
}
}
if (Object.keys(aufnahme).length === 0) {
const localStorageAufnahme = localStorage.getItem(
"geg-nachweis-wohnen.aufnahme"
);
if (localStorageAufnahme) {
aufnahme = JSON.parse(localStorageAufnahme);
}
}
if (Object.keys(objekt).length === 0) {
const localStorageObjekt = localStorage.getItem(
"geg-nachweis-wohnen.objekt"
);
if (localStorageObjekt) {
objekt = JSON.parse(localStorageObjekt);
}
}
if (Object.keys(bilder).length === 0) {
const localStorageBilder = localStorage.getItem(
"geg-nachweis-wohnen.bilder"
);
if (localStorageBilder) {
bilder = JSON.parse(localStorageBilder);
}
}
if (Object.keys(unterlagen).length === 0) {
const localStorageUnterlagen = localStorage.getItem(
"geg-nachweis-wohnen.unterlagen"
);
if (localStorageUnterlagen) {
unterlagen = JSON.parse(localStorageUnterlagen);
}
}
$: {
localStorage.setItem(
"geg-nachweis-wohnen.ausweis",
JSON.stringify(nachweis)
);
localStorage.setItem(
"geg-nachweis-wohnen.aufnahme",
JSON.stringify(aufnahme)
);
localStorage.setItem(
"geg-nachweis-wohnen.objekt",
JSON.stringify(objekt)
);
localStorage.setItem(
"geg-nachweis-wohnen.bilder",
JSON.stringify(bilder)
);
localStorage.setItem(
"geg-nachweis-wohnen.unterlagen",
JSON.stringify(unterlagen)
);
}
const ausweisart = Enums.Ausweisart.BedarfsausweisGewerbe;
const anliegen = "Angebot anfragen";
let form: HTMLFormElement;
let skala: HTMLDivElement;
</script>
<div
id="skala"
bind:this={skala}
class="bg-white grid grid-cols-1 p-4 lg:grid-cols-2 lg:gap-x-6 no-scroll"
>
<Progressbar
active={0}
{ausweisart}
{anliegen}
steps={["Gebäudedaten", "Kundendaten", "Anfragebestätigung"]}
/>
</div>
<form id="formInput-1" name="ausweis" data-test="ausweis" bind:this={form}>
<div id="formular-box" class="formular-boxen ring-0">
<!-- A Prüfung der Ausweisart -->
<Bereich bereich="A" title="Prüfung der Ausweisart">
<GEGAusweisart
bind:objekt
bind:aufnahme
bind:ausweis={nachweis}
{ausweisart}
/>
</Bereich>
<!-- B Eingabe der Gebäudeadresse - Angaben zu Wohnfläche, Keller und Dachgeschoss -->
<Bereich
bereich="B"
title="Eingabe der Gebäudeadresse - Angaben zu Wohnfläche, Keller und Dachgeschoss"
><GebaeudeDaten bind:aufnahme bind:objekt {ausweisart} /></Bereich
>
<Bereich
bereich="C"
title="Angaben zur Heizungsanlage"
><SanierungszustandHeizungsanlage bind:ausweis={nachweis} bind:images={bilder} bind:aufnahme bind:objekt {ausweisart} /></Bereich
>
<Bereich
bereich="D"
title="Angaben zu Fenster, Dachfenster und Türen"
><SanierungszustandFensterTueren bind:ausweis={nachweis} bind:images={bilder} bind:aufnahme bind:objekt {ausweisart} /></Bereich
>
<Bereich
bereich="E"
title="Angaben zur Wärmedämmung"
><SanierungszustandWaermedammung bind:ausweis={nachweis} bind:images={bilder} bind:aufnahme bind:objekt {ausweisart} /></Bereich
>
<Bereich
bereich="F"
title="Angaben zur Wärmedämmung"
><AnlagenTechnik bind:ausweis={nachweis} bind:images={bilder} bind:aufnahme bind:objekt {ausweisart} /></Bereich
>
<Bereich bereich="G" title="Gebäudepläne & Unterlagen">
<div
class="bereich-box grid grid-cols-1 lg:grid-cols-2 gap-x-6 mt-6"
>
<div class="md:box md:card mb-0">
<div class="font-bold mb-2">Pläne</div>
<div>
Hier können sie Grundrisspläne, Ansichtspläne und
Schnitte hochladen. Die Dateien können entweder im PDF
Format oder als Bild hochgeladen werden.
</div>
</div>
<div class="md:box md:card mb-0 mt-6 md:mt-0">
<div>
<strong
>Bitte laden Sie hier mind. 1 Dokument hoch:</strong
>
</div>
<FileGrid
max={Infinity}
min={1}
name={"plaene"}
bind:files={plaene}
bind:ausweis={nachweis}
bind:objekt
></FileGrid>
</div>
</div>
<div
class="bereich-box grid grid-cols-1 lg:grid-cols-2 gap-x-6 mt-6"
>
<div class="md:box md:card mb-0">
<div class="font-bold mb-2">Unterlagen</div>
<div>
Hier können sie weitere Unterlagen wie z.B.
Baugenehmigungen, U-Wert Berechnungen, Anlagentechnik
oder ihren alten Energieausweis hochladen. Die Dateien
können entweder im PDF Format oder als Bild hochgeladen
werden.
</div>
</div>
<div class="md:box md:card mb-0 mt-6 md:mt-0">
<FileGrid
max={Infinity}
min={0}
name={"unterlagen"}
bind:files={unterlagen}
bind:ausweis={nachweis}
bind:objekt
></FileGrid>
</div>
</div>
</Bereich>
</div>
<ButtonWeiterHilfe
bind:ausweis={nachweis}
bind:bilder
bind:unterlagen
bind:user
bind:objekt
bind:aufnahme
ausweisart={Enums.Ausweisart.BedarfsausweisGewerbe}
{form}
{skala}
></ButtonWeiterHilfe>
</form>

View File

@@ -1 +1,90 @@
bedarfsausweis Gewerbe anfragen
---
import AusweisLayout from "#layouts/AusweisLayoutDaten.astro";
import { AufnahmeClient, BildClient, GEGNachweisWohnenClient, ObjektClient, UnterlageClient } from "#components/Ausweis/types";
import { createCaller } from "src/astro-typesafe-api-caller";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken.js";
import BedarfsausweisGewerbeModule from "#modules/angebot-anfragen/BedarfsausweisGewerbeModule.svelte";
const uid = Astro.url.searchParams.get("uid");
let nachweis: GEGNachweisWohnenClient = {} as GEGNachweisWohnenClient;
let aufnahme: AufnahmeClient = {} as AufnahmeClient;
let objekt: ObjektClient = {} as ObjektClient;
let bilder: BildClient[] = []
let unterlagen: UnterlageClient[] = []
const valid = validateAccessTokenServer(Astro);
const caller = createCaller(Astro);
if (uid) {
if (!valid) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
try {
nachweis = await caller["bedarfsausweis-gewerbe"]._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid
}
});
aufnahme = await caller.aufnahme._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: nachweis.uid_aufnahme
}
})
objekt = await caller.objekt._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: nachweis.uid_objekt
}
})
bilder = await caller.aufnahme._uid.bilder.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: nachweis.uid_aufnahme
}
})
unterlagen = await caller.aufnahme._uid.unterlagen.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: nachweis.uid_aufnahme
}
})
if (!nachweis) {
// Der Ausweis scheint nicht zu existieren.
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
return Astro.redirect(
"/angebot-anfragen/bedarfsausweis-gewerbe-anfragen"
);
}
} catch(e) {
return Astro.redirect(
"/angebot-anfragen/bedarfsausweis-gewerbe-anfragen"
);
}
}
---
<AusweisLayout title="Bedarfsausweis Gewerbe anfragen">
<BedarfsausweisGewerbeModule client:only {nachweis} {objekt} {aufnahme} {bilder} {unterlagen} />
</AusweisLayout>

View File

@@ -0,0 +1,212 @@
import { GEGNachweisWohnenClient, OptionalNullable, UUidWithPrefix, ZodOverlap } from "#components/Ausweis/types.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { BedarfsausweisGewerbeSchema } from "src/generated/zod/bedarfsausweisgewerbe.js";
import { z } from "zod";
export const PATCH = defineApiRoute({
input: BedarfsausweisGewerbeSchema.omit({
uid: true,
id: true,
benutzer_id: true,
geg_einpreisung_id: true,
aufnahme_id: true,
}),
output: z.void(),
headers: {
"Authorization": z.string()
},
middleware: authorizationMiddleware,
async fetch(input, ctx, user) {
const objekt = await prisma.bedarfsausweisGewerbe.findUnique({
where: {
uid: ctx.params.uid,
benutzer: {
id: user.id
}
}
})
if (!objekt) {
throw new APIError({
code: "NOT_FOUND",
message: "Nachweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."
})
}
await prisma.bedarfsausweisGewerbe.update({
where: {
uid: ctx.params.uid
},
data: input
})
},
})
export const DELETE = defineApiRoute({
meta: {
description: "Storniert einen Nachweis"
},
headers: authorizationHeaders,
middleware: authorizationMiddleware,
async fetch(input, ctx, user) {
const { uid } = ctx.params;
if (!UUidWithPrefix.safeParse(uid).success) {
throw new APIError({
code: "BAD_REQUEST",
message: "UID konnte nicht verifiziert werden."
})
}
// Wir holen uns den BedarfsNachweis
// Dieser MUSS mit dem Nutzer verknüpft sein.
const nachweis = await prisma.bedarfsausweisGewerbe.findUnique({
where: {
uid,
}
});
if (!nachweis) {
// Falls wir den Nachweis nicht finden können, werfen wir einen Fehler
throw new APIError({
code: "NOT_FOUND",
message: "Nachweis konnte nicht gefunden werden.",
});
}
// Wir dürfen den Nachweis nur stornieren, wenn er noch nicht ausgestellt wurde
// Außerdem müssen wir schauen, ob wir Admin oder der Besitzer des Nachweises sind.
if ((nachweis.benutzer_id !== user.id) && user.rolle !== "ADMIN") {
// Falls der Nachweis nicht dem Nutzer gehört, werfen wir einen Fehler
throw new APIError({
code: "FORBIDDEN",
message: "Nachweis gehört nicht dem Nutzer.",
});
}
// if (Nachweis.erledigt) {
// // Falls der Nachweis bereits ausgestellt wurde, werfen wir einen Fehler
// throw new TRPCError({
// code: "BAD_REQUEST",
// message: "Nachweis wurde bereits ausgestellt.",
// });
// }
if (nachweis.storniert) {
// Falls der Nachweis bereits storniert ist, werfen wir einen Fehler
throw new APIError({
code: "BAD_REQUEST",
message: "Nachweis wurde bereits storniert.",
});
}
await prisma.gEGNachweisWohnen.update({
where: {
id: nachweis.id
},
data: {
storniert: true
}
})
// Wir erstellen ein Event, dass der Nachweis storniert wurde
// Dann können wir das in der Historie anzeigen
await prisma.event.create({
data: {
title: "Nachweis storniert",
description: ((user.rolle === "ADMIN") && (nachweis.benutzer_id !== user.id)) ? "Nachweis wurde von einem Administrator storniert." : "Nachweis wurde vom Besitzer storniert.",
benutzer: {
connect: {
id: user.id
}
},
aufnahme: {
connect: {
id: nachweis.aufnahme_id
}
}
}
})
},
})
export const GET = defineApiRoute({
meta: {
description: "Gibt ein spezifisches Gebäude des Benutzers zurück.",
tags: ["Gebäude"],
headers: {
"Authorization": {
description: "Ein gültiger Authentifizierungstoken",
required: true,
allowEmptyValue: false,
examples: {
Bearer: {
value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
}
}
},
output: BedarfsausweisGewerbeSchema.merge(z.object({
uid_aufnahme: UUidWithPrefix,
uid_objekt: UUidWithPrefix,
uid_benutzer: UUidWithPrefix.optional()
})).omit({
id: true,
aufnahme_id: true,
benutzer_id: true
}),
middleware: authorizationMiddleware,
async fetch(input, context, user) {
const { uid } = context.params;
if (!uid) {
throw new APIError({
code: "BAD_REQUEST",
message: "Missing uid in request params"
})
}
const nachweis = await prisma.bedarfsausweisGewerbe.findUnique({
where: {
uid,
benutzer_id: user.id
},
include: {
benutzer: {
select: {
uid: true
}
},
aufnahme: {
select: {
uid: true,
objekt: {
select: {
uid: true
}
}
}
}
}
});
if (!nachweis) {
// Falls wir den Nachweis nicht finden können, werfen wir einen Fehler
throw new APIError({
code: "NOT_FOUND",
message: "Nachweis konnte nicht gefunden werden.",
});
}
return {
uid_aufnahme: nachweis.aufnahme.uid,
uid_objekt: nachweis.aufnahme.objekt.uid,
uid_benutzer: nachweis.benutzer?.uid,
...exclude(nachweis, ["id", "aufnahme_id", "benutzer_id", "aufnahme"])
}
},
});

View File

@@ -0,0 +1,144 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { BedarfsausweisGewerbeSchema } from "src/generated/zod/bedarfsausweisgewerbe.js";
import { z } from "zod";
export const PUT = defineApiRoute({
meta: {
contentTypes: ["application/json"],
description:
"Erstellt einen neuen Bedarfsausweis Gewerbe.",
tags: ["GEG Nachweis", "Bedarfsausweis Gewerbe"],
},
input: z.object({
nachweis: BedarfsausweisGewerbeSchema.omit({
id: true,
benutzer_id: true,
uid: true,
aufnahme_id: true,
geg_einpreisung_id: true,
rechnung_id: true
}),
uid_aufnahme: UUidWithPrefix
}),
output: z.object({
uid: UUidWithPrefix,
objekt_uid: UUidWithPrefix,
aufnahme_uid: UUidWithPrefix,
}),
headers: authorizationHeaders,
middleware: authorizationMiddleware,
async fetch(input, ctx, user) {
const aufnahme = await prisma.aufnahme.findUnique({
where: {
uid: input.uid_aufnahme
}
})
if (!aufnahme || aufnahme.benutzer_id !== user.id) {
throw new APIError({
code: "FORBIDDEN",
message: "Aufnahme konnte nicht gefunden werden oder gehört nicht zu diesem Benutzer."
})
}
const nachweis = await prisma.bedarfsausweisGewerbe.create({
data: {
...input.nachweis,
benutzer: {
connect: {
id: user.id,
},
},
aufnahme: {
connect: {
id: aufnahme.id,
},
}
},
select: {
uid: true,
aufnahme: {
select: {
uid: true,
objekt: {
select: {
uid: true,
},
},
},
},
},
});
return {
uid: nachweis.uid,
objekt_uid: nachweis.aufnahme.objekt.uid,
aufnahme_uid: nachweis.aufnahme.uid,
};
},
});
export const GET = defineApiRoute({
meta: {
description: "Gibt eine spezifische GEG Nachweis Anfrage des Benutzers zurück.",
tags: ["GEG Nachweis"],
headers: {
Authorization: {
description: "Ein gültiger Authentifizierungstoken",
required: true,
allowEmptyValue: false,
examples: {
Bearer: {
value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
},
},
},
},
},
headers: authorizationHeaders,
middleware: authorizationMiddleware,
async fetch(input, context, user) {
const { uid } = context.params;
const nachweis = await prisma.bedarfsausweisGewerbe.findUnique({
where: {
uid,
},
include: {
benutzer: true,
aufnahme: {
include: {
events: {
include: {
benutzer: {
select: {
uid: true,
},
},
},
orderBy: {
date: "asc",
},
},
},
},
},
});
if (
!nachweis ||
(nachweis.benutzer_id !== null && nachweis.benutzer_id !== user.id)
) {
// Falls wir den Ausweis nicht finden können, werfen wir einen Fehler
throw new APIError({
code: "NOT_FOUND",
message: "GEG Nachweis konnte nicht gefunden werden.",
});
}
return nachweis;
},
});

View File

@@ -140,7 +140,7 @@ function getPaymentDescription(ausweisart: Enums.Ausweisart) {
return "Verbrauchsausweis Gewerbegebäude"
case "VerbrauchsausweisWohnen":
return "Verbrauchsausweis Wohngebäude"
case "GEGNachweisBedarfsausweis":
case "BedarfsausweisGewerbe":
case "GEGNachweisGewerbe":
case "GEGNachweisWohnen":
return "GEG Nachweis"

View File

@@ -35,6 +35,12 @@ export const PUT = defineApiRoute({
uid: input.nachweis_uid
}
})
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
nachweis = await prisma.bedarfsausweisGewerbe.findUnique({
where: {
uid: input.nachweis_uid
}
})
} else {
throw new APIError({
"code": "BAD_REQUEST",
@@ -84,6 +90,23 @@ export const PUT = defineApiRoute({
}
}
})
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
einpreisung = await prisma.gEGEinpreisung.create({
data: {
...omit(input, ["nachweis_uid"]),
status: Enums.Einpreisungsstatus.open,
benutzer: {
connect: {
id: user.id
}
},
bedarfsausweis_gewerbe: {
connect: {
uid: input.nachweis_uid
}
}
}
})
}
await sendGEGAnforderungsMail(nachweis, user)

13
src/server/lib/hash.ts Normal file
View File

@@ -0,0 +1,13 @@
function murmurHash36(str: string) {
let h = 0xdeadbeef;
for (let i = 0; i < str.length; i++) {
h = Math.imul(h ^ str.charCodeAt(i), 2654435761);
}
return (h >>> 0).toString(36).toUpperCase().slice(0, 6);
}
export function shortenUID(uid: string) {
const str = murmurHash36(uid);
const mid = Math.floor(str.length / 2);
return [str.slice(0, mid), str.slice(mid)].join("-");
}

View File

@@ -165,10 +165,32 @@ export function fakeAufnahmeComplete() {
objekt_id: faker.number.int(),
};
}
export function fakeBedarfsausweisGewerbe() {
return {
ausstellgrund: undefined,
keller_beheizt: undefined,
};
}
export function fakeBedarfsausweisGewerbeComplete() {
return {
id: faker.number.int({ max: 2147483647 }),
uid: '[object Object]',
ausstellgrund: undefined,
keller_beheizt: undefined,
storniert: false,
bestellt: false,
zurueckgestellt: false,
abluftanlage: false,
zu_abluftanlage: false,
konditionierung_der_zuluft: false,
luftheizung: false,
hallenheizung: false,
dunkelstrahler: false,
direktheizung: false,
infrarotstrahler: false,
fussbodenheizung: false,
bauteilaktivierung: false,
klimatisierung: false,
benutzer_id: undefined,
aufnahme_id: faker.number.int(),
rechnung_id: undefined,
@@ -343,13 +365,13 @@ export function fakeBenutzerComplete() {
}
export function fakeBild() {
return {
kategorie: faker.helpers.arrayElement([BilderKategorie.Heizung, BilderKategorie.Fenster, BilderKategorie.Gebaeude, BilderKategorie.Daemmung] as const),
kategorie: faker.helpers.arrayElement([BilderKategorie.Heizung, BilderKategorie.Fenster, BilderKategorie.Gebaeude, BilderKategorie.Daemmung, BilderKategorie.AnlagenTechnik] as const),
};
}
export function fakeBildComplete() {
return {
id: faker.number.int({ max: 2147483647 }),
kategorie: faker.helpers.arrayElement([BilderKategorie.Heizung, BilderKategorie.Fenster, BilderKategorie.Gebaeude, BilderKategorie.Daemmung] as const),
kategorie: faker.helpers.arrayElement([BilderKategorie.Heizung, BilderKategorie.Fenster, BilderKategorie.Gebaeude, BilderKategorie.Daemmung, BilderKategorie.AnlagenTechnik] as const),
uid: '[object Object]',
aufnahme_id: undefined,
};