Compare commits
42 Commits
test
...
registrier
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc0509cac2 | ||
|
|
056cbfa144 | ||
|
|
e50f54eedc | ||
|
|
4eee179d37 | ||
|
|
1e3b5dff60 | ||
|
|
7b894ffd00 | ||
|
|
dbd725797c | ||
|
|
d9b0d6ac95 | ||
|
|
5bb5fb9401 | ||
|
|
c0d546fb9d | ||
|
|
9a2359a993 | ||
|
|
ed20bb1c76 | ||
|
|
fc6462c653 | ||
|
|
df7d80e2e4 | ||
|
|
89e71c4641 | ||
|
|
2d0e27075b | ||
|
|
bd758e3793 | ||
|
|
3e73203c94 | ||
|
|
e9f51560f6 | ||
|
|
1e7fd7afe0 | ||
|
|
3aa3349d72 | ||
|
|
042bad25e0 | ||
|
|
50f36dbc6c | ||
|
|
6894468e58 | ||
|
|
51257bbde8 | ||
|
|
5bd06fa0ef | ||
|
|
9a1625fa1b | ||
|
|
744c9c3f52 | ||
|
|
429ce4c4e5 | ||
|
|
9d58502f29 | ||
|
|
fcf12db850 | ||
|
|
4db097b544 | ||
|
|
4bf104fc76 | ||
|
|
7371fa8765 | ||
|
|
22a88599d1 | ||
|
|
c6d7cbe661 | ||
|
|
c67355ace7 | ||
|
|
ed37399c3c | ||
|
|
76943d8ef4 | ||
|
|
ebabb8d667 | ||
|
|
a603c5d202 | ||
|
|
75c4e3fa2b |
@@ -8,6 +8,8 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
merge:
|
merge:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
reason: ${{ steps.check.outputs.reason }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -28,9 +30,15 @@ jobs:
|
|||||||
id: check
|
id: check
|
||||||
run: |
|
run: |
|
||||||
git fetch origin
|
git fetch origin
|
||||||
if [ $(git rev-list --count origin/staging..origin/main) -gt 0 ]; then
|
COUNT=$(git rev-list --count origin/staging..origin/main)
|
||||||
|
if [ "$COUNT" -gt 0 ]; then
|
||||||
|
echo "reason=ok" >> $GITHUB_OUTPUT
|
||||||
echo "❌ Staging is behind main and requires manual merging."
|
echo "❌ Staging is behind main and requires manual merging."
|
||||||
exit 1
|
exit 1
|
||||||
|
elif [ "$COUNT" -eq 0 ]; then
|
||||||
|
echo "reason=identical" >> $GITHUB_OUTPUT
|
||||||
|
echo "✅ Staging and main are identical. Nothing to do."
|
||||||
|
exit 42
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Create PR from staging to main
|
- name: Create PR from staging to main
|
||||||
@@ -53,7 +61,7 @@ jobs:
|
|||||||
|
|
||||||
notify_failure:
|
notify_failure:
|
||||||
needs: merge
|
needs: merge
|
||||||
if: failure()
|
if: failure() && needs.merge.outputs.reason != 'identical'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Send Discord notification on failure
|
- name: Send Discord notification on failure
|
||||||
|
|||||||
18
.github/workflows/enforce-pr-source.yml
vendored
Normal file
18
.github/workflows/enforce-pr-source.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
name: Enforce PR Source
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened, ready_for_review]
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-pr-source:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Enforce only staging → main
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.head_ref }}" != "staging" ]]; then
|
||||||
|
echo "ERROR: Only 'staging' branch may create PRs into 'main'!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
2
Makefile
2
Makefile
@@ -59,7 +59,7 @@ all:
|
|||||||
bun run dev 2>&1 | tee ~/logs/`date '+%d-%m-%Y_%H:%M:%S'`.log
|
bun run dev 2>&1 | tee ~/logs/`date '+%d-%m-%Y_%H:%M:%S'`.log
|
||||||
|
|
||||||
update-dwd-klimafaktoren-cron:
|
update-dwd-klimafaktoren-cron:
|
||||||
pm2 start bun --name "update-dwd-klimafaktoren-cron" --cron "0 12 28 * *" -- src/cronjobs/update-dwd-klimafaktoren.ts
|
pm2 start bun --name "update-dwd-klimafaktoren-cron" --no-autorestart --cron "0 12 28 * *" -- src/cronjobs/update-dwd-klimafaktoren.ts
|
||||||
|
|
||||||
prod: install-dependencies prisma-studio backup-database-cronjob update-dwd-klimafaktoren-cron
|
prod: install-dependencies prisma-studio backup-database-cronjob update-dwd-klimafaktoren-cron
|
||||||
bun run build
|
bun run build
|
||||||
|
|||||||
@@ -13,13 +13,17 @@ export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required
|
|||||||
# Den Key dafür findet man auf https://dcd.ionos.com/latest/?lang=en#/key-management
|
# Den Key dafür findet man auf https://dcd.ionos.com/latest/?lang=en#/key-management
|
||||||
docker exec -t online-energieausweis-database-1 pg_dump --data-only -U main main | brotli --best > $FILE_NAME
|
docker exec -t online-energieausweis-database-1 pg_dump --data-only -U main main | brotli --best > $FILE_NAME
|
||||||
|
|
||||||
aws s3 cp $FILE_NAME s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-1.ionoscloud.com --storage-class STANDARD
|
aws s3 cp $FILE_NAME s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3.eu-central-3.ionoscloud.com --storage-class STANDARD
|
||||||
|
|
||||||
echo "Uploaded $FILE_NAME"
|
echo "Uploaded $FILE_NAME"
|
||||||
|
|
||||||
docker exec -t online-energieausweis-database-1 pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE
|
docker exec -t online-energieausweis-database-1 pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE
|
||||||
|
|
||||||
aws s3 cp $FILE_NAME_COMPLETE s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-1.ionoscloud.com --storage-class STANDARD
|
<<<<<<< HEAD
|
||||||
|
aws s3 cp $FILE_NAME_COMPLETE s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-3.ionoscloud.com --storage-class STANDARD
|
||||||
|
=======
|
||||||
|
aws s3 cp $FILE_NAME_COMPLETE s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3.eu-central-3.ionoscloud.com --storage-class STANDARD
|
||||||
|
>>>>>>> dev
|
||||||
|
|
||||||
echo "Uploaded $FILE_NAME_COMPLETE"
|
echo "Uploaded $FILE_NAME_COMPLETE"
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
|
name: database
|
||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
build: ./
|
build: ./
|
||||||
|
|||||||
@@ -41,19 +41,19 @@ model BedarfsausweisWohnen {
|
|||||||
volumen Float?
|
volumen Float?
|
||||||
dicht Boolean?
|
dicht Boolean?
|
||||||
fenster_flaeche_1 Float?
|
fenster_flaeche_1 Float?
|
||||||
fenster_art_1 String?
|
fenster_art_1 Float?
|
||||||
fenster_flaeche_2 Float?
|
fenster_flaeche_2 Float?
|
||||||
fenster_art_2 String?
|
fenster_art_2 Float?
|
||||||
dachfenster_flaeche Float?
|
dachfenster_flaeche Float?
|
||||||
dachfenster_art String?
|
dachfenster_art Float?
|
||||||
haustuer_flaeche Float?
|
haustuer_flaeche Float?
|
||||||
haustuer_art String?
|
haustuer_art Float?
|
||||||
dach_bauart String? @db.VarChar
|
dach_bauart String? @db.VarChar
|
||||||
decke_bauart String? @db.VarChar
|
decke_bauart String? @db.VarChar
|
||||||
dach_daemmung String?
|
dach_daemmung Float?
|
||||||
decke_daemmung String?
|
decke_daemmung Float?
|
||||||
aussenwand_daemmung String?
|
aussenwand_daemmung Float?
|
||||||
boden_daemmung String?
|
boden_daemmung Float?
|
||||||
aussenwand_bauart String? @db.VarChar
|
aussenwand_bauart String? @db.VarChar
|
||||||
boden_bauart String? @db.VarChar
|
boden_bauart String? @db.VarChar
|
||||||
warmwasser_verteilung String? @db.VarChar
|
warmwasser_verteilung String? @db.VarChar
|
||||||
|
|||||||
@@ -2,28 +2,34 @@
|
|||||||
|
|
||||||
# === Configuration ===
|
# === Configuration ===
|
||||||
BUCKET_NAME="ibc-db-backup"
|
BUCKET_NAME="ibc-db-backup"
|
||||||
ENDPOINT_URL="https://s3-eu-central-1.ionoscloud.com"
|
ENDPOINT_URL="https://s3.eu-central-3.ionoscloud.com"
|
||||||
LOCAL_DOWNLOAD_DIR="./" # Where to save the file
|
LOCAL_DOWNLOAD_DIR="./"
|
||||||
|
|
||||||
# === Get latest file from IONOS S3 bucket ===
|
# === Use filename from argument if provided ===
|
||||||
LATEST_FILE=$(aws s3api list-objects-v2 \
|
if [ -n "$1" ]; then
|
||||||
|
LATEST_FILE="$1"
|
||||||
|
else
|
||||||
|
echo "📡 No filename provided, fetching latest..."
|
||||||
|
# === Get latest file from IONOS S3 bucket ===
|
||||||
|
LATEST_FILE=$(aws --profile ionos s3api list-objects-v2 \
|
||||||
--bucket "$BUCKET_NAME" \
|
--bucket "$BUCKET_NAME" \
|
||||||
--prefix "data-dump" \
|
--prefix "full-dump" \
|
||||||
--endpoint-url "$ENDPOINT_URL" \
|
--endpoint-url "$ENDPOINT_URL" \
|
||||||
--query 'Contents | sort_by(@, &LastModified) | [-1].Key' \
|
--query 'Contents | sort_by(@, &LastModified) | [-1].Key' \
|
||||||
--output text)
|
--output text)
|
||||||
|
|
||||||
# === Check if file was found ===
|
# === Check if file was found ===
|
||||||
if [ "$LATEST_FILE" == "None" ] || [ -z "$LATEST_FILE" ]; then
|
if [ "$LATEST_FILE" == "None" ] || [ -z "$LATEST_FILE" ]; then
|
||||||
echo "❌ No matching .sql.br file found."
|
echo "❌ No matching .sql.br file found."
|
||||||
exit 1
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
FILENAME=$(basename "$LATEST_FILE")
|
FILENAME=$(basename "$LATEST_FILE")
|
||||||
SQL_FILE="${FILENAME%.br}" # Remove .br suffix
|
SQL_FILE="${FILENAME%.br}" # Remove .br suffix
|
||||||
|
|
||||||
echo "📥 Downloading $LATEST_FILE"
|
echo "📥 Downloading $LATEST_FILE"
|
||||||
aws s3 cp "s3://$BUCKET_NAME/$LATEST_FILE" "$LOCAL_DOWNLOAD_DIR" \
|
aws --profile ionos s3 cp "s3://$BUCKET_NAME/$LATEST_FILE" "$LOCAL_DOWNLOAD_DIR" \
|
||||||
--endpoint-url "$ENDPOINT_URL"
|
--endpoint-url "$ENDPOINT_URL"
|
||||||
|
|
||||||
# === Decompress with Brotli ===
|
# === Decompress with Brotli ===
|
||||||
@@ -31,8 +37,8 @@ echo "🗜️ Decompressing $FILENAME -> $SQL_FILE"
|
|||||||
brotli -d "$FILENAME"
|
brotli -d "$FILENAME"
|
||||||
|
|
||||||
# === Import into Postgres inside Docker ===
|
# === Import into Postgres inside Docker ===
|
||||||
echo "🐘 Importing into PostgreSQL (online-energieausweis-database-1:main)"
|
echo "🐘 Importing into PostgreSQL (database:main)"
|
||||||
docker exec -i "online-energieausweis-database-1" env PGPASSWORD="hHMP8cd^N3SnzGRR" \
|
docker exec -i "database" env PGPASSWORD="hHMP8cd^N3SnzGRR" \
|
||||||
psql -U "main" -d "main" < "$SQL_FILE"
|
psql -U "main" -d "main" < "$SQL_FILE"
|
||||||
|
|
||||||
echo "✅ Import complete."
|
echo "✅ Import complete."
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const createCaller = createCallerFactory({
|
|||||||
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
|
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
|
||||||
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
|
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
|
||||||
"unterlage": await import("../src/pages/api/unterlage.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/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"),
|
||||||
"admin/bedarfsausweis-ausstellen": await import("../src/pages/api/admin/bedarfsausweis-ausstellen.ts"),
|
"admin/bedarfsausweis-ausstellen": await import("../src/pages/api/admin/bedarfsausweis-ausstellen.ts"),
|
||||||
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
|
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
|
||||||
@@ -12,13 +13,15 @@ export const createCaller = createCallerFactory({
|
|||||||
"admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"),
|
"admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"),
|
||||||
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
|
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
|
||||||
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
|
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
|
||||||
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
|
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
|
||||||
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
|
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
|
||||||
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.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"),
|
"auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
|
||||||
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
|
"auth/verification-code": await import("../src/pages/api/auth/verification-code.ts"),
|
||||||
|
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
|
||||||
"bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"),
|
"bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"),
|
||||||
"bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/index.ts"),
|
"bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/index.ts"),
|
||||||
|
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
|
||||||
"bedarfsausweis-wohnen/[id]": await import("../src/pages/api/bedarfsausweis-wohnen/[id].ts"),
|
"bedarfsausweis-wohnen/[id]": await import("../src/pages/api/bedarfsausweis-wohnen/[id].ts"),
|
||||||
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"),
|
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"),
|
||||||
"bilder/[id]": await import("../src/pages/api/bilder/[id].ts"),
|
"bilder/[id]": await import("../src/pages/api/bilder/[id].ts"),
|
||||||
@@ -31,15 +34,14 @@ export const createCaller = createCallerFactory({
|
|||||||
"rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"),
|
"rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"),
|
||||||
"rechnung": await import("../src/pages/api/rechnung/index.ts"),
|
"rechnung": await import("../src/pages/api/rechnung/index.ts"),
|
||||||
"ticket": await import("../src/pages/api/ticket/index.ts"),
|
"ticket": await import("../src/pages/api/ticket/index.ts"),
|
||||||
"user": await import("../src/pages/api/user/index.ts"),
|
|
||||||
"user/self": await import("../src/pages/api/user/self.ts"),
|
"user/self": await import("../src/pages/api/user/self.ts"),
|
||||||
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
|
|
||||||
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
|
|
||||||
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
|
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
|
||||||
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
|
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
|
||||||
|
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
|
||||||
|
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
|
||||||
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
|
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
|
||||||
|
"objekt/[id]": await import("../src/pages/api/objekt/[id]/index.ts"),
|
||||||
"aufnahme/[id]/bilder": await import("../src/pages/api/aufnahme/[id]/bilder.ts"),
|
"aufnahme/[id]/bilder": await import("../src/pages/api/aufnahme/[id]/bilder.ts"),
|
||||||
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),
|
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),
|
||||||
"aufnahme/[id]/unterlagen": await import("../src/pages/api/aufnahme/[id]/unterlagen.ts"),
|
"aufnahme/[id]/unterlagen": await import("../src/pages/api/aufnahme/[id]/unterlagen.ts"),
|
||||||
"objekt/[id]": await import("../src/pages/api/objekt/[id]/index.ts"),
|
|
||||||
})
|
})
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { BedarfsausweisWohnen, Enums, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/server/prisma.js";
|
import { BedarfsausweisWohnen, Enums, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/server/prisma.js";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { format } from "sharp";
|
|
||||||
|
|
||||||
export let bestellungen: (Rechnung & {
|
export let bestellungen: (Rechnung & {
|
||||||
verbrauchsausweis_wohnen: VerbrauchsausweisWohnen | null,
|
verbrauchsausweis_wohnen: VerbrauchsausweisWohnen | null,
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ const brennstoffe: [
|
|||||||
["Fernwärme KWK EB", "kWh", 1.0, 0.0, 0.04],
|
["Fernwärme KWK EB", "kWh", 1.0, 0.0, 0.04],
|
||||||
["Fernwärme HKW FB", "kWh", 1.0, 1.3, 0.4],
|
["Fernwärme HKW FB", "kWh", 1.0, 1.3, 0.4],
|
||||||
["Fernwärme HKW EB", "kWh", 1.0, 0.1, 0.06],
|
["Fernwärme HKW EB", "kWh", 1.0, 0.1, 0.06],
|
||||||
|
["Fernwärme Hamburg", "kWh", 1.0, 0.33, 0.064],
|
||||||
["Erdgas", "kWh", 1.0, 1.1, 0.24],
|
["Erdgas", "kWh", 1.0, 1.1, 0.24],
|
||||||
["Heizöl", "kWh", 1.0, 1.1, 0.31],
|
["Heizöl", "kWh", 1.0, 1.1, 0.31],
|
||||||
["Heizöl", "l", 10.0, 1.1, 0.31],
|
["Heizöl", "l", 10.0, 1.1, 0.31],
|
||||||
|
|||||||
@@ -257,6 +257,12 @@
|
|||||||
|
|
||||||
let bedarfsausweisFileInput: HTMLInputElement;
|
let bedarfsausweisFileInput: HTMLInputElement;
|
||||||
let bedarfsausweisAdditionalInput: HTMLInputElement;
|
let bedarfsausweisAdditionalInput: HTMLInputElement;
|
||||||
|
|
||||||
|
let dropdownOpen = false;
|
||||||
|
|
||||||
|
function toggleDropdown() {
|
||||||
|
dropdownOpen = !dropdownOpen;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4 mx-2">
|
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4 mx-2">
|
||||||
@@ -273,30 +279,41 @@
|
|||||||
{/if}
|
{/if}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div
|
<div
|
||||||
class="flex justify-end mb-2 dropdown dropdown-bottom absolute top-4 right-4"
|
class="mb-2 dropdown dropdown-bottom absolute top-4 right-4 bg-base-100"
|
||||||
>
|
>
|
||||||
<button class="rounded-full p-2.5 hover:bg-base-100">
|
<button class="rounded-full p-2.5 hover:bg-base-100" on:click={toggleDropdown}>
|
||||||
<DotsVertical size={15} />
|
<DotsVertical size={15} />
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
{#if dropdownOpen}
|
||||||
<ul
|
<ul
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-64 gap-2"
|
class="z-[1] menu p-2 shadow bg-base-100 rounded-box w-64 gap-2 border"
|
||||||
>
|
>
|
||||||
<li>
|
<!-- <div>
|
||||||
<button on:click={ausweisStornieren}
|
<button on:click={ausweisStornieren} class="flex items-center gap-2" disabled
|
||||||
><CrossCircled size={15} />Ausweis Stornieren</button
|
><CrossCircled size={15} />Stornieren</button
|
||||||
>
|
>
|
||||||
</li>
|
</div>
|
||||||
<li>
|
<div>
|
||||||
<button><Pencil2 size={15} /> Als Vorlage benutzen</button>
|
<button class="flex items-center gap-2" disabled
|
||||||
</li>
|
><Pencil2 size={15} /> Als Vorlage</button>
|
||||||
<li>
|
</div>
|
||||||
<button on:click={() => hilfeModal.showModal()}
|
<div>
|
||||||
|
<button on:click={() => hilfeModal.showModal()} class="flex items-center gap-2" disabled
|
||||||
><QuestionMarkCircled size={15} /> Hilfe Erhalten</button
|
><QuestionMarkCircled size={15} /> Hilfe Erhalten</button
|
||||||
>
|
>
|
||||||
</li>
|
</div> -->
|
||||||
</ul>
|
{#if ausweis.bestellt && rechnung}
|
||||||
|
<div>
|
||||||
|
<a href="/dashboard/rechnung/aendern?rechnungid={rechnung.id}"><button> Adresse ändern</button
|
||||||
|
></a>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
|
||||||
<div class="flex flex-row flex-wrap items-center gap-2">
|
<div class="flex flex-row flex-wrap items-center gap-2">
|
||||||
{#if ausweis.ausgestellt}
|
{#if ausweis.ausgestellt}
|
||||||
<span class="bg-green-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Ausgestellt</span>
|
<span class="bg-green-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Ausgestellt</span>
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade } from "svelte/transition";
|
|
||||||
import WidgetCardTemplate from "#components/widgets/immowelt/WidgetCardTemplate.svelte";
|
import WidgetCardTemplate from "#components/widgets/immowelt/WidgetCardTemplate.svelte";
|
||||||
import { PRICES } from "#lib/constants.js";
|
import { PRICES } from "#lib/constants.js";
|
||||||
import { Enums } from "#lib/client/prisma";
|
import { Enums } from "#lib/client/prisma.js";
|
||||||
|
|
||||||
|
|
||||||
let ausnahme: boolean = false;
|
let ausnahme: boolean = false;
|
||||||
let oneBOX: boolean = false;
|
let oneBOX: boolean = false;
|
||||||
@@ -17,56 +15,54 @@
|
|||||||
let heizungsAlter: string = "bitte auswählen";
|
let heizungsAlter: string = "bitte auswählen";
|
||||||
let leerStand: string = "bitte auswählen";
|
let leerStand: string = "bitte auswählen";
|
||||||
|
|
||||||
const partner:string = "immowelt";
|
const partner: string = "immowelt";
|
||||||
|
|
||||||
const twoBoxReason = ["Vermietung/Verkauf", "Aushangpflicht", "Sonstiges"];
|
const twoBoxReason = ["Vermietung/Verkauf", "Aushangpflicht", "Sonstiges"];
|
||||||
const gewerbeHouse = ["Gewerbegebäude", "Mischgebäude"];
|
const gewerbeHouse = ["Gewerbegebäude", "Mischgebäude"];
|
||||||
|
|
||||||
$: ausnahme =
|
$: ausnahme =
|
||||||
leerStand === "mehr als 30" ||
|
leerStand === "mehr als 30" ||
|
||||||
heizungsAlter === "< 3" ||
|
heizungsAlter === "< 3" ||
|
||||||
(baujahr === "vor 1978" && einheiten === "bis 4 Wohneinheiten" && sanierungsstatus === "unsaniert");
|
(baujahr === "vor 1978" &&
|
||||||
|
einheiten === "bis 4 Wohneinheiten" &&
|
||||||
|
sanierungsstatus === "unsaniert");
|
||||||
|
|
||||||
$: isTwoBoxReason = twoBoxReason.includes(anlass);
|
$: isTwoBoxReason = twoBoxReason.includes(anlass);
|
||||||
|
|
||||||
$: isGewerbe = gewerbeHouse.includes(gebaeudetyp);
|
$: isGewerbe = gewerbeHouse.includes(gebaeudetyp);
|
||||||
|
|
||||||
$: oneBOX =
|
$: oneBOX =
|
||||||
(ausnahme && !isGewerbe) ||
|
(ausnahme && !isGewerbe) ||
|
||||||
(!isTwoBoxReason && gebaeudetyp !== "Mischgebäude") ||
|
(!isTwoBoxReason && gebaeudetyp !== "Mischgebäude") ||
|
||||||
(gebaeudetyp === "Gewerbegebäude" && leerStand === "mehr als 30");
|
(gebaeudetyp === "Gewerbegebäude" && leerStand === "mehr als 30");
|
||||||
|
|
||||||
$: threeBOX =
|
$: threeBOX =
|
||||||
(ausnahme && gebaeudetyp === "Mischgebäude" && isTwoBoxReason && leerStand !== "mehr als 30");
|
ausnahme &&
|
||||||
|
gebaeudetyp === "Mischgebäude" &&
|
||||||
$: standardXL =
|
isTwoBoxReason &&
|
||||||
(einheiten === "mehr als 4 Wohneinheiten")
|
leerStand !== "mehr als 30";
|
||||||
|
|
||||||
|
$: standardXL = einheiten === "mehr als 4 Wohneinheiten";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div id="IBC_app">
|
<div id="IBC_app">
|
||||||
|
|
||||||
<input id="recode" type="hidden" value="widgetvorlage" />
|
<input id="recode" type="hidden" value="widgetvorlage" />
|
||||||
|
|
||||||
<div id="OEA_input">
|
<div id="OEA_input">
|
||||||
|
<div
|
||||||
|
id="firstrow"
|
||||||
<div id="firstrow" class="firstrow"
|
class="firstrow"
|
||||||
class:sm:grid-cols-3={isTwoBoxReason}
|
class:sm:grid-cols-3={isTwoBoxReason}
|
||||||
class:sm:grid-cols-2={!isTwoBoxReason}>
|
class:sm:grid-cols-2={!isTwoBoxReason}
|
||||||
|
>
|
||||||
|
|
||||||
|
|
||||||
<div class="auswahl">
|
<div class="auswahl">
|
||||||
<div class="titel">Anlass</div>
|
<div class="titel">Anlass</div>
|
||||||
<select
|
<select id="anlass" class="selectfeld" bind:value={anlass}>
|
||||||
id="anlass"
|
|
||||||
class="selectfeld"
|
|
||||||
bind:value={anlass}>
|
|
||||||
>
|
>
|
||||||
<option selected disabled>bitte auswählen</option>
|
<option selected disabled>bitte auswählen</option>
|
||||||
<option value="Vermietung/Verkauf">Vermietung/Verkauf</option>
|
<option value="Vermietung/Verkauf"
|
||||||
|
>Vermietung/Verkauf</option
|
||||||
|
>
|
||||||
<option value="Modernisierung">Modernisierung</option>
|
<option value="Modernisierung">Modernisierung</option>
|
||||||
<option value="Neubau">Neubau</option>
|
<option value="Neubau">Neubau</option>
|
||||||
<option value="Erweiterung">Erweiterung</option>
|
<option value="Erweiterung">Erweiterung</option>
|
||||||
@@ -77,9 +73,7 @@ $: standardXL =
|
|||||||
|
|
||||||
<div class="auswahl">
|
<div class="auswahl">
|
||||||
<div class="titel">Gebäudetyp</div>
|
<div class="titel">Gebäudetyp</div>
|
||||||
<select
|
<select class="selectfeld" bind:value={gebaeudetyp}>
|
||||||
class="selectfeld"
|
|
||||||
bind:value={gebaeudetyp}>
|
|
||||||
>
|
>
|
||||||
<option selected disabled>bitte auswählen</option>
|
<option selected disabled>bitte auswählen</option>
|
||||||
<option value="Einfamilienhaus">Einfamilienhaus</option>
|
<option value="Einfamilienhaus">Einfamilienhaus</option>
|
||||||
@@ -93,10 +87,7 @@ $: standardXL =
|
|||||||
{#if isTwoBoxReason}
|
{#if isTwoBoxReason}
|
||||||
<div class="auswahl">
|
<div class="auswahl">
|
||||||
<div class="titel">Sanierungsstand</div>
|
<div class="titel">Sanierungsstand</div>
|
||||||
<select
|
<select class="selectfeld" bind:value={sanierungsstatus}>
|
||||||
class="selectfeld"
|
|
||||||
bind:value={sanierungsstatus}>
|
|
||||||
|
|
||||||
>
|
>
|
||||||
<option selected disabled>bitte auswählen</option>
|
<option selected disabled>bitte auswählen</option>
|
||||||
<option value="saniert">saniert</option>
|
<option value="saniert">saniert</option>
|
||||||
@@ -104,7 +95,6 @@ $: standardXL =
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if isTwoBoxReason}
|
{#if isTwoBoxReason}
|
||||||
@@ -115,7 +105,6 @@ $: standardXL =
|
|||||||
id="baujahr"
|
id="baujahr"
|
||||||
class="selectfeld"
|
class="selectfeld"
|
||||||
bind:value={baujahr}
|
bind:value={baujahr}
|
||||||
|
|
||||||
>
|
>
|
||||||
<option selected disabled>bitte auswählen</option>
|
<option selected disabled>bitte auswählen</option>
|
||||||
<option value="vor 1978">vor 1978</option>
|
<option value="vor 1978">vor 1978</option>
|
||||||
@@ -125,10 +114,7 @@ $: standardXL =
|
|||||||
|
|
||||||
<div class="auswahl">
|
<div class="auswahl">
|
||||||
<div class="titel">Heizungsalter</div>
|
<div class="titel">Heizungsalter</div>
|
||||||
<select
|
<select class="selectfeld" bind:value={heizungsAlter}>
|
||||||
class="selectfeld"
|
|
||||||
bind:value={heizungsAlter}
|
|
||||||
>
|
|
||||||
<option selected disabled>bitte auswählen</option>
|
<option selected disabled>bitte auswählen</option>
|
||||||
<option value="< 3">jünger als 3 Jahre</option>
|
<option value="< 3">jünger als 3 Jahre</option>
|
||||||
<option value=">= 3">3 Jahre oder älter</option>
|
<option value=">= 3">3 Jahre oder älter</option>
|
||||||
@@ -137,10 +123,7 @@ $: standardXL =
|
|||||||
|
|
||||||
<div class="auswahl">
|
<div class="auswahl">
|
||||||
<div class="titel">Wohneinheiten</div>
|
<div class="titel">Wohneinheiten</div>
|
||||||
<select
|
<select class="selectfeld" bind:value={einheiten}>
|
||||||
class="selectfeld"
|
|
||||||
bind:value={einheiten}
|
|
||||||
>
|
|
||||||
<option selected disabled>bitte auswählen</option>
|
<option selected disabled>bitte auswählen</option>
|
||||||
<option value="bis 4 Wohneinheiten"
|
<option value="bis 4 Wohneinheiten"
|
||||||
>bis 4 Wohneinheiten</option
|
>bis 4 Wohneinheiten</option
|
||||||
@@ -153,10 +136,7 @@ $: standardXL =
|
|||||||
|
|
||||||
<div class="OEA_item4">
|
<div class="OEA_item4">
|
||||||
<div class="titel">Leerstand</div>
|
<div class="titel">Leerstand</div>
|
||||||
<select
|
<select class="selectfeld ausnahmen" bind:value={leerStand}>
|
||||||
class="selectfeld ausnahmen"
|
|
||||||
bind:value={leerStand}
|
|
||||||
>
|
|
||||||
<option selected disabled>bitte auswählen</option>
|
<option selected disabled>bitte auswählen</option>
|
||||||
<option value="bis 30">bis 30%</option>
|
<option value="bis 30">bis 30%</option>
|
||||||
<option value="mehr als 30">mehr als 30%</option>
|
<option value="mehr als 30">mehr als 30%</option>
|
||||||
@@ -165,20 +145,34 @@ $: standardXL =
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div id="thirdrow" class="thirdrow"
|
<div
|
||||||
|
id="thirdrow"
|
||||||
|
class="thirdrow"
|
||||||
class:grid-cols-1={oneBOX}
|
class:grid-cols-1={oneBOX}
|
||||||
class:md:grid-cols-6={threeBOX}
|
class:md:grid-cols-6={threeBOX}
|
||||||
class:md:grid-cols-4={!oneBOX && !threeBOX}
|
class:md:grid-cols-4={!oneBOX && !threeBOX}
|
||||||
>
|
>
|
||||||
|
{#if isTwoBoxReason && gebaeudetyp != "Gewerbegebäude" && ausnahme === false}
|
||||||
|
|
||||||
{#if isTwoBoxReason && (gebaeudetyp != "Gewerbegebäude") && (ausnahme === false)}
|
|
||||||
|
|
||||||
|
|
||||||
<WidgetCardTemplate
|
<WidgetCardTemplate
|
||||||
name="Verbrauchsausweis Wohngebäude"
|
name="Verbrauchsausweis Wohngebäude"
|
||||||
price={PRICES.VerbrauchsausweisWohnen[Enums.AusweisTyp.Standard] + (standardXL ? 10 : 0)}
|
price={PRICES.VerbrauchsausweisWohnen[
|
||||||
src={'https://online-energieausweis.org/images/partner/'+partner+'/wohngebaeude.svg'}
|
standardXL
|
||||||
|
? Enums.AusweisTyp.standardXL
|
||||||
|
: Enums.AusweisTyp.Standard
|
||||||
|
]}
|
||||||
|
price1={PRICES.VerbrauchsausweisWohnen[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.BeratungXL
|
||||||
|
: Enums.AusweisTyp.Beratung
|
||||||
|
]}
|
||||||
|
price2={PRICES.VerbrauchsausweisWohnen[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.OfflineXL
|
||||||
|
: Enums.AusweisTyp.Offline
|
||||||
|
]}
|
||||||
|
src={"https://online-energieausweis.org/images/partner/" +
|
||||||
|
partner +
|
||||||
|
"/wohngebaeude.svg"}
|
||||||
alt="Wohnhaus Verbrauchsausweis"
|
alt="Wohnhaus Verbrauchsausweis"
|
||||||
variant="einfach"
|
variant="einfach"
|
||||||
empfehlung="nein"
|
empfehlung="nein"
|
||||||
@@ -186,22 +180,40 @@ $: standardXL =
|
|||||||
services={[
|
services={[
|
||||||
["3 Jahresverbräuche der Heizung benötigt.", true],
|
["3 Jahresverbräuche der Heizung benötigt.", true],
|
||||||
["Zulässig bei Vermietung oder Verkauf.", true],
|
["Zulässig bei Vermietung oder Verkauf.", true],
|
||||||
["Unzulässig bei unsanierten Gebäuden vor 1978.", false],
|
[
|
||||||
|
"Unzulässig bei unsanierten Gebäuden vor 1978.",
|
||||||
|
false,
|
||||||
|
],
|
||||||
["Ungenau durch individuelles Heizverhalten.", false],
|
["Ungenau durch individuelles Heizverhalten.", false],
|
||||||
["Wird nicht immer bei den Banken akzeptiert.", false]
|
["Wird nicht immer bei den Banken akzeptiert.", false],
|
||||||
]}
|
]}
|
||||||
href_buy={"https://online-energieausweis.org/"+partner+"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/"}{standardXL ? '?ausweistyp=standardXL' : ''}
|
href_buy1={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/${standardXL ? "?ausweistyp=standardXL" : ""}`}
|
||||||
href_overview={"https://online-energieausweis.org/"+partner+"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/produkt-uebersicht/"}{standardXL ? '?ausweistyp=standardXL' : ''}
|
href_buy2={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/${standardXL ? "?ausweistyp=BeratungXL" : "?ausweistyp=Beratung"}`}
|
||||||
|
href_buy3={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/${standardXL ? "?ausweistyp=OfflineXL" : "?ausweistyp=Offline"}`}
|
||||||
></WidgetCardTemplate>
|
></WidgetCardTemplate>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isTwoBoxReason && (gebaeudetyp != "Gewerbegebäude")}
|
{#if isTwoBoxReason && gebaeudetyp != "Gewerbegebäude"}
|
||||||
|
|
||||||
<WidgetCardTemplate
|
<WidgetCardTemplate
|
||||||
name="Bedarfsausweis Wohngebäude"
|
name="Bedarfsausweis Wohngebäude"
|
||||||
price={PRICES.BedarfsausweisWohnen[Enums.AusweisTyp.Standard] + (standardXL ? 25 : 0)}
|
price={PRICES.BedarfsausweisWohnen[
|
||||||
src={'https://online-energieausweis.org/images/partner/'+partner+'/wohngebaeude.svg'}
|
standardXL
|
||||||
|
? Enums.AusweisTyp.standardXL
|
||||||
|
: Enums.AusweisTyp.Standard
|
||||||
|
]}
|
||||||
|
price1={PRICES.BedarfsausweisWohnen[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.BeratungXL
|
||||||
|
: Enums.AusweisTyp.Beratung
|
||||||
|
]}
|
||||||
|
price2={PRICES.BedarfsausweisWohnen[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.OfflineXL
|
||||||
|
: Enums.AusweisTyp.Offline
|
||||||
|
]}
|
||||||
|
src={"https://online-energieausweis.org/images/partner/" +
|
||||||
|
partner +
|
||||||
|
"/wohngebaeude.svg"}
|
||||||
alt="Wohnhaus Bedarfsausweis"
|
alt="Wohnhaus Bedarfsausweis"
|
||||||
variant="fundiert"
|
variant="fundiert"
|
||||||
empfehlung="ja"
|
empfehlung="ja"
|
||||||
@@ -211,181 +223,283 @@ $: standardXL =
|
|||||||
["Für Vermietung, Verkauf und Finanzierung.", true],
|
["Für Vermietung, Verkauf und Finanzierung.", true],
|
||||||
["Zulässig auch für unsanierte Objekte.", true],
|
["Zulässig auch für unsanierte Objekte.", true],
|
||||||
["Kann als Grundlage für den ISFP dienen.", true],
|
["Kann als Grundlage für den ISFP dienen.", true],
|
||||||
["Objektivere Berechnungsmethode nach DIN 18599.", true],
|
[
|
||||||
|
"Objektivere Berechnungsmethode nach DIN 18599.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
]}
|
]}
|
||||||
href_buy={"https://online-energieausweis.org/"+partner+"/energieausweis-erstellen/bedarfsausweis-wohngebaeude/"}{standardXL ? '?ausweistyp=standardXL' : ''}
|
href_buy1={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/bedarfsausweis-wohngebaeude/${standardXL ? "?ausweistyp=standardXL" : ""}`}
|
||||||
href_overview={"https://online-energieausweis.org/"+partner+"/energieausweis-erstellen/bedarfsausweis-wohngebaeude/produkt-uebersicht"}{standardXL ? '?ausweistyp=standardXL' : ''}
|
href_buy2={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/bedarfsausweis-wohngebaeude/${standardXL ? "?ausweistyp=BeratungXL" : "?ausweistyp=Beratung"}`}
|
||||||
|
href_buy3={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/bedarfsausweis-wohngebaeude/${standardXL ? "?ausweistyp=OfflineXL" : "?ausweistyp=Offline"}`}
|
||||||
></WidgetCardTemplate>
|
></WidgetCardTemplate>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isTwoBoxReason && isGewerbe && (leerStand != "mehr als 30")}
|
{#if isTwoBoxReason && isGewerbe && leerStand != "mehr als 30"}
|
||||||
|
|
||||||
<WidgetCardTemplate
|
<WidgetCardTemplate
|
||||||
name="Verbrauchsausweis Gewerbegebäude"
|
name="Verbrauchsausweis Gewerbegebäude"
|
||||||
price={PRICES.VerbrauchsausweisGewerbe[Enums.AusweisTyp.Standard] + (standardXL ? 15 : 0)}
|
price={PRICES.VerbrauchsausweisGewerbe[
|
||||||
src={'https://online-energieausweis.org/images/partner/'+partner+'/gewerbegebaeude.svg'}
|
standardXL
|
||||||
|
? Enums.AusweisTyp.standardXL
|
||||||
|
: Enums.AusweisTyp.Standard
|
||||||
|
]}
|
||||||
|
price1={PRICES.VerbrauchsausweisGewerbe[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.BeratungXL
|
||||||
|
: Enums.AusweisTyp.Beratung
|
||||||
|
]}
|
||||||
|
price2={PRICES.VerbrauchsausweisGewerbe[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.OfflineXL
|
||||||
|
: Enums.AusweisTyp.Offline
|
||||||
|
]}
|
||||||
|
src={"https://online-energieausweis.org/images/partner/" +
|
||||||
|
partner +
|
||||||
|
"/gewerbegebaeude.svg"}
|
||||||
alt="Gewerbe Verbrauchsausweis"
|
alt="Gewerbe Verbrauchsausweis"
|
||||||
variant="einfach"
|
variant="einfach"
|
||||||
empfehlung="nein"
|
empfehlung="nein"
|
||||||
cta="jetzt online erstellen"
|
cta="jetzt online erstellen"
|
||||||
services={[
|
services={[
|
||||||
|
[
|
||||||
["3 Jahresverbräuche von Heizung Gebäudestrom nötig.", true],
|
"3 Jahresverbräuche von Heizung Gebäudestrom nötig.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
["Zulässig bei Vermietung oder Verkauf.", true],
|
["Zulässig bei Vermietung oder Verkauf.", true],
|
||||||
["Für bauliche und energetische Maßnahmen ungeeignet.", false],
|
[
|
||||||
|
"Für bauliche und energetische Maßnahmen ungeeignet.",
|
||||||
|
false,
|
||||||
|
],
|
||||||
["Wird nicht immer bei den Banken akzeptiert.", false],
|
["Wird nicht immer bei den Banken akzeptiert.", false],
|
||||||
["Ungenau durch individuelles Heizverhalten", false],
|
["Ungenau durch individuelles Heizverhalten", false],
|
||||||
]}
|
]}
|
||||||
href_buy={"https://online-energieausweis.org/"+partner+"/energieausweis-erstellen/verbrauchsausweis-gewerbe/"}{standardXL ? '?ausweistyp=standardXL' : ''}
|
href_buy1={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/verbrauchsausweis-gewerbe/${standardXL ? "?ausweistyp=standardXL" : ""}`}
|
||||||
href_overview={"https://online-energieausweis.org/"+partner+"/energieausweis-erstellen/verbrauchsausweis-gewerbe/produkt-uebersicht/"}{standardXL ? '?ausweistyp=standardXL' : ''}
|
href_buy2={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/verbrauchsausweis-gewerbe/${standardXL ? "?ausweistyp=BeratungXL" : "?ausweistyp=Beratung"}`}
|
||||||
|
href_buy3={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/verbrauchsausweis-gewerbe/${standardXL ? "?ausweistyp=OfflineXL" : "?ausweistyp=Offline"}`}
|
||||||
></WidgetCardTemplate>
|
></WidgetCardTemplate>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if isTwoBoxReason && isGewerbe}
|
{#if isTwoBoxReason && isGewerbe}
|
||||||
|
|
||||||
<WidgetCardTemplate
|
<WidgetCardTemplate
|
||||||
name="Bedarfsausweis Gewerbegebäude"
|
name="Bedarfsausweis Gewerbegebäude"
|
||||||
price={PRICES.BedarfsausweisGewerbe[Enums.AusweisTyp.Standard]}
|
price={PRICES.BedarfsausweisGewerbe[
|
||||||
src={'https://online-energieausweis.org/images/partner/'+partner+'/gewerbegebaeude.svg'}
|
standardXL
|
||||||
|
? Enums.AusweisTyp.standardXL
|
||||||
|
: Enums.AusweisTyp.Standard
|
||||||
|
]}
|
||||||
|
price1={PRICES.BedarfsausweisGewerbe[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.BeratungXL
|
||||||
|
: Enums.AusweisTyp.Beratung
|
||||||
|
]}
|
||||||
|
price2={PRICES.BedarfsausweisGewerbe[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.OfflineXL
|
||||||
|
: Enums.AusweisTyp.Offline
|
||||||
|
]}
|
||||||
|
src={"https://online-energieausweis.org/images/partner/" +
|
||||||
|
partner +
|
||||||
|
"/gewerbegebaeude.svg"}
|
||||||
alt="Gewerbe Bedarfsausweis"
|
alt="Gewerbe Bedarfsausweis"
|
||||||
variant="fundiert"
|
variant="fundiert"
|
||||||
empfehlung="ja"
|
empfehlung="ja"
|
||||||
cta="Angebot anfragen"
|
cta="Angebot anfragen"
|
||||||
services={[
|
services={[
|
||||||
|
|
||||||
["Mehrzonenmodell nach DIN 18599.", true],
|
["Mehrzonenmodell nach DIN 18599.", true],
|
||||||
["Zulässig bei Vermietung oder Verkauf.", true],
|
["Zulässig bei Vermietung oder Verkauf.", true],
|
||||||
["Grundlage für Sanierung-Varianten.", true],
|
["Grundlage für Sanierung-Varianten.", true],
|
||||||
["Objektiveres, besser vergleichbares Ergebnis.", true],
|
["Objektiveres, besser vergleichbares Ergebnis.", true],
|
||||||
["Zulässig bei Leerstand oder fehlenden Verbräuchen", true],
|
[
|
||||||
|
"Zulässig bei Leerstand oder fehlenden Verbräuchen",
|
||||||
|
true,
|
||||||
|
],
|
||||||
]}
|
]}
|
||||||
href_buy={"https://online-energieausweis.org/"+partner+"/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/"}
|
href_buy1={`https://online-energieausweis.org/${partner}/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/${standardXL ? "?ausweistyp=standardXL" : ""}`}
|
||||||
href_overview={"https://online-energieausweis.org/"+partner+"/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/produkt-uebersicht/"}
|
href_buy2={`https://online-energieausweis.org/${partner}/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/${standardXL ? "?ausweistyp=BeratungXL" : "?ausweistyp=Beratung"}`}
|
||||||
></WidgetCardTemplate>
|
></WidgetCardTemplate>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if (anlass != "bitte auswählen") && !isTwoBoxReason && (gebaeudetyp != "Gewerbegebäude")}
|
{#if anlass != "bitte auswählen" && !isTwoBoxReason && gebaeudetyp != "Gewerbegebäude"}
|
||||||
|
|
||||||
<WidgetCardTemplate
|
<WidgetCardTemplate
|
||||||
name="GEG-Nachweis Wohngebäude"
|
name="GEG-Nachweis Wohngebäude"
|
||||||
price={PRICES.GEGNachweisWohnen[Enums.AusweisTyp.Standard]}
|
price={PRICES.GEGNachweisWohnen[
|
||||||
src={'https://online-energieausweis.org/images/partner/'+partner+'/wohngebaeude.svg'}
|
standardXL
|
||||||
|
? Enums.AusweisTyp.standardXL
|
||||||
|
: Enums.AusweisTyp.Standard
|
||||||
|
]}
|
||||||
|
price1={PRICES.GEGNachweisWohnen[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.BeratungXL
|
||||||
|
: Enums.AusweisTyp.Beratung
|
||||||
|
]}
|
||||||
|
price2={PRICES.GEGNachweisWohnen[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.OfflineXL
|
||||||
|
: Enums.AusweisTyp.Offline
|
||||||
|
]}
|
||||||
|
src={"https://online-energieausweis.org/images/partner/" +
|
||||||
|
partner +
|
||||||
|
"/wohngebaeude.svg"}
|
||||||
alt="GEG-Nachweis-Wohnen"
|
alt="GEG-Nachweis-Wohnen"
|
||||||
variant="Bauvorlage"
|
variant="Bauvorlage"
|
||||||
empfehlung="ja"
|
empfehlung="ja"
|
||||||
cta="Angebot anfragen"
|
cta="Angebot anfragen"
|
||||||
services={[
|
services={[
|
||||||
|
[
|
||||||
["Nachweis fürs Bauamt bei Neubau oder Modernisierung.", true],
|
"Nachweis fürs Bauamt bei Neubau oder Modernisierung.",
|
||||||
["Beinhaltet die Effizienz der Bauteile und Anlagentechnik.", true],
|
true,
|
||||||
["Erstellung des Energieausweises nach Abschluss inklusive.", true],
|
],
|
||||||
["Berechnung und Bilanzierung nach aktueller DIN 18599.", true],
|
[
|
||||||
["Zonierung und Erstellung eines 3D Gebäudemodells.", true],
|
"Beinhaltet die Effizienz der Bauteile und Anlagentechnik.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Erstellung des Energieausweises nach Abschluss inklusive.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Berechnung und Bilanzierung nach aktueller DIN 18599.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Zonierung und Erstellung eines 3D Gebäudemodells.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
]}
|
]}
|
||||||
href_buy={"https://online-energieausweis.org/"+partner+"/angebot-anfragen/geg-nachweis-wohnen-anfragen/"}
|
href_buy1={`https://online-energieausweis.org/${partner}/angebot-anfragen/geg-nachweis-wohnen-anfragen/${standardXL ? "?ausweistyp=standardXL" : ""}`}
|
||||||
href_overview={"https://online-energieausweis.org/"+partner+"/angebot-anfragen/geg-nachweis-wohnen-anfragen/produkt-uebersicht/"}
|
href_buy2={`https://online-energieausweis.org/${partner}/angebot-anfragen/geg-nachweis-wohnen-anfragen/${standardXL ? "?ausweistyp=BeratungXL" : "?ausweistyp=Beratung"}`}
|
||||||
|
|
||||||
></WidgetCardTemplate>
|
></WidgetCardTemplate>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if (anlass != "bitte auswählen") && !isTwoBoxReason && isGewerbe}
|
{#if anlass != "bitte auswählen" && !isTwoBoxReason && isGewerbe}
|
||||||
|
|
||||||
<WidgetCardTemplate
|
<WidgetCardTemplate
|
||||||
name="GEG-Nachweis Gewerbegebäude"
|
name="GEG-Nachweis Gewerbegebäude"
|
||||||
price={PRICES.GEGNachweisGewerbe[Enums.AusweisTyp.Standard]}
|
price={PRICES.GEGNachweisGewerbe[
|
||||||
src={'https://online-energieausweis.org/images/partner/'+partner+'/gewerbegebaeude.svg'}
|
standardXL
|
||||||
|
? Enums.AusweisTyp.standardXL
|
||||||
|
: Enums.AusweisTyp.Standard
|
||||||
|
]}
|
||||||
|
price1={PRICES.GEGNachweisGewerbe[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.BeratungXL
|
||||||
|
: Enums.AusweisTyp.Beratung
|
||||||
|
]}
|
||||||
|
price2={PRICES.GEGNachweisGewerbe[
|
||||||
|
standardXL
|
||||||
|
? Enums.AusweisTyp.OfflineXL
|
||||||
|
: Enums.AusweisTyp.Offline
|
||||||
|
]}
|
||||||
|
src={"https://online-energieausweis.org/images/partner/" +
|
||||||
|
partner +
|
||||||
|
"/gewerbegebaeude.svg"}
|
||||||
alt="GEG-Nachweis-Gewerbe"
|
alt="GEG-Nachweis-Gewerbe"
|
||||||
variant="Bauvorlage"
|
variant="Bauvorlage"
|
||||||
empfehlung="ja"
|
empfehlung="ja"
|
||||||
cta="Angebot anfragen"
|
cta="Angebot anfragen"
|
||||||
services={[
|
services={[
|
||||||
|
[
|
||||||
["Nachweis fürs Bauamt bei Neubau oder Modernisierung.", true],
|
"Nachweis fürs Bauamt bei Neubau oder Modernisierung.",
|
||||||
["Beinhaltet die Effizienz der Bauteile und Anlagentechnik.", true],
|
true,
|
||||||
["Erstellung des Energieausweises nach Abschluss inklusive.", true],
|
],
|
||||||
["Berechnung und Bilanzierung nach aktueller DIN 18599.", true],
|
[
|
||||||
["Mehrzonenmodell inkl. Erstellung eines 3D Gebäudemodells.", true],
|
"Beinhaltet die Effizienz der Bauteile und Anlagentechnik.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Erstellung des Energieausweises nach Abschluss inklusive.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Berechnung und Bilanzierung nach aktueller DIN 18599.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"Mehrzonenmodell inkl. Erstellung eines 3D Gebäudemodells.",
|
||||||
|
true,
|
||||||
|
],
|
||||||
]}
|
]}
|
||||||
href_buy={"https://online-energieausweis.org/"+partner+"/angebot-anfragen/geg-nachweis-gewerbe-anfragen/"}
|
href_buy1={`https://online-energieausweis.org/${partner}/angebot-anfragen/geg-nachweis-gewerbe-anfragen/${standardXL ? "?ausweistyp=standardXL" : ""}`}
|
||||||
href_overview={"https://online-energieausweis.org/"+partner+"/angebot-anfragen/geg-nachweis-gewerbe-anfragen/produkt-uebersicht/"}
|
href_buy2={`https://online-energieausweis.org/${partner}/angebot-anfragen/geg-nachweis-gewerbe-anfragen/${standardXL ? "?ausweistyp=BeratungXL" : "?ausweistyp=Beratung"}`}
|
||||||
></WidgetCardTemplate>
|
></WidgetCardTemplate>
|
||||||
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
#IBC_app {
|
||||||
#IBC_app {
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "immo Sans";
|
font-family: "immo Sans";
|
||||||
src: url('/fonts/Immo-Sans/immoSans-Regular.eot');
|
src: url("/fonts/Immo-Sans/immoSans-Regular.eot");
|
||||||
src: url('/fonts/Immo-Sans/immoSans-Regular.eot?#iefix') format('embedded-opentype'),
|
src:
|
||||||
url('/fonts/Immo-Sans/immoSans-Regular.woff2') format('woff2'),
|
url("/fonts/Immo-Sans/immoSans-Regular.eot?#iefix")
|
||||||
url('/fonts/Immo-Sans/immoSans-Regular.woff') format('woff');
|
format("embedded-opentype"),
|
||||||
|
url("/fonts/Immo-Sans/immoSans-Regular.woff2") format("woff2"),
|
||||||
|
url("/fonts/Immo-Sans/immoSans-Regular.woff") format("woff");
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "immo Sans Bold";
|
|
||||||
src: url('/fonts/Immo-Sans/immoSans-Bold.eot');
|
|
||||||
src: url('/fonts/Immo-Sans/immoSans-Bold.eot?#iefix') format('embedded-opentype'), url('../../Fonts/Immo-Sans/immoSans-Bold.woff2') format('woff2'), url('../../Fonts/Immo-Sans/immoSans-Bold.woff') format('woff');
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Antique Olive Compact bold';
|
font-family: "immo Sans Bold";
|
||||||
|
src: url("/fonts/Immo-Sans/immoSans-Bold.eot");
|
||||||
|
src:
|
||||||
|
url("/fonts/Immo-Sans/immoSans-Bold.eot?#iefix")
|
||||||
|
format("embedded-opentype"),
|
||||||
|
url("../../Fonts/Immo-Sans/immoSans-Bold.woff2") format("woff2"),
|
||||||
|
url("../../Fonts/Immo-Sans/immoSans-Bold.woff") format("woff");
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Antique Olive Compact bold";
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-display:swap;
|
font-display: swap;
|
||||||
src: url("/fonts/Antique Olive Std Compact.woff2") format('woff2');
|
src: url("/fonts/Antique Olive Std Compact.woff2") format("woff2");
|
||||||
}
|
}
|
||||||
|
|
||||||
@apply min-w-[320px] max-w-[1920px] p-[4px]
|
@apply min-w-[320px] max-w-[1920px] p-[4px]
|
||||||
sm:p-[10px];
|
sm:p-[10px];
|
||||||
|
|
||||||
font-family: "immo Sans";
|
font-family: "immo Sans";
|
||||||
select option{
|
select option {
|
||||||
font-family: "immo Sans",sans-serif;}
|
font-family: "immo Sans", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
.firstrow{@apply grid grid-cols-1 gap-x-4 gap-y-2
|
.firstrow {
|
||||||
|
@apply grid grid-cols-1 gap-x-4 gap-y-2
|
||||||
sm:grid-cols-2 sm:gap-x-4 sm:gap-y-2;
|
sm:grid-cols-2 sm:gap-x-4 sm:gap-y-2;
|
||||||
|
|
||||||
.titel{@apply text-black font-bold bg-[#ffcc00] px-2 py-1 rounded-[0.25rem];}
|
.titel {
|
||||||
|
@apply text-black font-bold bg-[#ffcc00] px-2 py-1 rounded-[0.25rem];
|
||||||
|
}
|
||||||
|
|
||||||
.selectfeld{@apply w-full px-2 py-1 min-h-[38px] ring-1 ring-black/15}
|
.selectfeld {
|
||||||
|
@apply w-full px-2 py-1 min-h-[38px] ring-1 ring-black/15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
.secondrow {
|
||||||
|
@apply grid grid-cols-2 gap-x-4 gap-y-2 mt-4
|
||||||
.secondrow{@apply grid grid-cols-2 gap-x-4 gap-y-2 mt-4
|
|
||||||
sm:grid-cols-4 sm:gap-x-4 sm:gap-y-2;
|
sm:grid-cols-4 sm:gap-x-4 sm:gap-y-2;
|
||||||
|
|
||||||
.titel{@apply text-black font-bold bg-[#cccccc] px-2 py-1 rounded-[0.25rem];}
|
.titel {
|
||||||
|
@apply text-black font-bold bg-[#cccccc] px-2 py-1 rounded-[0.25rem];
|
||||||
|
}
|
||||||
|
|
||||||
.selectfeld{@apply w-full px-2 py-1 min-h-[38px] ring-1 ring-black/15}
|
.selectfeld {
|
||||||
|
@apply w-full px-2 py-1 min-h-[38px] ring-1 ring-black/15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
#OEA_input {
|
||||||
|
@apply grid;
|
||||||
|
}
|
||||||
|
|
||||||
#OEA_input{@apply grid}
|
.thirdrow {
|
||||||
|
@apply grid grid-cols-1 gap-x-4 gap-y-2 col-start-1
|
||||||
.thirdrow{@apply grid grid-cols-1 gap-x-4 gap-y-2 col-start-1
|
|
||||||
md:grid-cols-4 md:gap-x-4 md:gap-y-2;
|
md:grid-cols-4 md:gap-x-4 md:gap-y-2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,104 +1,140 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade } from "svelte/transition";
|
import { fade } from "svelte/transition";
|
||||||
export let price: number;
|
export let price: number;
|
||||||
|
|
||||||
|
export let price1: number;
|
||||||
|
export let price2: number;
|
||||||
|
|
||||||
export let name: string;
|
export let name: string;
|
||||||
export let variant: string;
|
export let variant: string;
|
||||||
export let services: [string, boolean][];
|
export let services: [string, boolean][];
|
||||||
export let href_buy: string;
|
export let href_buy1: string;
|
||||||
export let href_overview: string;
|
export let href_buy2: string;
|
||||||
|
export let href_buy3: string = "";
|
||||||
|
|
||||||
export let src: string;
|
export let src: string;
|
||||||
export let alt: string;
|
export let alt: string;
|
||||||
export let empfehlung: string;
|
export let empfehlung: string;
|
||||||
export let cta: string;
|
export let cta: string;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div class="produktbox" transition:fade={{ duration: 0 }}>
|
||||||
class="produktbox"
|
{#if empfehlung === "ja"}
|
||||||
transition:fade={{ duration: 0 }}
|
<div class="empfehlung" aria-label="Empfohlenes Produkt">
|
||||||
>
|
Empfehlung
|
||||||
|
</div>
|
||||||
{#if empfehlung === "ja"}
|
{/if}
|
||||||
<div class="empfehlung" aria-label="Empfohlenes Produkt">Empfehlung</div>
|
|
||||||
{/if}
|
|
||||||
<h2 class="titel sm:mb-2">{name}</h2>
|
<h2 class="titel sm:mb-2">{name}</h2>
|
||||||
|
|
||||||
|
|
||||||
<div class="sumCent">
|
<div class="sumCent">
|
||||||
<div class="variante">{variant}</div>
|
<div class="variante">{variant}</div>
|
||||||
<img
|
<img class="image" {src} {alt} />
|
||||||
class="image"
|
|
||||||
{src}
|
|
||||||
{alt}
|
|
||||||
/>
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<p class="price">
|
<p class="price">
|
||||||
ab {price} €
|
ab {price} €
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="sumCent buttoncols">
|
<hr class="col-span-2 w-full md:w-[50%] md:m-auto bg-[#ffcc00] h-[2px]" />
|
||||||
<a
|
|
||||||
href={href_buy}
|
|
||||||
class="buttoncol"
|
|
||||||
aria-label="Jetzt {name} kaufen"
|
|
||||||
target="_blank"
|
|
||||||
>{cta}
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href={href_overview}
|
|
||||||
class="buttoncol"
|
|
||||||
aria-label="{name} Produkt-Übersicht"
|
|
||||||
target="_blank"
|
|
||||||
>Produkt-Übersicht</a
|
|
||||||
>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="sumRows forServices">
|
<div class="sumRows forServices">
|
||||||
|
|
||||||
{#each services as [service, check]}
|
{#each services as [service, check]}
|
||||||
<div class="services">
|
<div class="services">
|
||||||
<span>{@html service}</span>
|
<span>{@html service}</span>
|
||||||
<span class={check ? "check" : "check-no"}>{check ? "✔" : "✘"}</span>
|
<span class={check ? "check" : "check-no"}
|
||||||
|
>{check ? "✔" : "✘"}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="col-span-2 w-full md:w-[50%] md:m-auto bg-[#ffcc00] h-[2px]" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="sumCent buttoncols"
|
||||||
|
class:md:grid-cols-3={href_buy3}
|
||||||
|
class:md:grid-cols-2={!href_buy3}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={href_buy1}
|
||||||
|
class="buttoncol"
|
||||||
|
aria-label="Jetzt {name} kaufen"
|
||||||
|
target="_blank"
|
||||||
|
>mach selbst (<span class="inside-price">{price}</span> €)
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={href_buy2}
|
||||||
|
class="buttoncol"
|
||||||
|
aria-label="{name} Produkt-Übersicht"
|
||||||
|
target="_blank"
|
||||||
|
>wir helfen (<span class="inside-price">{price1}</span> €)
|
||||||
|
</a>
|
||||||
|
|
||||||
|
{#if href_buy3}
|
||||||
|
<a
|
||||||
|
href={href_buy3}
|
||||||
|
class="buttoncol"
|
||||||
|
aria-label="{name} Produkt-Übersicht"
|
||||||
|
target="_blank"
|
||||||
|
>wir machen (<span class="inside-price">{price2}</span> €)
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
.produktbox {
|
||||||
.produktbox{@apply grid grid-cols-subgrid col-span-2 grid-rows-subgrid row-span-3 md:row-span-12 bg-black/5 rounded-lg
|
@apply grid grid-cols-subgrid col-span-2 grid-rows-subgrid row-span-3 md:row-span-12 bg-black/5 rounded-lg
|
||||||
px-2 py-2 mt-5;
|
px-2 py-2 mt-5;
|
||||||
box-shadow:2px 2px 8px rgba(0,0,0,0.25);
|
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.25);
|
||||||
|
|
||||||
.sumCent{@apply justify-self-center col-span-2}
|
.sumCent {
|
||||||
.sumRows{@apply hidden sm:grid grid-rows-subgrid row-span-5 items-center}
|
@apply justify-self-center col-span-2;
|
||||||
.forServices{@apply grid-rows-subgrid row-span-5 items-center col-span-2 justify-center px-6}
|
}
|
||||||
|
.sumRows {
|
||||||
|
@apply hidden sm:grid grid-rows-subgrid row-span-5 items-center;
|
||||||
|
}
|
||||||
|
.forServices {
|
||||||
|
@apply grid-rows-subgrid row-span-5 items-center col-span-2 justify-center px-6;
|
||||||
|
}
|
||||||
|
|
||||||
.image{@apply w-[75%] mx-auto
|
.image {
|
||||||
md:w-[75%] md:pl-0}
|
@apply w-[75%] mx-auto
|
||||||
|
md:w-[75%] md:pl-0;
|
||||||
|
}
|
||||||
|
|
||||||
.buttoncols{@apply grid grid-cols-1 gap-x-4 w-full mb-4
|
.buttoncols {
|
||||||
md:grid-cols-2 md:w-[auto]}
|
@apply grid grid-cols-1 gap-x-4 w-full my-4
|
||||||
|
md:grid-cols-3 md:w-[auto];
|
||||||
|
}
|
||||||
|
|
||||||
.buttoncol{@apply mt-2 md:mt-0 text-center text-black bg-[#ffcc00] rounded-md px-3 py-1 no-underline
|
.buttoncol {
|
||||||
hover:bg-[#222222] hover:text-white}
|
@apply mt-2 md:mt-0 text-center text-black bg-[#ffcc00] rounded-md px-3 py-1 no-underline
|
||||||
|
hover:bg-[#222222] hover:text-white;
|
||||||
|
}
|
||||||
|
.inside-price {
|
||||||
|
@apply font-bold;
|
||||||
|
}
|
||||||
|
|
||||||
.price{@apply tracking-tighter text-[2rem] text-[#222222] pl-12 m-0 -mt-7 text-nowrap text-left;
|
.price {
|
||||||
font-family: "Antique Olive Compact bold";}
|
@apply tracking-tighter text-[2rem] text-[#222222] pl-12 m-0 -mt-7 text-nowrap text-left;
|
||||||
|
font-family: "Antique Olive Compact bold";
|
||||||
|
}
|
||||||
|
|
||||||
.titel {@apply col-span-2 text-center [font-size:_clamp(20px,2.5vw,28px)]}
|
.titel {
|
||||||
.empfehlung{@apply -mt-4 absolute justify-self-end rounded-md bg-red-700 text-white w-fit h-fit px-2 py-1 rotate-1 text-[0.65rem] ring-4 ring-white mr-6}
|
@apply col-span-2 text-center [font-size:_clamp(20px,2.5vw,28px)];
|
||||||
|
}
|
||||||
|
.empfehlung {
|
||||||
|
@apply -mt-4 absolute justify-self-end rounded-md bg-red-700 text-white w-fit h-fit px-2 py-1 rotate-1 text-[0.65rem] ring-4 ring-white mr-6;
|
||||||
|
}
|
||||||
.variante {
|
.variante {
|
||||||
@apply w-fit italic col-span-2 -mt-2 -mb-4 text-[1rem] text-[#222222] justify-self-start ring-2 ring-[#ffcc00] rounded-md pl-[4px] pr-[6px] py-[0px];
|
@apply w-fit italic col-span-2 -mt-2 -mb-4 text-[1rem] text-[#222222] justify-self-start ring-2 ring-[#ffcc00] rounded-md pl-[4px] pr-[6px] py-[0px];
|
||||||
}
|
}
|
||||||
|
|
||||||
.services {
|
.services {
|
||||||
@apply hidden text-start py-1 md:grid grid-rows-subgrid row-span-1 items-center md:grid-cols-[1fr_50px]
|
@apply hidden text-start py-1 md:grid grid-rows-subgrid row-span-1 items-center md:grid-cols-[1fr_50px];
|
||||||
}
|
}
|
||||||
.services:not(:last-child) {
|
.services:not(:last-child) {
|
||||||
@apply border-b-[1px] border-gray-200;
|
@apply border-b-[1px] border-gray-200;
|
||||||
@@ -109,7 +145,5 @@ hover:bg-[#222222] hover:text-white}
|
|||||||
.check-no {
|
.check-no {
|
||||||
@apply justify-self-end self-center font-bold text-red-700;
|
@apply justify-self-end self-center font-bold text-red-700;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ export const BedarfsausweisWohnenSchema = z.object({
|
|||||||
volumen: z.number().nullish(),
|
volumen: z.number().nullish(),
|
||||||
dicht: z.boolean().nullish(),
|
dicht: z.boolean().nullish(),
|
||||||
fenster_flaeche_1: z.number().nullish(),
|
fenster_flaeche_1: z.number().nullish(),
|
||||||
fenster_art_1: z.string().nullish(),
|
fenster_art_1: z.number().nullish(),
|
||||||
fenster_flaeche_2: z.number().nullish(),
|
fenster_flaeche_2: z.number().nullish(),
|
||||||
fenster_art_2: z.string().nullish(),
|
fenster_art_2: z.number().nullish(),
|
||||||
dachfenster_flaeche: z.number().nullish(),
|
dachfenster_flaeche: z.number().nullish(),
|
||||||
dachfenster_art: z.string().nullish(),
|
dachfenster_art: z.number().nullish(),
|
||||||
haustuer_flaeche: z.number().nullish(),
|
haustuer_flaeche: z.number().nullish(),
|
||||||
haustuer_art: z.string().nullish(),
|
haustuer_art: z.number().nullish(),
|
||||||
dach_bauart: z.string().nullish(),
|
dach_bauart: z.string().nullish(),
|
||||||
decke_bauart: z.string().nullish(),
|
decke_bauart: z.string().nullish(),
|
||||||
dach_daemmung: z.string().nullish(),
|
dach_daemmung: z.string().nullish(),
|
||||||
|
|||||||
29
src/lib/auth/time-based-hash.ts
Normal file
29
src/lib/auth/time-based-hash.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
import { uptime } from "os"
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generiert einen zeitbasierten Hash der sich alle 15 Minuten ändert und an die Uptime des servers gekoppelt ist.
|
||||||
|
* @param email - Die E-Mail-Adresse des Benutzers, die als Teil des Hashes verwendet wird.
|
||||||
|
* @param time - Die Zeit in Millisekunden, die seit dem Start des Servers vergangen ist (Standard ist die Uptime des Servers).
|
||||||
|
* @param length - Die Länge des zurückgegebenen Hashes (Standard ist 6 Zeichen).
|
||||||
|
* @returns Ein zeitbasierter Hash, der sich alle 15 Minuten ändert und auf der E-Mail-Adresse basiert.
|
||||||
|
*/
|
||||||
|
export function createTimeBasedHash(email: string, time: number = uptime(), length: number = 6): string {
|
||||||
|
const now = Date.now();
|
||||||
|
const elapsed = now - time;
|
||||||
|
const window = Math.floor(elapsed / (15 * 60 * 1000)); // 15 minute windows
|
||||||
|
|
||||||
|
const data = `${email}:${window}`;
|
||||||
|
|
||||||
|
// Use a cryptographic hash (you can also use HMAC with a secret if you want)
|
||||||
|
const hash = crypto.createHash('sha256').update(data).digest();
|
||||||
|
|
||||||
|
// Convert part of the hash to an integer
|
||||||
|
const int = hash.readUInt32BE(0); // take first 4 bytes
|
||||||
|
|
||||||
|
// Modulo to get 6 digits
|
||||||
|
const pin = (int % 1000000).toString().padStart(6, '0');
|
||||||
|
|
||||||
|
return pin;
|
||||||
|
}
|
||||||
41
src/lib/server/mail/code.ts
Normal file
41
src/lib/server/mail/code.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { transport } from "#lib/mail.js";
|
||||||
|
import {
|
||||||
|
Benutzer,
|
||||||
|
} from "#lib/client/prisma.js";
|
||||||
|
import { createTimeBasedHash } from "#lib/auth/time-based-hash.js";
|
||||||
|
|
||||||
|
export async function sendVerificationCodeMail(
|
||||||
|
user: Benutzer
|
||||||
|
) {
|
||||||
|
const code = createTimeBasedHash(user.email)
|
||||||
|
|
||||||
|
await transport.sendMail({
|
||||||
|
from: `"IBCornelsen" <info@online-energieausweis.org>`,
|
||||||
|
to: user.email,
|
||||||
|
subject: `Ihre Registrierung bei IBCornelsen`,
|
||||||
|
bcc: "info@online-energieausweis.org",
|
||||||
|
html: `<p>Sehr geehrte*r ${user.vorname} ${user.name},</p>
|
||||||
|
<p>Um Ihre Registrierung abzuschließen, geben Sie folgenden Bestätigungscode auf der Website ein, um Ihre E-Mail-Adresse zu bestätigen:<br><br>
|
||||||
|
<b>${code}</b>
|
||||||
|
</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>`
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
} from "#lib/client/prisma.js";
|
} from "#lib/client/prisma.js";
|
||||||
import { encodeToken } from "#lib/auth/token.js";
|
import { encodeToken } from "#lib/auth/token.js";
|
||||||
import { TokenType } from "#lib/auth/types.js";
|
import { TokenType } from "#lib/auth/types.js";
|
||||||
|
import { createTimeBasedHash } from "#lib/auth/time-based-hash.js";
|
||||||
|
|
||||||
export async function sendRegisterMail(
|
export async function sendRegisterMail(
|
||||||
user: Benutzer
|
user: Benutzer
|
||||||
@@ -12,9 +13,11 @@ export async function sendRegisterMail(
|
|||||||
const verificationJwt = encodeToken({
|
const verificationJwt = encodeToken({
|
||||||
typ: TokenType.Verify,
|
typ: TokenType.Verify,
|
||||||
exp: Date.now() + (15 * 60 * 1000),
|
exp: Date.now() + (15 * 60 * 1000),
|
||||||
uid: user.uid
|
id: user.id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const code = createTimeBasedHash(user.email)
|
||||||
|
|
||||||
await transport.sendMail({
|
await transport.sendMail({
|
||||||
from: `"IBCornelsen" <info@online-energieausweis.org>`,
|
from: `"IBCornelsen" <info@online-energieausweis.org>`,
|
||||||
to: user.email,
|
to: user.email,
|
||||||
@@ -22,10 +25,11 @@ export async function sendRegisterMail(
|
|||||||
bcc: "info@online-energieausweis.org",
|
bcc: "info@online-energieausweis.org",
|
||||||
html: `<p>Sehr geehrte*r ${user.vorname} ${user.name},</p>
|
html: `<p>Sehr geehrte*r ${user.vorname} ${user.name},</p>
|
||||||
<p>vielen Dank für Ihre Registrierung bei IBCornelsen. Ihr Benutzerkonto wurde erfolgreich erstellt.<br><br>
|
<p>vielen Dank für Ihre Registrierung bei IBCornelsen. Ihr Benutzerkonto wurde erfolgreich erstellt.<br><br>
|
||||||
|
|
||||||
Um Ihre Registrierung abzuschließen, klicken Sie bitte auf den folgenden Link, um Ihre E-Mail-Adresse zu bestätigen:<br><br>
|
Um Ihre Registrierung abzuschließen, klicken Sie bitte auf den folgenden Link, um Ihre E-Mail-Adresse zu bestätigen:<br><br>
|
||||||
|
<a href="${BASE_URI}/auth/verify?t=${verificationJwt}">E-Mail-Adresse bestätigen</a><br><br>
|
||||||
<a href="${BASE_URI}/auth/verify?t=${verificationJwt}">E-Mail-Adresse bestätigen</a><br></p>
|
Oder geben Sie folgenden Bestätigungscode auf der Website ein:<br>
|
||||||
|
<b>${code}</b>
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Mit freundlichen Grüßen,
|
Mit freundlichen Grüßen,
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -46,9 +46,8 @@
|
|||||||
export let rechnung: RechnungClient | null = null;
|
export let rechnung: RechnungClient | null = null;
|
||||||
export let ausweisart: Enums.Ausweisart;
|
export let ausweisart: Enums.Ausweisart;
|
||||||
export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal;
|
export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal;
|
||||||
|
|
||||||
export let partner_code: string;
|
export let partner_code: string;
|
||||||
|
export let nurRechnungsadresseUpdate: Boolean | null = false;
|
||||||
|
|
||||||
let email: string, vorname: string, name: string, empfaenger: string, strasse: string, plz: string, ort: string, zusatzzeile: string, telefon: string;
|
let email: string, vorname: string, name: string, empfaenger: string, strasse: string, plz: string, ort: string, zusatzzeile: string, telefon: string;
|
||||||
|
|
||||||
@@ -67,9 +66,18 @@
|
|||||||
vorname = impersonatedUser.vorname || "";
|
vorname = impersonatedUser.vorname || "";
|
||||||
name = impersonatedUser.name || "";
|
name = impersonatedUser.name || "";
|
||||||
telefon = impersonatedUser.telefon || "";
|
telefon = impersonatedUser.telefon || "";
|
||||||
|
email = impersonatedUser.email || "";
|
||||||
|
if (rechnung){
|
||||||
|
empfaenger = rechnung?.empfaenger || "";
|
||||||
|
strasse = rechnung?.strasse || "";
|
||||||
|
plz = rechnung?.plz || "";
|
||||||
|
ort = rechnung?.ort || "";
|
||||||
|
zusatzzeile = rechnung?.zusatzzeile || "";
|
||||||
|
email = rechnung?.email || "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let abweichende_versand_adresse = JSON.parse(localStorage.getItem("kundendaten.abweichende_versand_adresse") || "false")
|
let abweichende_versand_adresse = rechnung?.abweichende_versand_adresse ?? JSON.parse(localStorage.getItem("kundendaten.abweichende_versand_adresse") || "false")
|
||||||
|
|
||||||
let versand_email: string | undefined,
|
let versand_email: string | undefined,
|
||||||
versand_zusatzzeile: string | undefined,
|
versand_zusatzzeile: string | undefined,
|
||||||
@@ -77,16 +85,13 @@
|
|||||||
versand_strasse: string | undefined,
|
versand_strasse: string | undefined,
|
||||||
versand_plz: string | undefined,
|
versand_plz: string | undefined,
|
||||||
versand_ort: string | undefined;
|
versand_ort: string | undefined;
|
||||||
$: {
|
|
||||||
if (!abweichende_versand_adresse) {
|
versand_email = "";//Todo Datenbankfeld fehlt noch
|
||||||
versand_email = email
|
versand_zusatzzeile = rechnung?.versand_zusatzzeile ?? zusatzzeile;
|
||||||
versand_zusatzzeile = zusatzzeile
|
versand_empfaenger = rechnung?.versand_empfaenger ?? empfaenger;
|
||||||
versand_empfaenger = empfaenger
|
versand_strasse = rechnung?.versand_strasse ?? strasse;
|
||||||
versand_strasse = strasse
|
versand_plz = rechnung?.versand_plz ?? plz;
|
||||||
versand_plz = plz
|
versand_ort = rechnung?.versand_ort ?? ort;
|
||||||
versand_ort = ort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
// Wir speichern jede Änderung an den Kundendaten im localStorage ab.
|
// Wir speichern jede Änderung an den Kundendaten im localStorage ab.
|
||||||
@@ -207,6 +212,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const merged_versand_empfaenger = versand_empfaenger || empfaenger;
|
||||||
|
const merged_versand_strasse = versand_strasse || strasse;
|
||||||
|
const merged_versand_plz = versand_plz || plz;
|
||||||
|
const merged_versand_ort = versand_ort || ort;
|
||||||
|
const merged_versand_zusatzzeile = versand_zusatzzeile || zusatzzeile;
|
||||||
|
|
||||||
const { id } = await api.rechnung.anfordern.PUT.fetch(
|
const { id } = await api.rechnung.anfordern.PUT.fetch(
|
||||||
{
|
{
|
||||||
email: email,
|
email: email,
|
||||||
@@ -214,10 +225,11 @@
|
|||||||
strasse: strasse,
|
strasse: strasse,
|
||||||
plz: plz,
|
plz: plz,
|
||||||
ort: ort,
|
ort: ort,
|
||||||
versand_empfaenger: versand_empfaenger,
|
versand_empfaenger: merged_versand_empfaenger,
|
||||||
versand_strasse: versand_strasse,
|
versand_strasse: merged_versand_strasse,
|
||||||
versand_plz: versand_plz,
|
versand_plz: merged_versand_plz,
|
||||||
versand_ort: versand_ort,
|
versand_ort: merged_versand_ort,
|
||||||
|
versand_zusatzzeile: merged_versand_zusatzzeile,
|
||||||
telefon: telefon,
|
telefon: telefon,
|
||||||
nachweis_id: result.nachweis_id
|
nachweis_id: result.nachweis_id
|
||||||
},
|
},
|
||||||
@@ -274,6 +286,45 @@
|
|||||||
|
|
||||||
resultUser = await benutzerSpeichern(benutzerObjekt);
|
resultUser = await benutzerSpeichern(benutzerObjekt);
|
||||||
|
|
||||||
|
|
||||||
|
let id: string, checkout_url: string | undefined;
|
||||||
|
|
||||||
|
if (rechnung) {
|
||||||
|
const merged_versand_empfaenger = versand_empfaenger || empfaenger;
|
||||||
|
const merged_versand_strasse = versand_strasse || strasse;
|
||||||
|
const merged_versand_plz = versand_plz || plz;
|
||||||
|
const merged_versand_ort = versand_ort || ort;
|
||||||
|
const merged_versand_zusatzzeile = versand_zusatzzeile || zusatzzeile;
|
||||||
|
|
||||||
|
const result = await api.rechnung._id.PATCH.fetch({
|
||||||
|
bezahlmethode: aktiveBezahlmethode,
|
||||||
|
abweichende_versand_adresse: abweichende_versand_adresse,
|
||||||
|
empfaenger,
|
||||||
|
strasse,
|
||||||
|
plz,
|
||||||
|
ort,
|
||||||
|
telefon,
|
||||||
|
email,
|
||||||
|
zusatzzeile,
|
||||||
|
versand_empfaenger: merged_versand_empfaenger,
|
||||||
|
versand_strasse: merged_versand_strasse,
|
||||||
|
versand_plz: merged_versand_plz,
|
||||||
|
versand_ort: merged_versand_ort,
|
||||||
|
versand_zusatzzeile: merged_versand_zusatzzeile
|
||||||
|
}, {
|
||||||
|
params: {
|
||||||
|
id: rechnung.id
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
id = result.id;
|
||||||
|
checkout_url = result.checkout_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
addNotification({
|
addNotification({
|
||||||
dismissable: true,
|
dismissable: true,
|
||||||
@@ -361,6 +412,12 @@
|
|||||||
try {
|
try {
|
||||||
let id: string, checkout_url: string | undefined;
|
let id: string, checkout_url: string | undefined;
|
||||||
|
|
||||||
|
const merged_versand_empfaenger = versand_empfaenger || empfaenger;
|
||||||
|
const merged_versand_strasse = versand_strasse || strasse;
|
||||||
|
const merged_versand_plz = versand_plz || plz;
|
||||||
|
const merged_versand_ort = versand_ort || ort;
|
||||||
|
const merged_versand_zusatzzeile = versand_zusatzzeile || zusatzzeile;
|
||||||
|
|
||||||
if (rechnung) {
|
if (rechnung) {
|
||||||
const result = await api.rechnung._id.PATCH.fetch({
|
const result = await api.rechnung._id.PATCH.fetch({
|
||||||
bezahlmethode: aktiveBezahlmethode,
|
bezahlmethode: aktiveBezahlmethode,
|
||||||
@@ -369,12 +426,13 @@
|
|||||||
strasse: strasse,
|
strasse: strasse,
|
||||||
plz: plz,
|
plz: plz,
|
||||||
ort: ort,
|
ort: ort,
|
||||||
versand_empfaenger: versand_empfaenger,
|
|
||||||
versand_strasse: versand_strasse,
|
|
||||||
versand_plz: versand_plz,
|
|
||||||
versand_ort: versand_ort,
|
|
||||||
telefon: telefon,
|
telefon: telefon,
|
||||||
versand_zusatzzeile: versand_zusatzzeile
|
zusatzzeile: zusatzzeile,
|
||||||
|
versand_empfaenger: merged_versand_empfaenger,
|
||||||
|
versand_strasse: merged_versand_strasse,
|
||||||
|
versand_plz: merged_versand_plz,
|
||||||
|
versand_ort: merged_versand_ort,
|
||||||
|
versand_zusatzzeile: merged_versand_zusatzzeile
|
||||||
}, {
|
}, {
|
||||||
params: {
|
params: {
|
||||||
id: rechnung.id
|
id: rechnung.id
|
||||||
@@ -399,13 +457,16 @@
|
|||||||
strasse: strasse,
|
strasse: strasse,
|
||||||
plz: plz,
|
plz: plz,
|
||||||
ort: ort,
|
ort: ort,
|
||||||
versand_empfaenger: versand_empfaenger,
|
zusatzzeile: zusatzzeile,
|
||||||
versand_strasse: versand_strasse,
|
versand_empfaenger: merged_versand_empfaenger,
|
||||||
versand_plz: versand_plz,
|
versand_strasse: merged_versand_strasse,
|
||||||
versand_ort: versand_ort,
|
versand_plz: merged_versand_plz,
|
||||||
|
versand_ort: merged_versand_ort,
|
||||||
|
versand_zusatzzeile: merged_versand_zusatzzeile,
|
||||||
telefon: telefon,
|
telefon: telefon,
|
||||||
ausweis_id: ausweis.id,
|
ausweis_id: ausweis.id,
|
||||||
partner_code
|
partner_code,
|
||||||
|
abweichende_versand_adresse: abweichende_versand_adresse
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -445,6 +506,7 @@
|
|||||||
let form: HTMLFormElement;
|
let form: HTMLFormElement;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if !nurRechnungsadresseUpdate}
|
||||||
<div
|
<div
|
||||||
id="skala"
|
id="skala"
|
||||||
class="bg-white grid grid-cols-1 gap-x-8 gap-y-4 px-0 sm:p-4
|
class="bg-white grid grid-cols-1 gap-x-8 gap-y-4 px-0 sm:p-4
|
||||||
@@ -475,7 +537,7 @@
|
|||||||
<Progressbar active={1} {ausweisart} ausweistyp={ausweis.ausweistyp} anliegen={"Energieausweis erstellen"} />
|
<Progressbar active={1} {ausweisart} ausweistyp={ausweis.ausweistyp} anliegen={"Energieausweis erstellen"} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<form id="formInput-2" bind:this={form}>
|
<form id="formInput-2" bind:this={form}>
|
||||||
<div id="formular-box" class="formular-boxen ring-0">
|
<div id="formular-box" class="formular-boxen ring-0">
|
||||||
@@ -743,7 +805,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
|
|||||||
<input
|
<input
|
||||||
name="versand_ort"
|
name="versand_ort"
|
||||||
type="text"
|
type="text"
|
||||||
readonly
|
|
||||||
required
|
required
|
||||||
bind:value={versand_ort}
|
bind:value={versand_ort}
|
||||||
/>
|
/>
|
||||||
@@ -780,7 +841,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- E-mail -->
|
<!-- E-mail -->
|
||||||
|
<!-- Versand Email wird derzeit nicht verwendet
|
||||||
<div class="input-standard order-12 md:order-12 xl:order-12">
|
<div class="input-standard order-12 md:order-12 xl:order-12">
|
||||||
<InputLabel title="E-mail *"></InputLabel>
|
<InputLabel title="E-mail *"></InputLabel>
|
||||||
|
|
||||||
@@ -797,7 +858,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
|
|||||||
</HelpLabel>
|
</HelpLabel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
<!-- Telefon
|
<!-- Telefon
|
||||||
|
|
||||||
<div class="input-standard order-[13] md:order-[13] xl:order-[13]">
|
<div class="input-standard order-[13] md:order-[13] xl:order-[13]">
|
||||||
@@ -821,7 +882,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
|
|||||||
</Bereich
|
</Bereich
|
||||||
>
|
>
|
||||||
|
|
||||||
{#if !gegAnfrage}
|
{#if !gegAnfrage && !nurRechnungsadresseUpdate}
|
||||||
<Bereich bereich="3" title="Bezahlmethode">
|
<Bereich bereich="3" title="Bezahlmethode">
|
||||||
<div
|
<div
|
||||||
id="bezahlung"
|
id="bezahlung"
|
||||||
@@ -932,7 +993,7 @@ grid-cols-3 sm:grid-cols-5 justify-around justify-items-center items-center"
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<!-- Falls wir es mit einem Ausweis zu tun haben und der Nutzer keine Hilfe bestellt hat dann zeigen wir eine Box mit sachen an die vielleicht unklar sind. -->
|
<!-- Falls wir es mit einem Ausweis zu tun haben und der Nutzer keine Hilfe bestellt hat dann zeigen wir eine Box mit sachen an die vielleicht unklar sind. -->
|
||||||
{#if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) && (ausweis.ausweistyp === Enums.AusweisTyp.Standard || ausweis.ausweistyp === Enums.AusweisTyp.standardXL)}
|
{#if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) && (ausweis.ausweistyp === Enums.AusweisTyp.Standard || ausweis.ausweistyp === Enums.AusweisTyp.standardXL) && (!nurRechnungsadresseUpdate)}
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-1 gap-x-6 my-6">
|
<div class="grid grid-cols-1 sm:grid-cols-1 gap-x-6 my-6">
|
||||||
<div class="pruefpunkte bereich-box bg-white">
|
<div class="pruefpunkte bereich-box bg-white">
|
||||||
<h3>Bitte untenstehende Punkte bestätigen. Bitte gehen Sie gegebenenfalls zurück zum Formular und überprüfen bzw. korrigieren Ihre Eingaben.</h3>
|
<h3>Bitte untenstehende Punkte bestätigen. Bitte gehen Sie gegebenenfalls zurück zum Formular und überprüfen bzw. korrigieren Ihre Eingaben.</h3>
|
||||||
@@ -1115,6 +1176,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
|
|||||||
|
|
||||||
<button class="order-2 button" type="button" on:click={() => speichern()}>Speichern</button>
|
<button class="order-2 button" type="button" on:click={() => speichern()}>Speichern</button>
|
||||||
|
|
||||||
|
{#if !nurRechnungsadresseUpdate}
|
||||||
{#if rechnung && rechnung.status === "paid"}
|
{#if rechnung && rechnung.status === "paid"}
|
||||||
<!-- Von einer GEG Anfrage sollte man sowieso nicht noch mal auf die Kundendaten Seite gelangen, also brauchen wir das hier nicht. -->
|
<!-- Von einer GEG Anfrage sollte man sowieso nicht noch mal auf die Kundendaten Seite gelangen, also brauchen wir das hier nicht. -->
|
||||||
<button
|
<button
|
||||||
@@ -1140,6 +1202,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
|
|||||||
>
|
>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if user.rolle === Enums.BenutzerRolle.ADMIN}
|
{#if user.rolle === Enums.BenutzerRolle.ADMIN}
|
||||||
<button class="button text-sm" on:click={() => {
|
<button class="button text-sm" on:click={() => {
|
||||||
|
|||||||
@@ -13,6 +13,10 @@
|
|||||||
|
|
||||||
export let redirect: string | null = null;
|
export let redirect: string | null = null;
|
||||||
|
|
||||||
|
function handleInput(event) {
|
||||||
|
email = event.target.value.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
async function login(e: SubmitEvent) {
|
async function login(e: SubmitEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (passwort.length < 8) {
|
if (passwort.length < 8) {
|
||||||
@@ -26,7 +30,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { uid } = await api.user.PUT.fetch({
|
await api.user.PUT.fetch({
|
||||||
email,
|
email,
|
||||||
passwort,
|
passwort,
|
||||||
vorname,
|
vorname,
|
||||||
@@ -38,7 +42,7 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.href = "/auth/login";
|
window.location.href = `/auth/code?email=${email}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
errorHidden = false;
|
errorHidden = false;
|
||||||
}
|
}
|
||||||
@@ -83,6 +87,7 @@
|
|||||||
name="email"
|
name="email"
|
||||||
class="input input-bordered text-base text-base-content font-medium"
|
class="input input-bordered text-base text-base-content font-medium"
|
||||||
bind:value={email}
|
bind:value={email}
|
||||||
|
on:input={handleInput}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
89
src/modules/auth/CodeModule.svelte
Normal file
89
src/modules/auth/CodeModule.svelte
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { addNotification } from "#components/Notifications/shared.js";
|
||||||
|
import { CrossCircled } from "radix-svelte-icons";
|
||||||
|
import { fade } from "svelte/transition";
|
||||||
|
import { api } from "astro-typesafe-api/client";
|
||||||
|
import NotificationWrapper from "#components/Notifications/NotificationWrapper.svelte";
|
||||||
|
|
||||||
|
export let redirect: string | null = null;
|
||||||
|
export let email: string;
|
||||||
|
|
||||||
|
function verify(e: SubmitEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
const code = numbers.join("");
|
||||||
|
|
||||||
|
if (code.length !== 6) {
|
||||||
|
addNotification({
|
||||||
|
message: "Bitte geben Sie einen gültigen Verifizierungscode ein.",
|
||||||
|
dismissable: true,
|
||||||
|
timeout: 3000,
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api.auth["verification-code"].POST.fetch({ code, email }).then(() => {
|
||||||
|
if (redirect) {
|
||||||
|
window.location.href = redirect;
|
||||||
|
} else {
|
||||||
|
window.location.href = "/";
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
errorHidden = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
function codeErneutAnfordern() {
|
||||||
|
api.auth["verification-code"].GET.fetch(null, {
|
||||||
|
headers: {
|
||||||
|
"Authorization": "Bearer"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let numbers = new Array(6).fill("");
|
||||||
|
|
||||||
|
let errorHidden = true;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="mx-auto w-1/3 bg-base-200 p-8 border border-base-300 rounded-lg">
|
||||||
|
<h1 class="text-3xl mb-4">Verifizierung</h1>
|
||||||
|
<p>Wir haben ihnen einen Verifizierungscode per Email geschickt, bitte geben sie diesen ein um ihre Registrierung fertigzustellen.</p>
|
||||||
|
<form on:submit={verify}>
|
||||||
|
<div class="flex flex-row gap-4 w-full justify-center my-12">
|
||||||
|
{#each { length: 6 } as _, i}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered text-4xl text-base-content font-medium w-12 text-center"
|
||||||
|
bind:value={numbers[i]}
|
||||||
|
maxlength="1"
|
||||||
|
on:input={function(e) {
|
||||||
|
if (i !== 5) {
|
||||||
|
e.target.nextSibling.focus()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<button type="submit" class="button"
|
||||||
|
>Abschicken</button
|
||||||
|
>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <button type="button" on:click={codeErneutAnfordern} class="button"
|
||||||
|
>Code erneut anfordern</button
|
||||||
|
> -->
|
||||||
|
</div>
|
||||||
|
{#if !errorHidden}
|
||||||
|
<div class="flex flex-row gap-4 mt-8" in:fade out:fade={{delay: 400}}>
|
||||||
|
<CrossCircled size={24} />
|
||||||
|
<span class="font-semibold"> Da ist wohl etwas schiefgelaufen. Der eingegebene Verifizierungscode ist ungültig.</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</form>
|
||||||
|
<NotificationWrapper></NotificationWrapper>
|
||||||
|
</div>
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
---
|
---
|
||||||
import AusweisLayout from "#layouts/AusweisLayoutDatenPartner.astro";
|
import AusweisLayout from "#layouts/AusweisLayoutDatenPartner.astro";
|
||||||
import VerbrauchsausweisWohnenModule from "#modules/VerbrauchsausweisWohnen/VerbrauchsausweisWohnenModule.svelte";
|
|
||||||
import { AufnahmeClient, BildClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
|
||||||
import { Aufnahme, BedarfsausweisGewerbe, Bild, Enums, Objekt, Unterlage, VerbrauchsausweisWohnen } from "#lib/server/prisma";
|
import { Aufnahme, BedarfsausweisGewerbe, Bild, Enums, Objekt, Unterlage, VerbrauchsausweisWohnen } from "#lib/server/prisma";
|
||||||
import { getAufnahme, getBedarfsausweisGewerbe, getBilder, getObjekt, getUnterlagen, getVerbrauchsausweisWohnen } from "#lib/server/db";
|
import { getAufnahme, getBedarfsausweisGewerbe, getBilder, getObjekt, getUnterlagen, getVerbrauchsausweisWohnen } from "#lib/server/db";
|
||||||
import { getCurrentUser } from "#lib/server/user";
|
import { getCurrentUser } from "#lib/server/user";
|
||||||
@@ -9,7 +7,7 @@ import BedarfsausweisGewerbeModule from "#modules/angebot-anfragen/Bedarfsauswei
|
|||||||
|
|
||||||
const id = Astro.url.searchParams.get("id");
|
const id = Astro.url.searchParams.get("id");
|
||||||
const aufnahme_id = Astro.url.searchParams.get("aufnahme")
|
const aufnahme_id = Astro.url.searchParams.get("aufnahme")
|
||||||
let nachweistyp = Astro.url.searchParams.get("nachweistyp") as Enums.AusweisTyp || Enums.AusweisTyp.Standard;
|
let nachweistyp = Astro.url.searchParams.get("ausweistyp") as Enums.AusweisTyp || Enums.AusweisTyp.Standard;
|
||||||
|
|
||||||
let nachweis: BedarfsausweisGewerbe = {} as BedarfsausweisGewerbe;
|
let nachweis: BedarfsausweisGewerbe = {} as BedarfsausweisGewerbe;
|
||||||
let aufnahme: Aufnahme = {} as Aufnahme;
|
let aufnahme: Aufnahme = {} as Aufnahme;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import GEGNachweisGewerbeModule from "#modules/angebot-anfragen/GEGNachweisGewer
|
|||||||
|
|
||||||
const id = Astro.url.searchParams.get("id");
|
const id = Astro.url.searchParams.get("id");
|
||||||
const aufnahme_id = Astro.url.searchParams.get("aufnahme")
|
const aufnahme_id = Astro.url.searchParams.get("aufnahme")
|
||||||
let nachweistyp = Astro.url.searchParams.get("nachweistyp") as Enums.AusweisTyp || Enums.AusweisTyp.Standard;
|
let nachweistyp = Astro.url.searchParams.get("ausweistyp") as Enums.AusweisTyp || Enums.AusweisTyp.Standard;
|
||||||
|
|
||||||
let nachweis: GEGNachweisGewerbe = {} as GEGNachweisGewerbe;
|
let nachweis: GEGNachweisGewerbe = {} as GEGNachweisGewerbe;
|
||||||
let aufnahme: Aufnahme = {} as Aufnahme;
|
let aufnahme: Aufnahme = {} as Aufnahme;
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export const GET = defineApiRoute({
|
|||||||
exp: refreshTokenExpiry.valueOf(),
|
exp: refreshTokenExpiry.valueOf(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log("Creating refresh token for user ID:", user.id);
|
||||||
const { id } = await prisma.refreshTokens.create({
|
const { id } = await prisma.refreshTokens.create({
|
||||||
data: {
|
data: {
|
||||||
token: refreshToken,
|
token: refreshToken,
|
||||||
|
|||||||
70
src/pages/api/auth/verification-code.ts
Normal file
70
src/pages/api/auth/verification-code.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import { prisma } from "#lib/server/prisma.js";
|
||||||
|
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
|
||||||
|
import { sendVerificationCodeMail } from "#lib/server/mail/code.js";
|
||||||
|
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||||
|
import { createTimeBasedHash } from "#lib/auth/time-based-hash.js";
|
||||||
|
|
||||||
|
|
||||||
|
export const GET = defineApiRoute({
|
||||||
|
meta: {
|
||||||
|
description:
|
||||||
|
"Fragt einen neuen Verifizierungscode per Mail an.",
|
||||||
|
tags: ["Benutzer"],
|
||||||
|
summary: "Verifizierungscode anfragen.",
|
||||||
|
},
|
||||||
|
middleware: authorizationMiddleware,
|
||||||
|
output: z.void(),
|
||||||
|
async fetch(input, ctx) {
|
||||||
|
// Falls der Nutzer nicht existiert, wird eine Fehlermeldung zurückgegeben.
|
||||||
|
const user = await prisma.benutzer.findUnique({
|
||||||
|
where: {
|
||||||
|
email: input.email.toLowerCase(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new APIError({
|
||||||
|
code: "BAD_REQUEST",
|
||||||
|
message: "Benutzer konnte nicht gefunden werden.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await sendVerificationCodeMail(user);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
export const POST = defineApiRoute({
|
||||||
|
meta: {
|
||||||
|
description:
|
||||||
|
"Versucht den Nutzer mithilfe des abgeschickten Codes zu verifizieren.",
|
||||||
|
tags: ["Benutzer"],
|
||||||
|
summary: "Verifizieren.",
|
||||||
|
},
|
||||||
|
input: z.object({
|
||||||
|
code: z.string(),
|
||||||
|
email: z.string().email().toLowerCase(),
|
||||||
|
}),
|
||||||
|
output: z.void(),
|
||||||
|
async fetch({ code, email }, ctx) {
|
||||||
|
const generatedCode = createTimeBasedHash(email);
|
||||||
|
console.log(generatedCode, code);
|
||||||
|
|
||||||
|
if (code !== generatedCode) {
|
||||||
|
throw new APIError({
|
||||||
|
code: "BAD_REQUEST",
|
||||||
|
message: "Der eingegebene Verifizierungscode ist ungültig.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.benutzer.update({
|
||||||
|
where: {
|
||||||
|
email: email.toLowerCase(),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
verified: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -16,12 +16,14 @@ export const PATCH = defineApiRoute({
|
|||||||
strasse: true,
|
strasse: true,
|
||||||
telefon: true,
|
telefon: true,
|
||||||
empfaenger: true,
|
empfaenger: true,
|
||||||
|
zusatzzeile: true,
|
||||||
versand_empfaenger: true,
|
versand_empfaenger: true,
|
||||||
versand_ort: true,
|
versand_ort: true,
|
||||||
versand_plz: true,
|
versand_plz: true,
|
||||||
versand_strasse: true,
|
versand_strasse: true,
|
||||||
versand_zusatzzeile: true,
|
versand_zusatzzeile: true,
|
||||||
abweichende_versand_adresse: true
|
abweichende_versand_adresse: true,
|
||||||
|
email: true
|
||||||
}),
|
}),
|
||||||
output: z.object({
|
output: z.object({
|
||||||
checkout_url: z.string().optional(),
|
checkout_url: z.string().optional(),
|
||||||
@@ -31,7 +33,9 @@ export const PATCH = defineApiRoute({
|
|||||||
headers: authorizationHeaders,
|
headers: authorizationHeaders,
|
||||||
async fetch(input, context, user) {
|
async fetch(input, context, user) {
|
||||||
// Wir holen uns die Rechnung
|
// Wir holen uns die Rechnung
|
||||||
const rechnung = await prisma.rechnung.findUnique({
|
let rechnung;
|
||||||
|
if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
|
||||||
|
rechnung = await prisma.rechnung.findUnique({
|
||||||
where: {
|
where: {
|
||||||
id: context.params.id,
|
id: context.params.id,
|
||||||
benutzer: {
|
benutzer: {
|
||||||
@@ -47,6 +51,21 @@ export const PATCH = defineApiRoute({
|
|||||||
verbrauchsausweis_wohnen: true
|
verbrauchsausweis_wohnen: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
rechnung = await prisma.rechnung.findUnique({
|
||||||
|
where: {
|
||||||
|
id: context.params.id
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
bedarfsausweis_gewerbe: true,
|
||||||
|
bedarfsausweis_wohnen: true,
|
||||||
|
geg_nachweis_gewerbe: true,
|
||||||
|
geg_nachweis_wohnen: true,
|
||||||
|
verbrauchsausweis_gewerbe: true,
|
||||||
|
verbrauchsausweis_wohnen: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (!rechnung) {
|
if (!rechnung) {
|
||||||
throw new APIError({
|
throw new APIError({
|
||||||
@@ -66,12 +85,14 @@ export const PATCH = defineApiRoute({
|
|||||||
strasse: input.strasse,
|
strasse: input.strasse,
|
||||||
telefon: input.telefon,
|
telefon: input.telefon,
|
||||||
empfaenger: input.empfaenger,
|
empfaenger: input.empfaenger,
|
||||||
|
zusatzzeile: input.zusatzzeile,
|
||||||
versand_empfaenger: input.versand_empfaenger,
|
versand_empfaenger: input.versand_empfaenger,
|
||||||
versand_ort: input.versand_ort,
|
versand_ort: input.versand_ort,
|
||||||
versand_plz: input.versand_plz,
|
versand_plz: input.versand_plz,
|
||||||
versand_strasse: input.versand_strasse,
|
versand_strasse: input.versand_strasse,
|
||||||
versand_zusatzzeile: input.versand_zusatzzeile,
|
versand_zusatzzeile: input.versand_zusatzzeile,
|
||||||
abweichende_versand_adresse: input.abweichende_versand_adresse,
|
abweichende_versand_adresse: input.abweichende_versand_adresse,
|
||||||
|
email: input.email
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
24
src/pages/auth/code.astro
Normal file
24
src/pages/auth/code.astro
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
import CodeModule from "../../modules/auth/CodeModule.svelte";
|
||||||
|
import MinimalLayout from "#layouts/MinimalLayout.astro";
|
||||||
|
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
|
||||||
|
|
||||||
|
const valid = await validateAccessTokenServer(Astro)
|
||||||
|
|
||||||
|
if (valid) {
|
||||||
|
return Astro.redirect("/dashboard")
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirect = Astro.url.searchParams.get("redirect");
|
||||||
|
const email = Astro.url.searchParams.get("email");
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
return Astro.redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<MinimalLayout title="Verifizierung - IBCornelsen">
|
||||||
|
<CodeModule client:load {redirect} {email}></CodeModule>
|
||||||
|
</MinimalLayout>
|
||||||
108
src/pages/dashboard/rechnung/aendern.astro
Normal file
108
src/pages/dashboard/rechnung/aendern.astro
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
---
|
||||||
|
import { encodeToken } from "#lib/auth/token";
|
||||||
|
import { TokenType } from "#lib/auth/types";
|
||||||
|
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "#lib/constants";
|
||||||
|
import { Enums, prisma } from "#lib/server/prisma";
|
||||||
|
import moment from "moment";
|
||||||
|
import { createCaller } from "src/astro-typesafe-api-caller";
|
||||||
|
import KundendatenModule from "#modules/KundendatenModule.svelte";
|
||||||
|
import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro";
|
||||||
|
import { getCurrentUser, getOtherUser } from "#lib/server/user";
|
||||||
|
import { getAusweisartFromId } from "#components/Ausweis/types";
|
||||||
|
import { getAufnahme, getBedarfsausweisWohnen, getBilder, getObjekt, getRechnung, getUnterlagen, getVerbrauchsausweisGewerbe, getVerbrauchsausweisWohnen } from "#lib/server/db";
|
||||||
|
import { BenutzerClient } from "#components/Ausweis/types.js";
|
||||||
|
|
||||||
|
function getExistingAusweis(rechnung) {
|
||||||
|
if (rechnung.verbrauchsausweis_wohnen) {
|
||||||
|
return rechnung.verbrauchsausweis_wohnen;
|
||||||
|
}
|
||||||
|
if (rechnung.verbrauchsausweis_gewerbe) {
|
||||||
|
return rechnung.verbrauchsausweis_gewerbe;
|
||||||
|
}
|
||||||
|
if (rechnung.bedarfsausweis_wohnen) {
|
||||||
|
return rechnung.bedarfsausweis_wohnen ;
|
||||||
|
}
|
||||||
|
if (rechnung.bedarfsausweis_gewerbe) {
|
||||||
|
return rechnung.bedarfsausweis_gewerbe;
|
||||||
|
}
|
||||||
|
if (rechnung.geg_nachweis_gewerbe) {
|
||||||
|
return rechnung.geg_nachweis_gewerbe;
|
||||||
|
}
|
||||||
|
if (rechnung.geg_nachweis_wohnen) {
|
||||||
|
return rechnung.geg_nachweis_wohnen;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await getCurrentUser(Astro);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return Astro.redirect("/auth/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
const rechnungid = Astro.url.searchParams.get("rechnungid")
|
||||||
|
|
||||||
|
if (!rechnungid) {
|
||||||
|
return Astro.redirect("/404")
|
||||||
|
}
|
||||||
|
|
||||||
|
let rechnung;
|
||||||
|
|
||||||
|
//Only Admin can read foreign invoices
|
||||||
|
if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
|
||||||
|
rechnung = await prisma.rechnung.findUnique({
|
||||||
|
where: {
|
||||||
|
id: rechnungid,
|
||||||
|
benutzer_id: user.id
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
verbrauchsausweis_wohnen: true,
|
||||||
|
verbrauchsausweis_gewerbe: true,
|
||||||
|
bedarfsausweis_wohnen: true,
|
||||||
|
bedarfsausweis_gewerbe: true,
|
||||||
|
geg_nachweis_gewerbe: true,
|
||||||
|
geg_nachweis_wohnen: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
rechnung = await prisma.rechnung.findUnique({
|
||||||
|
where: {
|
||||||
|
id: rechnungid,
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
verbrauchsausweis_wohnen: true,
|
||||||
|
verbrauchsausweis_gewerbe: true,
|
||||||
|
bedarfsausweis_wohnen: true,
|
||||||
|
bedarfsausweis_gewerbe: true,
|
||||||
|
geg_nachweis_gewerbe: true,
|
||||||
|
geg_nachweis_wohnen: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rechnung) {
|
||||||
|
return Astro.redirect("/404")
|
||||||
|
}
|
||||||
|
|
||||||
|
const ausweis = getExistingAusweis(rechnung);
|
||||||
|
const ausweisart = getAusweisartFromId(ausweis.id)
|
||||||
|
|
||||||
|
let aufnahme, objekt, bilder, unterlagen, partner_code;
|
||||||
|
|
||||||
|
aufnahme = await getAufnahme(ausweis.aufnahme_id)
|
||||||
|
objekt = await getObjekt(aufnahme?.objekt_id)
|
||||||
|
bilder = await getBilder(ausweis.aufnahme_id)
|
||||||
|
unterlagen = await getUnterlagen(ausweis.aufnahme_id)
|
||||||
|
|
||||||
|
|
||||||
|
let impersonatedUser: Partial<BenutzerClient> | null = null;
|
||||||
|
|
||||||
|
if (user){
|
||||||
|
if (user.id !== ausweis.benutzer_id && ausweis.benutzer_id !== undefined){
|
||||||
|
impersonatedUser = await getOtherUser(Astro, ausweis.benutzer_id) || {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---
|
||||||
|
<AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen">
|
||||||
|
<KundendatenModule {user} {impersonatedUser} {ausweis} {objekt} {aufnahme} {bilder} {rechnung} {ausweisart} {unterlagen} {partner_code} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} nurRechnungsadresseUpdate={true} client:only ></KundendatenModule>
|
||||||
|
</AusweisLayout>
|
||||||
@@ -3,12 +3,28 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Config
|
# Config
|
||||||
CONTAINER_NAME="online-energieausweis-database-1"
|
CONTAINER_NAME="database"
|
||||||
DB_USER="main"
|
DB_USER="main"
|
||||||
DB_NAME="main"
|
DB_NAME="main"
|
||||||
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
|
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
|
||||||
FILE_NAME="backup-$TIMESTAMP.sql.br"
|
FILE_NAME="backup-$TIMESTAMP.sql.br"
|
||||||
|
|
||||||
|
# Wir holen uns den parameter --skip-backup, um zu entscheiden, ob wir ein Backup machen wollen
|
||||||
|
SKIP_BACKUP=false
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--skip-backup)
|
||||||
|
SKIP_BACKUP=true
|
||||||
|
shift # Remove the argument from the list
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unbekannter Parameter: $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
REQUIRED_CONFIRMATION='Ja, ich möchte alle Daten unwiderruflich löschen.'
|
REQUIRED_CONFIRMATION='Ja, ich möchte alle Daten unwiderruflich löschen.'
|
||||||
|
|
||||||
echo "⚠️ WARNUNG: Diese Aktion wird alle Tabellen und Einträge in der Datenbank vollständig löschen!"
|
echo "⚠️ WARNUNG: Diese Aktion wird alle Tabellen und Einträge in der Datenbank vollständig löschen!"
|
||||||
@@ -21,9 +37,11 @@ if [[ "$USER_CONFIRMATION" != "$REQUIRED_CONFIRMATION" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "📦 Backup wird erstellt..."
|
if [[ "$SKIP_BACKUP" == false ]]; then
|
||||||
docker exec -t "$CONTAINER_NAME" pg_dumpall -c -U "$DB_USER" | brotli > "$FILE_NAME"
|
echo "📦 Backup wird erstellt..."
|
||||||
echo "✅ Backup abgeschlossen: $FILE_NAME"
|
docker exec -t "$CONTAINER_NAME" pg_dumpall -c -U "$DB_USER" | brotli > "$FILE_NAME"
|
||||||
|
echo "✅ Backup abgeschlossen: $FILE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "🧨 Alle Daten aus allen Tabellen werden gelöscht..."
|
echo "🧨 Alle Daten aus allen Tabellen werden gelöscht..."
|
||||||
|
|
||||||
@@ -34,12 +52,22 @@ DECLARE
|
|||||||
r RECORD;
|
r RECORD;
|
||||||
sql TEXT := '';
|
sql TEXT := '';
|
||||||
BEGIN
|
BEGIN
|
||||||
|
-- Truncate all tables
|
||||||
FOR r IN
|
FOR r IN
|
||||||
SELECT tablename
|
SELECT tablename
|
||||||
FROM pg_tables
|
FROM pg_tables
|
||||||
WHERE schemaname = 'public'
|
WHERE schemaname = 'public'
|
||||||
LOOP
|
LOOP
|
||||||
sql := sql || FORMAT('TRUNCATE TABLE public.%I CASCADE;', r.tablename);
|
sql := sql || FORMAT('DROP TABLE public.%I CASCADE;', r.tablename);
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
-- Drop all sequences
|
||||||
|
FOR r IN
|
||||||
|
SELECT sequence_name
|
||||||
|
FROM information_schema.sequences
|
||||||
|
WHERE sequence_schema = 'public'
|
||||||
|
LOOP
|
||||||
|
sql := sql || FORMAT('DROP SEQUENCE IF EXISTS public.%I CASCADE;', r.sequence_name);
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
EXECUTE sql;
|
EXECUTE sql;
|
||||||
|
|||||||
Reference in New Issue
Block a user