diff --git a/.github/workflows/auto-merge-staging-into-main.yml b/.github/workflows/auto-merge-staging-into-main.yml new file mode 100644 index 00000000..f233b3ad --- /dev/null +++ b/.github/workflows/auto-merge-staging-into-main.yml @@ -0,0 +1,76 @@ +name: Auto Merge Staging into Main + +on: + schedule: + - cron: '0 2 * * *' # 2:00 UTC = 4:00 Europäische Zeit + workflow_dispatch: + +jobs: + merge: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set Git user + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Fetch all branches + run: | + git fetch origin main + git fetch origin staging + + - name: Check if main has commits not in staging + id: check + run: | + git fetch origin + if [ $(git rev-list --count origin/staging..origin/main) -gt 0 ]; then + echo "❌ Staging is behind main and requires manual merging." + exit 1 + fi + + - name: Create PR from staging to main + id: create_pr + run: | + PR_URL=$(gh pr create --base main --head staging --title "Auto-merge staging into main" --body "This PR was created automatically by GitHub Actions. It merges the latest \`staging\` into \`main\`.") + echo "PR_URL=$PR_URL" >> $GITHUB_OUTPUT + PR_NUMBER=$(echo $PR_URL | awk -F'/' '{print $NF}') + echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Enable auto-merge on PR + if: steps.create_pr.outputs.PR_NUMBER != '' + run: | + gh pr merge ${{ steps.create_pr.outputs.PR_NUMBER }} --merge --auto + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + + notify_failure: + needs: merge + if: failure() + runs-on: ubuntu-latest + steps: + - name: Send Discord notification on failure + run: | + curl -H "Content-Type: application/json" \ + -X POST \ + -d "{\"content\": \"🚨 Auto-Merge fehlgeschlagen! Bitte manuell prüfen: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\"}" \ + ${{ secrets.DISCORD_WEBHOOK_URL }} + + notify_success: + needs: merge + if: success() + runs-on: ubuntu-latest + steps: + - name: Send Discord notification on success + run: | + curl -H "Content-Type: application/json" \ + -X POST \ + -d "{\"content\": \"✅ Auto-Merge ausgeführt! Ergebnis jetzt auf [GitHub](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) und [online-energieausweis.org](https://online-energieausweis.org) einsehen.\"}" \ + ${{ secrets.DISCORD_WEBHOOK_URL }} \ No newline at end of file diff --git a/.github/workflows/dev-pipeline.yml b/.github/workflows/dev-pipeline.yml index b67202a2..f578abfc 100644 --- a/.github/workflows/dev-pipeline.yml +++ b/.github/workflows/dev-pipeline.yml @@ -28,4 +28,4 @@ jobs: git clean -f -d git pull origin dev git status - make prod \ No newline at end of file + make prod-no-backup \ No newline at end of file diff --git a/.github/workflows/prevent-wrong-pr.yml b/.github/workflows/prevent-wrong-pr.yml new file mode 100644 index 00000000..07f78b22 --- /dev/null +++ b/.github/workflows/prevent-wrong-pr.yml @@ -0,0 +1,28 @@ +name: PR Rules Enforcement + +on: + pull_request: + branches: + - main + - staging + +jobs: + check-pr: + runs-on: ubuntu-latest + name: Validate Pull Request Sources + steps: + - name: Prevent dev merges + run: | + if [[ "${{ github.head_ref }}" == "dev" && "${{ github.base_ref }}" == "main" ]]; then + echo "ERROR: Merging 'dev' into 'main' is forbidden!" + exit 1 + fi + + + - name: Allow only staging into main + if: github.base_ref == 'main' + run: | + if [[ "${{ github.head_ref }}" != "staging" ]]; then + echo "ERROR: Only 'staging' branch is allowed to merge into 'main'. Current: '${{ github.head_ref }}'" + exit 1 + fi diff --git a/Makefile b/Makefile index 80f67115..26be7c6e 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ PERSISTENT_DIR := $(HOME)/persistent/$(APP_NAME) BACKUP_FILENAME := $(HOME)/backups/$(shell date +"%Y-%m-%d_%H-%M-%S").sql.gz online-energieausweis: - bun run dev --host + NODE_ENV="development" bun run dev --host dev: database online-energieausweis @@ -30,6 +30,7 @@ run-database: stop-database docker volume create $(DB_VOLUME) docker build -t $(DB_CONTAINER_NAME) . docker run -d --name $(DB_CONTAINER_NAME) \ + --restart=always \ -e POSTGRES_USER=$(DB_USER) \ -e POSTGRES_PASSWORD=$(DB_PASSWORD) \ -p $(DB_PORT):5432 \ @@ -60,7 +61,9 @@ all: update-dwd-klimafaktoren-cron: pm2 start bun --name "update-dwd-klimafaktoren-cron" --cron "0 12 28 * *" -- src/cronjobs/update-dwd-klimafaktoren.ts -prod: install-dependencies prisma-studio backup-database-cronjob update-dwd-klimafaktoren-cron +prod: prod-no-backup backup-database-cronjob + +prod-no-backup: install-dependencies prisma-studio update-dwd-klimafaktoren-cron bun run build mkdir -p ~/logs mkdir -p ~/persistent/online-energieausweis @@ -71,4 +74,4 @@ prod: install-dependencies prisma-studio backup-database-cronjob update-dwd-klim backup-database-cronjob: - pm2 delete daily-db-backup - pm2 start bash --name "daily-db-backup" --cron "0 0 * * *" -- backup-database.bash \ No newline at end of file + pm2 start bash --name "daily-db-backup" --no-autorestart --cron "0 0 * * *" -- backup-database.bash \ No newline at end of file diff --git a/backup-database.bash b/backup-database.bash index fc8a5f08..fee2a70d 100644 --- a/backup-database.bash +++ b/backup-database.bash @@ -19,7 +19,11 @@ echo "Uploaded $FILE_NAME" docker exec -t online-energieausweis-database-1 pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE +<<<<<<< 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" diff --git a/bun.lock b/bun.lock index 8a94ea08..bb6cacf8 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,7 @@ "@pdfme/common": "^5.2.16", "@pdfme/generator": "^5.2.16", "@pdfme/ui": "^5.2.16", + "@svelte-plugins/datepicker": "^1.0.11", "@trpc/client": "^10.45.2", "@trpc/server": "^10.45.2", "astro": "^4.16.17", @@ -711,6 +712,8 @@ "@smithy/util-waiter": ["@smithy/util-waiter@4.0.2", "", { "dependencies": { "@smithy/abort-controller": "^4.0.1", "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-piUTHyp2Axx3p/kc2CIJkYSv0BAaheBQmbACZgQSSfWUumWNW+R1lL+H9PDBxKJkvOeEX+hKYEFiwO8xagL8AQ=="], + "@svelte-plugins/datepicker": ["@svelte-plugins/datepicker@1.0.11", "", {}, "sha512-Tqc07QLyRkCpc3Glg6oRLTUApLtCrOh52d6vJ7L32QI17HrwvcDDjaH3LF3X1SBm3CWdMrnqfJp3xjUZmB4wzw=="], + "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@2.5.3", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^1.0.4", "debug": "^4.3.4", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.3", "svelte-hmr": "^0.15.3", "vitefu": "^0.2.4" }, "peerDependencies": { "svelte": "^3.54.0 || ^4.0.0 || ^5.0.0-next.0", "vite": "^4.0.0" } }, "sha512-erhNtXxE5/6xGZz/M9eXsmI7Pxa6MS7jyTy06zN3Ck++ldrppOnOlJwHHTsMC7DHDQdgUp4NAc4cDNQ9eGdB/w=="], "@sveltejs/vite-plugin-svelte-inspector": ["@sveltejs/vite-plugin-svelte-inspector@1.0.4", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^2.2.0", "svelte": "^3.54.0 || ^4.0.0", "vite": "^4.0.0" } }, "sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ=="], diff --git a/docker-compose.yml b/docker-compose.yml index a0485abf..a96bb452 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,7 @@ version: '3' services: database: build: ./ + restart: always env_file: - .env ports: diff --git a/package.json b/package.json index c5f7595b..96dbcac3 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@pdfme/common": "^5.2.16", "@pdfme/generator": "^5.2.16", "@pdfme/ui": "^5.2.16", + "@svelte-plugins/datepicker": "^1.0.11", "@trpc/client": "^10.45.2", "@trpc/server": "^10.45.2", "astro": "^4.16.17", diff --git a/prisma/schema/BedarfsausweisWohnen.prisma b/prisma/schema/BedarfsausweisWohnen.prisma index 656d4717..e3074294 100644 --- a/prisma/schema/BedarfsausweisWohnen.prisma +++ b/prisma/schema/BedarfsausweisWohnen.prisma @@ -41,19 +41,19 @@ model BedarfsausweisWohnen { volumen Float? dicht Boolean? fenster_flaeche_1 Float? - fenster_art_1 String? + fenster_art_1 Float? fenster_flaeche_2 Float? - fenster_art_2 String? + fenster_art_2 Float? dachfenster_flaeche Float? - dachfenster_art String? + dachfenster_art Float? haustuer_flaeche Float? - haustuer_art String? + haustuer_art Float? dach_bauart String? @db.VarChar decke_bauart String? @db.VarChar - dach_daemmung String? - decke_daemmung String? - aussenwand_daemmung String? - boden_daemmung String? + dach_daemmung Float? + decke_daemmung Float? + aussenwand_daemmung Float? + boden_daemmung Float? aussenwand_bauart String? @db.VarChar boden_bauart String? @db.VarChar warmwasser_verteilung String? @db.VarChar diff --git a/recover-db-dev.bash b/recover-db-dev.bash index e7b58155..110a1352 100644 --- a/recover-db-dev.bash +++ b/recover-db-dev.bash @@ -2,30 +2,46 @@ # === Configuration === 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 -# === Get latest file from IONOS S3 bucket === -LATEST_FILE=$(aws s3api list-objects-v2 \ - --bucket "$BUCKET_NAME" \ - --prefix "data-dump" \ - --endpoint-url "$ENDPOINT_URL" \ - --query 'Contents | sort_by(@, &LastModified) | [-1].Key' \ - --output text) +# === Check if a custom file is given as a command line argument === +if [ $# -eq 1 ]; then + CUSTOM_FILE="$1" + echo "🔍 Using custom file: $CUSTOM_FILE" + # Check if the file exists + if [ ! -f "$CUSTOM_FILE" ]; then + echo "❌ Custom file does not exist: $CUSTOM_FILE" + exit 1 + fi + LATEST_FILE="$CUSTOM_FILE" + FILENAME=$(basename "$LATEST_FILE") + SQL_FILE="${FILENAME%.br}" # Remove .br suffix +else + echo "🔍 No custom file provided, searching for latest .sql.br file in S3" -# === Check if file was found === -if [ "$LATEST_FILE" == "None" ] || [ -z "$LATEST_FILE" ]; then - echo "❌ No matching .sql.br file found." - exit 1 + # === Get latest file from IONOS S3 bucket === + LATEST_FILE=$(aws s3api list-objects-v2 \ + --bucket "$BUCKET_NAME" \ + --prefix "data-dump" \ + --endpoint-url "$ENDPOINT_URL" \ + --query 'Contents | sort_by(@, &LastModified) | [-1].Key' \ + --output text) + + # === Check if file was found === + if [ "$LATEST_FILE" == "None" ] || [ -z "$LATEST_FILE" ]; then + echo "❌ No matching .sql.br file found." + exit 1 + fi + echo "🔍 Latest file found: $LATEST_FILE" + FILENAME=$(basename "$LATEST_FILE") + SQL_FILE="${FILENAME%.br}" # Remove .br suffix + + echo "📥 Downloading $LATEST_FILE" + aws s3 cp "s3://$BUCKET_NAME/$LATEST_FILE" "$LOCAL_DOWNLOAD_DIR" \ + --endpoint-url "$ENDPOINT_URL" fi -FILENAME=$(basename "$LATEST_FILE") -SQL_FILE="${FILENAME%.br}" # Remove .br suffix - -echo "📥 Downloading $LATEST_FILE" -aws s3 cp "s3://$BUCKET_NAME/$LATEST_FILE" "$LOCAL_DOWNLOAD_DIR" \ - --endpoint-url "$ENDPOINT_URL" - # === Decompress with Brotli === echo "🗜️ Decompressing $FILENAME -> $SQL_FILE" brotli -d "$FILENAME" diff --git a/src/astro-typesafe-api-caller.ts b/src/astro-typesafe-api-caller.ts index 262124be..4c07b62c 100644 --- a/src/astro-typesafe-api-caller.ts +++ b/src/astro-typesafe-api-caller.ts @@ -12,25 +12,25 @@ export const createCaller = createCallerFactory({ "admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"), "admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"), "admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"), - "aufnahme": await import("../src/pages/api/aufnahme/index.ts"), - "ausweise": await import("../src/pages/api/ausweise/index.ts"), "auth/access-token": await import("../src/pages/api/auth/access-token.ts"), "auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"), "auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"), + "ausweise": await import("../src/pages/api/ausweise/index.ts"), "bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"), "bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/index.ts"), + "aufnahme": await import("../src/pages/api/aufnahme/index.ts"), "bedarfsausweis-wohnen/[id]": await import("../src/pages/api/bedarfsausweis-wohnen/[id].ts"), "bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"), "bilder/[id]": await import("../src/pages/api/bilder/[id].ts"), - "geg-nachweis-gewerbe/[id]": await import("../src/pages/api/geg-nachweis-gewerbe/[id].ts"), - "geg-nachweis-gewerbe": await import("../src/pages/api/geg-nachweis-gewerbe/index.ts"), "geg-nachweis-wohnen/[id]": await import("../src/pages/api/geg-nachweis-wohnen/[id].ts"), "geg-nachweis-wohnen": await import("../src/pages/api/geg-nachweis-wohnen/index.ts"), + "geg-nachweis-gewerbe/[id]": await import("../src/pages/api/geg-nachweis-gewerbe/[id].ts"), + "geg-nachweis-gewerbe": await import("../src/pages/api/geg-nachweis-gewerbe/index.ts"), "objekt": await import("../src/pages/api/objekt/index.ts"), + "ticket": await import("../src/pages/api/ticket/index.ts"), "rechnung/[id]": await import("../src/pages/api/rechnung/[id].ts"), "rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"), "rechnung": await import("../src/pages/api/rechnung/index.ts"), - "ticket": await import("../src/pages/api/ticket/index.ts"), "user": await import("../src/pages/api/user/index.ts"), "user/self": await import("../src/pages/api/user/self.ts"), "verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"), diff --git a/src/client/lib/lesen.ts b/src/client/lib/lesen.ts new file mode 100644 index 00000000..c7ded8a2 --- /dev/null +++ b/src/client/lib/lesen.ts @@ -0,0 +1,15 @@ +import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js"; +import { Benutzer } from "#lib/client/prisma.js"; +import { api } from "astro-typesafe-api/client"; +import Cookies from "js-cookie"; + +export async function benutzerLesen(benutzerId: string): Promise { + const benutzer = await api.user.GET.fetch({ id: benutzerId } + , { + headers: { + Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}` + } + }); + + return benutzer[0]; +} \ No newline at end of file diff --git a/src/client/lib/speichern.ts b/src/client/lib/speichern.ts index 31708641..89f6c2f0 100644 --- a/src/client/lib/speichern.ts +++ b/src/client/lib/speichern.ts @@ -1,5 +1,5 @@ import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js"; -import { Aufnahme, Objekt } from "#lib/client/prisma.js"; +import { Aufnahme, Benutzer, Objekt } from "#lib/client/prisma.js"; import { api } from "astro-typesafe-api/client"; import Cookies from "js-cookie"; @@ -161,4 +161,32 @@ export async function objektSpeichern(objekt: Objekt & { id?: string }): Promise return id; } +} + +export async function benutzerSpeichern(benutzer: Partial): Promise { + const completeBenutzer: Benutzer = { + id: benutzer.id, + name: benutzer.name ?? null, + email: benutzer.email, + passwort: "", + adresse: benutzer.adresse ?? null, + anrede: benutzer.anrede ?? null, + firma: benutzer.firma ?? null, + vorname: benutzer.vorname ?? null, + ort: benutzer.ort ?? null, + plz: benutzer.plz ?? null, + profilbild: benutzer.profilbild ?? null, + telefon: benutzer.telefon ?? null, + updated_at: new Date(), + verified: benutzer.verified ?? false, + }; + + await api.user.POST.fetch(completeBenutzer + , { + headers: { + Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}` + } + }); + + return benutzer.id; } \ No newline at end of file diff --git a/src/components/Abrechnung/AbrechnungTable.svelte b/src/components/Abrechnung/AbrechnungTable.svelte new file mode 100644 index 00000000..dfbe44d9 --- /dev/null +++ b/src/components/Abrechnung/AbrechnungTable.svelte @@ -0,0 +1,121 @@ + + +
+
+ + + +

Abrechnungsübersicht für {email}

+
+
+ +
+ {#if !bestellungen || bestellungen.length === 0} +

Keine Bestellungen gefunden.

+ {/if} + {#each periods as dt} + {@const jahrMonat = dt.format("Y-MM")} + {#if jahrMonat in bestellungenNachMonat && bestellungenNachMonat[jahrMonat].length > 0} + + {@const provisionMonat = bestellungenNachMonat[jahrMonat].reduce((acc, bestellung) => { + return acc + provisionen[bestellung.ausweis.ausweisart] || 0; + }, 0) * 1.19} + + + + + + + + + + + + + + + + + + + + + {#each bestellungenNachMonat[jahrMonat] as bestellung} + {@const provisionBestellung = provisionen[bestellung.ausweis.ausweisart] || 0} + + + + + + + + + + {/each} +
IDDATUMGEBÄUDEADRESSE PLZ ORT AUSWEISBETRAG NETTO
{months[dt.format("MM")]} {dt.format("YYYY")}{provisionMonat.toFixed(2)} €
{bestellung.id}{moment(bestellung.created_at).format("DD.MM.YYYY")}{bestellung.ausweis.aufnahme.objekt.adresse}{bestellung.ausweis.aufnahme.objekt.plz}{bestellung.ausweis.aufnahme.objekt.ort}{bestellung.ausweis.ausweisart}{provisionBestellung.toFixed(2)} €
+ {/if} + {/each} +
\ No newline at end of file diff --git a/src/components/Ausweis/ButtonWeiterHilfe.svelte b/src/components/Ausweis/ButtonWeiterHilfe.svelte index d7c9ff88..26a90543 100644 --- a/src/components/Ausweis/ButtonWeiterHilfe.svelte +++ b/src/components/Ausweis/ButtonWeiterHilfe.svelte @@ -214,8 +214,8 @@ grid-cols-1 gap-x-2 gap-y-4 />
- Verbrauchsausweis online
inkl. ausführlicher telefonischer - Beratung + Selbsteingabe online
inkl. ausführlicher telefonischer + Beratung!
@@ -234,7 +234,7 @@ grid-cols-1 gap-x-2 gap-y-4 />
- Verbrauchsausweis offline
Sie schicken uns 3 Verbrauchsabrechnungen zu) + Wir übernehmen die Eingabe
Sie übermitteln die nötigen Unterlagen per Upload oder E-Mail.
diff --git a/src/components/Dashboard/DashboardAusweis.svelte b/src/components/Dashboard/DashboardAusweis.svelte index 96ea5121..4134be86 100644 --- a/src/components/Dashboard/DashboardAusweis.svelte +++ b/src/components/Dashboard/DashboardAusweis.svelte @@ -257,6 +257,12 @@ let bedarfsausweisFileInput: HTMLInputElement; let bedarfsausweisAdditionalInput: HTMLInputElement; + + let dropdownOpen = false; + + function toggleDropdown() { + dropdownOpen = !dropdownOpen; + }
@@ -273,30 +279,41 @@ {/if}
+ {#if dropdownOpen}
+
+ +
+
+ - +
--> + {#if ausweis.bestellt && rechnung} + + {/if} -
+ {/if} + +
{#if ausweis.ausgestellt} Ausgestellt @@ -341,9 +358,6 @@
- {progress}%
{#await calculations then calculations}
diff --git a/src/components/Dashboard/DashboardSidebar.svelte b/src/components/Dashboard/DashboardSidebar.svelte index 5a0e4767..7d9aa514 100644 --- a/src/components/Dashboard/DashboardSidebar.svelte +++ b/src/components/Dashboard/DashboardSidebar.svelte @@ -70,6 +70,7 @@
{/if} +

diff --git a/src/components/Overlay.svelte b/src/components/Overlay.svelte index 36d94f46..fae15d93 100644 --- a/src/components/Overlay.svelte +++ b/src/components/Overlay.svelte @@ -2,6 +2,7 @@ export let hidden: boolean = true; export let closeable: boolean = true; import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock'; + import { Cross1 } from 'radix-svelte-icons'; $: if (globalThis.window) { if (hidden) { @@ -12,13 +13,11 @@ } -
{ - hidden = closeable ? true : hidden; -}}> +
{#if closeable} - + }}> {/if}
\ No newline at end of file diff --git a/src/components/widgets/immowelt/WelcherAusweisWidget_immowelt.svelte b/src/components/widgets/immowelt/WelcherAusweisWidget_immowelt.svelte index acbcadc0..2f7e07f7 100644 --- a/src/components/widgets/immowelt/WelcherAusweisWidget_immowelt.svelte +++ b/src/components/widgets/immowelt/WelcherAusweisWidget_immowelt.svelte @@ -177,7 +177,10 @@ $: standardXL = + + href_buy1={`https://online-energieausweis.org/${partner}/energieausweis-erstellen/verbrauchsausweis-wohngebaeude/${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'}`} + + > {/if} @@ -200,7 +206,9 @@ $: standardXL = {/if} @@ -223,7 +234,9 @@ $: standardXL = {/if} @@ -247,7 +262,9 @@ $: standardXL = {/if} @@ -271,7 +290,9 @@ $: standardXL = @@ -296,7 +319,9 @@ $: standardXL = {/if} diff --git a/src/components/widgets/immowelt/WidgetCardTemplate.svelte b/src/components/widgets/immowelt/WidgetCardTemplate.svelte index f626e3ab..7ea5f26b 100644 --- a/src/components/widgets/immowelt/WidgetCardTemplate.svelte +++ b/src/components/widgets/immowelt/WidgetCardTemplate.svelte @@ -1,115 +1,148 @@ -
+
+ {#if empfehlung === "ja"} +
+ Empfehlung +
+ {/if} +

{name}

-{#if empfehlung === "ja"} -
Empfehlung
-{/if} -

{name}

- - -
-
{variant}
- -
-

- ab {price} € -

-
- -
- - - -
+
+
{variant}
+ +
+

+ ab {price} € +

+
- {#each services as [service, check]} -
+
+ +
+ +
+ {#each services as [service, check]} +
{@html service} - {check ? "✔" : "✘"} -
- {/each} - + {check ? "✔" : "✘"}
-
+ {/each} +
+ +
+ + +
diff --git a/src/lib/pdf/pdfVerbrauchsausweisGewerbe.ts b/src/lib/pdf/pdfVerbrauchsausweisGewerbe.ts index 2a420188..be32284f 100644 --- a/src/lib/pdf/pdfVerbrauchsausweisGewerbe.ts +++ b/src/lib/pdf/pdfVerbrauchsausweisGewerbe.ts @@ -431,7 +431,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe }) page.drawImage(pfeilNachOben, { - x: vergleichsWertStromTranslationX, + x: vergleichsWertStromTranslationX, y: height - 437, width: pfeilWidth, height: 30 diff --git a/src/lib/server/ausweis.ts b/src/lib/server/ausweis.ts index 052cc636..13ee0821 100644 --- a/src/lib/server/ausweis.ts +++ b/src/lib/server/ausweis.ts @@ -1,11 +1,27 @@ -import { AufnahmeClient, BedarfsausweisWohnenClient, BenutzerClient, BildClient, getAusweisartFromId, ObjektClient, RechnungClient, VerbrauchsausweisGewerbeClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js"; +import { + AufnahmeClient, + BedarfsausweisWohnenClient, + BenutzerClient, + BildClient, + getAusweisartFromId, + ObjektClient, + RechnungClient, + VerbrauchsausweisGewerbeClient, + VerbrauchsausweisWohnenClient, +} from "#components/Ausweis/types.js"; import { pdfDatenblattVerbrauchsausweisGewerbe } from "#lib/pdf/pdfDatenblattVerbrauchsausweisGewerbe.js"; import { pdfDatenblattVerbrauchsausweisWohnen } from "#lib/pdf/pdfDatenblattVerbrauchsausweisWohnen.js"; import { pdfVerbrauchsausweisGewerbe } from "#lib/pdf/pdfVerbrauchsausweisGewerbe.js"; import { pdfVerbrauchsausweisWohnen } from "#lib/pdf/pdfVerbrauchsausweisWohnen.js"; import { pdfAushangVerbrauchsausweisGewerbe } from "#lib/pdf/pdfAushangVerbrauchsausweisGewerbe.js"; -import { Enums, prisma, Rechnung } from "#lib/server/prisma.js"; - +import { + BedarfsausweisWohnen, + Enums, + prisma, + Rechnung, + VerbrauchsausweisGewerbe, + VerbrauchsausweisWohnen, +} from "#lib/server/prisma.js"; /** * Gibt den richtigen Prisma Adapter für die Ausweisart basierend auf der UID zurück, oder null bei einer falschen UID. @@ -15,68 +31,179 @@ export function getPrismaAusweisAdapter(id: string) { const ausweisart = getAusweisartFromId(id); if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) { - return prisma.verbrauchsausweisWohnen + return prisma.verbrauchsausweisWohnen; } else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) { - return prisma.verbrauchsausweisGewerbe + return prisma.verbrauchsausweisGewerbe; } else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) { - return prisma.bedarfsausweisWohnen + return prisma.bedarfsausweisWohnen; } else if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) { - return prisma.gEGNachweisWohnen + return prisma.gEGNachweisWohnen; } else if (ausweisart === Enums.Ausweisart.GEGNachweisGewerbe) { - return prisma.gEGNachweisGewerbe + return prisma.gEGNachweisGewerbe; } else if (ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) { - return prisma.bedarfsausweisGewerbe + return prisma.bedarfsausweisGewerbe; } } /** * Gibt den richtigen Ansichtsausweis basierend auf der Ausweisart zurück. - * @param ausweis + * @param ausweis */ -export async function getAnsichtsausweis(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, vorschau: boolean = true, ausweisart = getAusweisartFromId(ausweis.id)) { +export async function getAnsichtsausweis( + ausweis: + | VerbrauchsausweisWohnenClient + | VerbrauchsausweisGewerbeClient + | BedarfsausweisWohnenClient, + aufnahme: AufnahmeClient, + objekt: ObjektClient, + bilder: BildClient[], + user: BenutzerClient, + vorschau: boolean = true, + ausweisart = getAusweisartFromId(ausweis.id) +) { if (!ausweisart) { - return null + return null; } if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) { - return await pdfVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, bilder, user, vorschau) + return await pdfVerbrauchsausweisWohnen( + ausweis as VerbrauchsausweisWohnenClient, + aufnahme, + objekt, + bilder, + user, + vorschau + ); } else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) { - return await pdfVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, bilder, user, vorschau) + return await pdfVerbrauchsausweisGewerbe( + ausweis as VerbrauchsausweisGewerbeClient, + aufnahme, + objekt, + bilder, + user, + vorschau + ); } - return null + return null; } /** * Gibt das richtige Datenblatt basierend auf der Ausweisart zurück. - * @param ausweis + * @param ausweis */ -export async function getDatenblatt(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, rechnung: Rechnung, ausweisart = getAusweisartFromId(ausweis.id)) { +export async function getDatenblatt( + ausweis: + | VerbrauchsausweisWohnenClient + | VerbrauchsausweisGewerbeClient + | BedarfsausweisWohnenClient, + aufnahme: AufnahmeClient, + objekt: ObjektClient, + bilder: BildClient[], + user: BenutzerClient, + rechnung: Rechnung, + ausweisart = getAusweisartFromId(ausweis.id) +) { if (!ausweisart) { - return null + return null; } if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) { - return await pdfDatenblattVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, rechnung, bilder) + return await pdfDatenblattVerbrauchsausweisWohnen( + ausweis as VerbrauchsausweisWohnenClient, + aufnahme, + objekt, + rechnung, + bilder + ); } else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) { - return await pdfDatenblattVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, rechnung, bilder) + return await pdfDatenblattVerbrauchsausweisGewerbe( + ausweis as VerbrauchsausweisGewerbeClient, + aufnahme, + objekt, + rechnung, + bilder + ); } - return null + return null; } /** * Gibt den richtigen Aushang basierend auf der Ausweisart zurück. - * @param ausweis + * @param ausweis */ -export async function getAushang(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, vorschau: boolean = true, rechnung: Rechnung, ausweisart = getAusweisartFromId(ausweis.id)) { +export async function getAushang( + ausweis: + | VerbrauchsausweisWohnenClient + | VerbrauchsausweisGewerbeClient + | BedarfsausweisWohnenClient, + aufnahme: AufnahmeClient, + objekt: ObjektClient, + bilder: BildClient[], + user: BenutzerClient, + vorschau: boolean = true, + rechnung: Rechnung, + ausweisart = getAusweisartFromId(ausweis.id) +) { if (!ausweisart || !rechnung.services.includes(Enums.Service.Aushang)) { - return null + return null; } if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) { - return await pdfAushangVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, bilder, user, vorschau) + return await pdfAushangVerbrauchsausweisGewerbe( + ausweis as VerbrauchsausweisGewerbeClient, + aufnahme, + objekt, + bilder, + user, + vorschau + ); } - return null -} \ No newline at end of file + return null; +} + +/** + * Extrahiert die Ausweisfelder aus einem Objekt, das mehrere Ausweisarten enthält, und fasst sie in einem gemeinsamen Feld `ausweis` zusammen. + * @param row Ein Objekt, das die Ausweisfelder enthält. + * @returns Ein neues Objekt, das die Ausweisfelder extrahiert und in einem gemeinsamen Feld `ausweis` zusammenfasst. + */ +export function extrahiereAusweisAusFeldMitMehrerenAusweisen( + row: T & { + bedarfsausweis_wohnen?: BedarfsausweisWohnen; + verbrauchsausweis_wohnen?: VerbrauchsausweisWohnen; + verbrauchsausweis_gewerbe?: VerbrauchsausweisGewerbe; + } +) { + const { + bedarfsausweis_wohnen, + verbrauchsausweis_wohnen, + verbrauchsausweis_gewerbe, + ...rest + } = row; + return { + ...rest, + ausweis: { + ...(bedarfsausweis_wohnen ?? + verbrauchsausweis_wohnen ?? + verbrauchsausweis_gewerbe), + ausweisart: bedarfsausweis_wohnen + ? Enums.Ausweisart.BedarfsausweisWohnen + : verbrauchsausweis_wohnen + ? Enums.Ausweisart.VerbrauchsausweisWohnen + : Enums.Ausweisart.VerbrauchsausweisGewerbe, + }, + } as { + ausweis: ( + | BedarfsausweisWohnen + | VerbrauchsausweisWohnen + | VerbrauchsausweisGewerbe + ) & { ausweisart: Enums.Ausweisart }; + } & Omit< + T, + | "bedarfsausweis_wohnen" + | "verbrauchsausweis_wohnen" + | "verbrauchsausweis_gewerbe" + >; +} diff --git a/src/lib/server/user.ts b/src/lib/server/user.ts index 1b6070f3..f9be1df6 100644 --- a/src/lib/server/user.ts +++ b/src/lib/server/user.ts @@ -1,9 +1,27 @@ import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js"; import { checkAuthorizationHeader, checkAuthorizationHeaderNoThrow } from "#lib/middleware/authorization.js"; import { AstroGlobal } from "astro"; +import { Enums } from "#lib/client/prisma.js"; +import { prisma } from "#lib/server/prisma.js"; export function getCurrentUser(Astro: AstroGlobal) { const accessToken = Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value; return checkAuthorizationHeaderNoThrow(`Bearer ${accessToken}`) +} + +export async function getOtherUser(Astro: AstroGlobal, userId : string) { + const accessToken = Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value; + + let currentUser = await checkAuthorizationHeaderNoThrow(`Bearer ${accessToken}`) + + if (currentUser?.rolle == Enums.BenutzerRolle.ADMIN) { + const user = await prisma.benutzer.findUnique({ + where: { + id: userId + } + }) + return user; + } + return null; } \ No newline at end of file diff --git a/src/modules/EmbeddedAuthFlowModule.svelte b/src/modules/EmbeddedAuthFlowModule.svelte index 4c26db3f..7637e0d4 100644 --- a/src/modules/EmbeddedAuthFlowModule.svelte +++ b/src/modules/EmbeddedAuthFlowModule.svelte @@ -6,11 +6,10 @@ export let onLogin: (response: Awaited>) => any; export let email: string = ""; export let password: string = ""; + export let route: "login" | "signup" = "login" - let route: "login" | "signup" = "login" - - const navigate = (target: typeof route) => { - route = target + const navigate = (target: string) => { + route = target as typeof route; } const loginData = { diff --git a/src/modules/KaufabschlussModule.svelte b/src/modules/KaufabschlussModule.svelte deleted file mode 100644 index 1f31a71a..00000000 --- a/src/modules/KaufabschlussModule.svelte +++ /dev/null @@ -1,384 +0,0 @@ - - -
-
-

Ansprechpartner

-
-
- -
- -
- -
-
- - -
- - -
- - -
- - -
-
-
- -
- - -
- - -
- - -
-
-
- -

Rechnungsadresse

-
-
-
- - -
- - -
- - -
-
-
- -
- - -
- - - - - -
- - -
-
-
- -
- - -
- - -
- - -
-
-
- -

Versandadresse

-
-
- - -
-
- -
- - -
- - -
- - -
-
-
- -
- - -
- - - - - -
- - -
-
-
- -

Bezahlmethode

-
- - - - - -
-
- -
-

Zusammenfassung

-
- -
-
-
- Netto - {Math.round(priceTotal * 0.81 * 100) / 100}€ -
-
- 19% MwSt - {Math.round(priceTotal * 0.19 * 100) / 100}}€ -
-
-
- Gesamt - {Math.round(priceTotal)}€ -
-

Mit dem Klick auf "Bestellung Bestätigen" akzeptieren sie unsere AGB und Datenschutzbestimmungen. Sie werden zu ihrem ausgewählten Bezahlprovider weitergeleitet, nach Bezahlung werden sie automatisch zu unserem Portal zurückgeleitet.

- -
-
-
-
diff --git a/src/modules/KundendatenModule.svelte b/src/modules/KundendatenModule.svelte index 2e79158b..a2d71b6b 100644 --- a/src/modules/KundendatenModule.svelte +++ b/src/modules/KundendatenModule.svelte @@ -32,8 +32,12 @@ import { getMaximumDevitationInPercent } from "#client/lib/helpers.js"; import { endEnergieVerbrauchVerbrauchsausweis_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016_Client.js"; import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016_Client.js"; - + import { benutzerSpeichern } from "#client/lib/speichern.js"; + import { benutzerLesen } from "#client/lib/lesen.js"; + import { exclude } from "#lib/exclude.js"; + export let user: Partial; + export let impersonatedUser: Partial | null = null; export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbe | BedarfsausweisWohnen; export let aufnahme: AufnahmeClient; export let objekt: ObjektClient; @@ -42,9 +46,8 @@ export let rechnung: RechnungClient | null = null; export let ausweisart: Enums.Ausweisart; export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal; - 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; @@ -59,9 +62,22 @@ ort = rechnung?.ort || localStorage.getItem("kundendaten.ort") || user.ort || ""; zusatzzeile = rechnung?.zusatzzeile || localStorage.getItem("kundendaten.zusatzzeile") || "" telefon = rechnung?.telefon || localStorage.getItem("kundendaten.telefon") || user.telefon || ""; + } else if (impersonatedUser) { + vorname = impersonatedUser.vorname || ""; + name = impersonatedUser.name || ""; + 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, versand_zusatzzeile: string | undefined, @@ -69,16 +85,13 @@ versand_strasse: string | undefined, versand_plz: string | undefined, versand_ort: string | undefined; - $: { - if (!abweichende_versand_adresse) { - versand_email = email - versand_zusatzzeile = zusatzzeile - versand_empfaenger = empfaenger - versand_strasse = strasse - versand_plz = plz - versand_ort = ort - } - } + + versand_email = "";//Todo Datenbankfeld fehlt noch + versand_zusatzzeile = rechnung?.versand_zusatzzeile ?? zusatzzeile; + versand_empfaenger = rechnung?.versand_empfaenger ?? empfaenger; + versand_strasse = rechnung?.versand_strasse ?? strasse; + versand_plz = rechnung?.versand_plz ?? plz; + versand_ort = rechnung?.versand_ort ?? ort; $: { // Wir speichern jede Änderung an den Kundendaten im localStorage ab. @@ -199,6 +212,12 @@ } 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( { email: email, @@ -206,10 +225,11 @@ strasse: strasse, plz: plz, ort: ort, - versand_empfaenger: versand_empfaenger, - versand_strasse: versand_strasse, - versand_plz: versand_plz, - versand_ort: versand_ort, + 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, telefon: telefon, nachweis_id: result.nachweis_id }, @@ -233,7 +253,7 @@ } } - async function speichern() { + async function speichern(authuser = null) { loginAction = speichern; if (!await validateAccessTokenClient()) { loginOverlayHidden = false; @@ -249,6 +269,62 @@ } else { result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart) } + + if (authuser) { + user = await benutzerLesen(authuser.id); + } + + let resultUser: Awaited> | Awaited> | null = null; + const { passwort, ...baseUser } = impersonatedUser ?? user; + + const benutzerObjekt = { + ...baseUser, + name, + vorname, + telefon + }; + + 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) { addNotification({ dismissable: true, @@ -269,7 +345,7 @@ } } - async function bestellen() { + async function bestellen(authuser = null) { if (!form.checkValidity()) { addNotification({ dismissable: true, @@ -312,6 +388,22 @@ } } + if (authuser) { + user = await benutzerLesen(authuser.id); + } + + let resultUser: Awaited> | Awaited> | null = null; + const { passwort, ...baseUser } = impersonatedUser ?? user; + + const benutzerObjekt = { + ...baseUser, + name, + vorname, + telefon + }; + + resultUser = await benutzerSpeichern(benutzerObjekt); + if (rechnung && rechnung.status === "paid") { window.location.href = "/dashboard" return; @@ -320,6 +412,12 @@ try { 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) { const result = await api.rechnung._id.PATCH.fetch({ bezahlmethode: aktiveBezahlmethode, @@ -328,12 +426,13 @@ strasse: strasse, plz: plz, ort: ort, - versand_empfaenger: versand_empfaenger, - versand_strasse: versand_strasse, - versand_plz: versand_plz, - versand_ort: versand_ort, 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: { id: rechnung.id @@ -358,13 +457,16 @@ strasse: strasse, plz: plz, ort: ort, - versand_empfaenger: versand_empfaenger, - versand_strasse: versand_strasse, - versand_plz: versand_plz, - versand_ort: versand_ort, + 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, telefon: telefon, ausweis_id: ausweis.id, - partner_code + partner_code, + abweichende_versand_adresse: abweichende_versand_adresse }, { headers: { @@ -404,6 +506,7 @@ let form: HTMLFormElement; +{#if !nurRechnungsadresseUpdate}
{/if}
- +{/if}
@@ -702,7 +805,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8 @@ -739,7 +841,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
- + - {#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)}

Bitte untenstehende Punkte bestätigen. Bitte gehen Sie gegebenenfalls zurück zum Formular und überprüfen bzw. korrigieren Ihre Eingaben.

@@ -1054,7 +1156,7 @@ grid-cols-3 sm:grid-cols-5 justify-around justify-items-center items-center" {/if}
- +
Ich habe die AGB und DSGVO im Impressum gelesen und akzeptiert.
@@ -1072,31 +1174,33 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8" - + - {#if rechnung && rechnung.status === "paid"} - - - {:else} - {#if gegAnfrage} + {#if !nurRechnungsadresseUpdate} + {#if rechnung && rechnung.status === "paid"} + bestellen()}>Absenden {:else} - + {#if gegAnfrage} + + {:else} + + {/if} {/if} {/if} @@ -1111,7 +1215,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
- +
diff --git a/src/modules/RegisterModule.svelte b/src/modules/RegisterModule.svelte index 223ff52c..fa49eac4 100644 --- a/src/modules/RegisterModule.svelte +++ b/src/modules/RegisterModule.svelte @@ -13,6 +13,10 @@ export let redirect: string | null = null; + function handleInput(event) { + email = event.target.value.toLowerCase(); + } + async function login(e: SubmitEvent) { e.preventDefault() if (passwort.length < 8) { @@ -83,6 +87,7 @@ name="email" class="input input-bordered text-base text-base-content font-medium" bind:value={email} + on:input={handleInput} required />
diff --git a/src/pages/[partner]/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/index.astro b/src/pages/[partner]/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/index.astro index c7a9b8e2..9979687d 100644 --- a/src/pages/[partner]/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/index.astro +++ b/src/pages/[partner]/angebot-anfragen/bedarfsausweis-gewerbe-anfragen/index.astro @@ -1,7 +1,5 @@ --- 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 { getAufnahme, getBedarfsausweisGewerbe, getBilder, getObjekt, getUnterlagen, getVerbrauchsausweisWohnen } from "#lib/server/db"; 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 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 aufnahme: Aufnahme = {} as Aufnahme; diff --git a/src/pages/[partner]/angebot-anfragen/geg-nachweis-gewerbe-anfragen/index.astro b/src/pages/[partner]/angebot-anfragen/geg-nachweis-gewerbe-anfragen/index.astro index 90f431c6..66a26817 100644 --- a/src/pages/[partner]/angebot-anfragen/geg-nachweis-gewerbe-anfragen/index.astro +++ b/src/pages/[partner]/angebot-anfragen/geg-nachweis-gewerbe-anfragen/index.astro @@ -7,7 +7,7 @@ import GEGNachweisGewerbeModule from "#modules/angebot-anfragen/GEGNachweisGewer const id = Astro.url.searchParams.get("id"); 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 aufnahme: Aufnahme = {} as Aufnahme; diff --git a/src/pages/api/admin/ausstellen.ts b/src/pages/api/admin/ausstellen.ts index c30f00fc..29084cef 100644 --- a/src/pages/api/admin/ausstellen.ts +++ b/src/pages/api/admin/ausstellen.ts @@ -17,7 +17,6 @@ import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { z } from "astro:content"; import { transport } from "#lib/mail.js"; import {Attachment} from "nodemailer/lib/mailer/index.js"; -import { BASE_URI } from "#lib/constants.js"; import { getAnsichtsausweis, getDatenblatt, getAushang } from "#lib/server/ausweis.js"; import { PutObjectCommand } from "@aws-sdk/client-s3"; import { s3Client } from "#lib/s3.js"; @@ -34,7 +33,6 @@ import { getVerbrauchsausweisWohnenKomplett, } from "#lib/server/db.js"; import { PDFDocument } from "pdf-lib"; -import * as fs from 'fs'; export const GET = defineApiRoute({ input: z.object({ diff --git a/src/pages/api/admin/bedarfsausweis-ausstellen.ts b/src/pages/api/admin/bedarfsausweis-ausstellen.ts index 08b9261a..a67e8b02 100644 --- a/src/pages/api/admin/bedarfsausweis-ausstellen.ts +++ b/src/pages/api/admin/bedarfsausweis-ausstellen.ts @@ -197,7 +197,7 @@ export const POST = defineApiRoute({ let filename: string; if (type === "Ausweis") { - filename = `ID_${ausweis.id}_Ausweis.pdf` + filename = `ID_${ausweis.id}_Energieausweis.pdf` } else { filename = `ID_${ausweis.id}_${name}`; } @@ -212,7 +212,7 @@ export const POST = defineApiRoute({ const command = new PutObjectCommand({ Bucket: "ibc-pdfs", - Key: name, + Key: filename, Body: buffer, ACL: "private", }); diff --git a/src/pages/api/auth/refresh-token.ts b/src/pages/api/auth/refresh-token.ts index 3ed57135..2d5b9491 100644 --- a/src/pages/api/auth/refresh-token.ts +++ b/src/pages/api/auth/refresh-token.ts @@ -62,6 +62,7 @@ export const GET = defineApiRoute({ exp: refreshTokenExpiry.valueOf(), }); + console.log("Creating refresh token for user ID:", user.id); const { id } = await prisma.refreshTokens.create({ data: { token: refreshToken, diff --git a/src/pages/api/rechnung/[id].ts b/src/pages/api/rechnung/[id].ts index e19131b3..5f70c5e6 100644 --- a/src/pages/api/rechnung/[id].ts +++ b/src/pages/api/rechnung/[id].ts @@ -16,12 +16,14 @@ export const PATCH = defineApiRoute({ strasse: true, telefon: true, empfaenger: true, + zusatzzeile: true, versand_empfaenger: true, versand_ort: true, versand_plz: true, versand_strasse: true, versand_zusatzzeile: true, - abweichende_versand_adresse: true + abweichende_versand_adresse: true, + email: true }), output: z.object({ checkout_url: z.string().optional(), @@ -31,22 +33,39 @@ export const PATCH = defineApiRoute({ headers: authorizationHeaders, async fetch(input, context, user) { // Wir holen uns die Rechnung - const rechnung = await prisma.rechnung.findUnique({ - where: { - id: context.params.id, - benutzer: { - id: user.id + let rechnung; + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { + rechnung = await prisma.rechnung.findUnique({ + where: { + id: context.params.id, + benutzer: { + id: user.id + } + }, + include: { + bedarfsausweis_gewerbe: true, + bedarfsausweis_wohnen: true, + geg_nachweis_gewerbe: true, + geg_nachweis_wohnen: true, + verbrauchsausweis_gewerbe: true, + verbrauchsausweis_wohnen: true } - }, - include: { - bedarfsausweis_gewerbe: true, - bedarfsausweis_wohnen: true, - geg_nachweis_gewerbe: true, - geg_nachweis_wohnen: true, - verbrauchsausweis_gewerbe: 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) { throw new APIError({ @@ -66,12 +85,14 @@ export const PATCH = defineApiRoute({ strasse: input.strasse, telefon: input.telefon, empfaenger: input.empfaenger, + zusatzzeile: input.zusatzzeile, versand_empfaenger: input.versand_empfaenger, versand_ort: input.versand_ort, versand_plz: input.versand_plz, versand_strasse: input.versand_strasse, versand_zusatzzeile: input.versand_zusatzzeile, abweichende_versand_adresse: input.abweichende_versand_adresse, + email: input.email } }) diff --git a/src/pages/api/ticket/index.ts b/src/pages/api/ticket/index.ts index 1367b309..516a41dc 100644 --- a/src/pages/api/ticket/index.ts +++ b/src/pages/api/ticket/index.ts @@ -57,7 +57,7 @@ export const PUT = defineApiRoute({ labels[category as keyof typeof labels]) || "650e909fdc09629a4d6d495d") url.searchParams.append("key", "e057eb39018368ea96e456c753ac41b4") - url.searchParams.append("idList", "67d75ca7403fd22c49bc7447") + url.searchParams.append("idList", "650303186e721b4bef0c3980") url.searchParams.append("token", "ATTA8b65b3587ab627167038cc32a3460650973eb181cde01dabb208ca1e90ed5467AC06A4F2") // Wir laden das Ticket zu Trello hoch. diff --git a/src/pages/api/user/index.ts b/src/pages/api/user/index.ts index 4c769cc5..ba9f3cbc 100644 --- a/src/pages/api/user/index.ts +++ b/src/pages/api/user/index.ts @@ -5,18 +5,17 @@ import { adminMiddleware, authorizationMiddleware } from "#lib/middleware/author import { hashPassword } from "#lib/password.js"; import { createLexOfficeCustomer } from "#lib/server/lexoffice.js"; import { sendRegisterMail } from "#lib/server/mail/registrierung.js"; -import { prisma } from "#lib/server/prisma.js"; +import { Benutzer, prisma } from "#lib/server/prisma.js"; import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { BenutzerSchema } from "src/generated/zod/benutzer.js"; import { z } from "zod"; +import { Enums } from "#lib/client/prisma.js"; export const POST = defineApiRoute({ input: BenutzerSchema.omit({ - id: true, lex_office_id: true, rolle: true, - created_at: true, - updated_at: true + created_at: true }), middleware: authorizationMiddleware, async fetch(input, context, user) { @@ -24,24 +23,36 @@ export const POST = defineApiRoute({ // TODO: Email wurde geändert, neue Bestätigunsmail schicken. } + const updateData: any = {}; + updateData.id = user.id; + if (input.adresse) updateData.adresse = input.adresse; + if (input.anrede) updateData.anrede = input.anrede; + if (input.email) updateData.email = input.email; + if (input.firma) updateData.firma = input.firma; + if (input.name) updateData.name = input.name; + if (input.vorname) updateData.vorname = input.vorname; + if (input.ort) updateData.ort = input.ort; + if (input.passwort.length != 0) updateData.passwort = hashPassword(input.passwort); + if (input.plz) updateData.plz = input.plz; + if (input.profilbild) updateData.profilbild = input.profilbild; + if (input.telefon) updateData.telefon = input.telefon; + if (input.verified) updateData.telefon = input.verified; + + //Only Admin can update other users + if (user.rolle == Enums.BenutzerRolle.ADMIN && input.id != user.id) { + updateData.id = input.id; + } else if(user.rolle != Enums.BenutzerRolle.ADMIN && input.id != user.id){ + return; + } + await prisma.benutzer.update({ where: { - id: user.id + id: updateData.id }, - data: { - adresse: input.adresse, - anrede: input.anrede, - email: input.email, - firma: input.firma, - name: input.name, - vorname: input.vorname, - ort: input.ort, - passwort: hashPassword(input.passwort), - plz: input.plz, - profilbild: input.profilbild, - telefon: input.telefon, - } - }) + data: updateData + }); + + }, }) @@ -53,9 +64,14 @@ export const GET = defineApiRoute({ email: z.string() })), output: z.array(BenutzerSchema), - middleware: adminMiddleware, + middleware: authorizationMiddleware, async fetch(input, context, admin) { if ("id" in input) { + //Only Admin can read other users + if (admin.rolle != Enums.BenutzerRolle.ADMIN && input.id != admin.id) { + return; + } + const user = await prisma.benutzer.findUnique({ where: { id: input.id @@ -68,6 +84,11 @@ export const GET = defineApiRoute({ return [user]; } else { + //Only admin can read many users + if (admin.rolle != Enums.BenutzerRolle.ADMIN ) { + return; + } + const users = await prisma.benutzer.findMany({ where: { email: { diff --git a/src/pages/dashboard/abrechnung/index.astro b/src/pages/dashboard/abrechnung/index.astro new file mode 100644 index 00000000..d0cbac99 --- /dev/null +++ b/src/pages/dashboard/abrechnung/index.astro @@ -0,0 +1,236 @@ +--- +import AbrechnungTable from "#components/Abrechnung/AbrechnungTable.svelte"; +import BlankLayout from "#layouts/BlankLayout.astro"; +import { extrahiereAusweisAusFeldMitMehrerenAusweisen } from "#lib/server/ausweis"; +import { Enums, prisma } from "#lib/server/prisma"; +import { getCurrentUser } from "#lib/server/user"; +import moment from "moment"; + +const start = moment(Astro.url.searchParams.get("start")); +const end = moment(Astro.url.searchParams.get("end")); + +let startdatum = start.isValid() ? start.toDate() : moment().startOf("month").toDate(); +let enddatum = end.isValid() ? end.toDate() : moment().endOf("month").toDate(); + +const benutzer = await getCurrentUser(Astro); + +if (!benutzer) { + return Astro.redirect("/404"); +} + +const provisionen = { + [Enums.Ausweisart.VerbrauchsausweisWohnen]: 10, + [Enums.Ausweisart.BedarfsausweisWohnen]: 10, + [Enums.Ausweisart.VerbrauchsausweisGewerbe]: 10, +}; + +// $kommission = db()->one("SELECT abr_va, abr_ba, abr_vanw FROM users WHERE resellercode = :resellercode", ["resellercode" => $resellercode]); +// Select every entry from database where user was involved. +let bestellungen; +if (start.isValid() && end.isValid()) { + bestellungen = await prisma.rechnung.findMany({ + where: { + partner_code: "immowelt", + OR: [ + { + verbrauchsausweis_gewerbe: { + ausgestellt: true, + }, + }, + { + bedarfsausweis_wohnen: { + ausgestellt: true, + }, + }, + { + verbrauchsausweis_wohnen: { + ausgestellt: true, + }, + }, + ], + AND: [ + { + created_at: { + gte: startdatum, + }, + }, + { + created_at: { + lte: enddatum, + }, + }, + ], + }, + orderBy: { + created_at: "desc", + }, + include: { + bedarfsausweis_wohnen: { + include: { + aufnahme: { + include: { + objekt: true, + }, + }, + }, + }, + verbrauchsausweis_gewerbe: { + include: { + aufnahme: { + include: { + objekt: true, + }, + }, + }, + }, + verbrauchsausweis_wohnen: { + include: { + aufnahme: { + include: { + objekt: true, + }, + }, + }, + }, + }, + }); +} else { + bestellungen = await prisma.rechnung.findMany({ + where: { + partner_code: "immowelt", + OR: [ + { + verbrauchsausweis_gewerbe: { + ausgestellt: true, + }, + }, + { + bedarfsausweis_wohnen: { + ausgestellt: true, + }, + }, + { + verbrauchsausweis_wohnen: { + ausgestellt: true, + }, + }, + ], + }, + orderBy: { + created_at: "desc", + }, + include: { + bedarfsausweis_wohnen: { + include: { + aufnahme: { + include: { + objekt: true, + }, + }, + }, + }, + verbrauchsausweis_gewerbe: { + include: { + aufnahme: { + include: { + objekt: true, + }, + }, + }, + }, + verbrauchsausweis_wohnen: { + include: { + aufnahme: { + include: { + objekt: true, + }, + }, + }, + }, + }, + }); +} + +// Wann wurde der partner_code zum ersten mal benutzt? +const partnerCodeErstesMal = ( + await prisma.rechnung.findFirst({ + select: { + created_at: true, + }, + where: { + partner_code: "immowelt", + OR: [ + { + verbrauchsausweis_gewerbe: { + ausgestellt: true, + }, + }, + { + bedarfsausweis_wohnen: { + ausgestellt: true, + }, + }, + { + verbrauchsausweis_wohnen: { + ausgestellt: true, + }, + }, + ], + created_at: { + gte: moment().set("year", 2020).set("dayOfYear", 1).toDate(), + }, + }, + orderBy: { + created_at: "asc", + }, + }) +)?.created_at; + +let provision = 0; +const ausweisarten: string[] = []; +for (const bestellung of bestellungen) { + if (bestellung.verbrauchsausweis_wohnen) { + ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisWohnen); + provision += provisionen[Enums.Ausweisart.VerbrauchsausweisWohnen]; + } + if (bestellung.bedarfsausweis_wohnen) { + ausweisarten.push(Enums.Ausweisart.BedarfsausweisWohnen); + provision += provisionen[Enums.Ausweisart.BedarfsausweisWohnen]; + } + if (bestellung.verbrauchsausweis_gewerbe) { + ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisGewerbe); + provision += provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe]; + } +} +--- + + + + extrahiereAusweisAusFeldMitMehrerenAusweisen(bestellung) + )} + {provisionen} + {partnerCodeErstesMal} + startDate={startdatum} + endDate={enddatum} + email={benutzer.email} + client:load + /> + +
+
+
+

+ Abrechnungsbetrag gesamt: {provision} € +

+
+ PDF für letzten Monat generieren. +
+
+
diff --git a/src/pages/dashboard/rechnung/aendern.astro b/src/pages/dashboard/rechnung/aendern.astro new file mode 100644 index 00000000..cfc37b59 --- /dev/null +++ b/src/pages/dashboard/rechnung/aendern.astro @@ -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 | null = null; + +if (user){ + if (user.id !== ausweis.benutzer_id && ausweis.benutzer_id !== undefined){ + impersonatedUser = await getOtherUser(Astro, ausweis.benutzer_id) || {} + } +} +--- + + + \ No newline at end of file diff --git a/src/pages/energieausweis-erstellen/bezahlung.astro b/src/pages/energieausweis-erstellen/bezahlung.astro index ef1a437c..48fda87c 100644 --- a/src/pages/energieausweis-erstellen/bezahlung.astro +++ b/src/pages/energieausweis-erstellen/bezahlung.astro @@ -3,10 +3,11 @@ import { getAusweisartFromId } from "#components/Ausweis/types"; import AusweisLayoutPruefung from "#layouts/AusweisLayoutPruefung.astro"; import { getPrismaAusweisAdapter } from "#lib/server/ausweis"; import { Enums } from "#lib/server/prisma"; -import { getCurrentUser } from "#lib/server/user"; +import { getCurrentUser, getOtherUser } from "#lib/server/user"; import KundendatenModule from "#modules/KundendatenModule.svelte"; import { PaymentStatus } from "@mollie/api-client"; import { AusweisTyp } from "src/generated/enums"; +import { BenutzerClient } from "#components/Ausweis/types.js"; const uid = Astro.url.searchParams.get("uid") @@ -45,8 +46,16 @@ if (!ausweis) { if (ausweis.rechnung.status === PaymentStatus.paid) { return Astro.redirect("/dashboard") } + +let impersonatedUser: Partial | null = null; + +if (user){ + if (user.id !== ausweis.benutzer_id && ausweis.benutzer_id !== undefined){ + impersonatedUser = await getOtherUser(Astro, ausweis.benutzer_id) || {} + } +} --- - + diff --git a/src/pages/heap-snapshot.astro b/src/pages/heap-snapshot.astro new file mode 100644 index 00000000..1c1f49bf --- /dev/null +++ b/src/pages/heap-snapshot.astro @@ -0,0 +1,19 @@ +--- +import { getHeapSnapshot } from "v8"; +import * as fs from "fs"; + +// Create a named heap snapshot +const snapshotStream = getHeapSnapshot(); +const fileName = `heap-${Date.now()}.heapsnapshot`; +const fileStream = fs.createWriteStream(fileName); + +snapshotStream.pipe(fileStream); + +fileStream.on("finish", () => { + console.log(`Heap snapshot saved to ${fileName}`); +}); + +fileStream.on("error", (err) => { + console.error("Error writing heap snapshot:", err); +}); +--- \ No newline at end of file diff --git a/src/pages/kaufabschluss.astro b/src/pages/kaufabschluss.astro deleted file mode 100644 index 524b1dab..00000000 --- a/src/pages/kaufabschluss.astro +++ /dev/null @@ -1,31 +0,0 @@ ---- - -import KaufabschlussModule from "#modules/KaufabschlussModule.svelte"; -import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro"; -import { Enums } from "#lib/client/prisma"; -import { createCaller } from "src/astro-typesafe-api-caller"; - -// Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde. -const uid = Astro.url.searchParams.get("uid"); - -if (!uid) { - return Astro.redirect("/404"); -} - -const caller = createCaller(Astro); - -const ausweis = await caller.v1.verbrauchsausweisWohnen.get({ - uid -}) - -const user = await caller.v1.benutzer.self(); - -if (!ausweis || !user) { - return Astro.redirect("/404"); -} ---- - - - - - diff --git a/src/pages/kundendaten.astro b/src/pages/kundendaten.astro index cab2da8d..7b5a31b6 100644 --- a/src/pages/kundendaten.astro +++ b/src/pages/kundendaten.astro @@ -3,9 +3,10 @@ import KundendatenModule from "#modules/KundendatenModule.svelte"; import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro"; import { Enums } from "#lib/client/prisma"; -import { getCurrentUser } from "#lib/server/user"; +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"; // Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde. @@ -70,9 +71,16 @@ if (!params.has("ausweis") || !params.has("aufnahme") || !params.has("objekt") | } } +let impersonatedUser: Partial | null = null; + +if (user){ + if (user.id !== ausweis.benutzer_id && ausweis.benutzer_id !== undefined){ + impersonatedUser = await getOtherUser(Astro, ausweis.benutzer_id) || {} + } +} --- - + diff --git a/src/pages/pdf/ansichtsausweis.ts b/src/pages/pdf/ansichtsausweis.ts index 5b4028f2..84e1623b 100644 --- a/src/pages/pdf/ansichtsausweis.ts +++ b/src/pages/pdf/ansichtsausweis.ts @@ -45,14 +45,23 @@ export const GET: APIRoute = async (Astro) => { user = await getCurrentUser(Astro) let pdf: Uint8Array | null = null; - if (/[A-Z]{2}[0-9]{8}/.test(ausweis.id)) { - const id = ausweis.id.match(/[A-Z]{2}([0-9]{8})/) as RegExpMatchArray - // Dieser Ausweis wurde mit der alten Version erstellt, das PDF sollte bereits existieren. - pdf = await getS3File("ibc-pdfs", `ID_${id[1]}_Energieausweis.pdf`) - } else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) { - pdf = await pdfVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt); - } else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) { - pdf = await pdfVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt); + + if (ausweis.ausgestellt) { + if (/[A-Z]{2}[0-9]{8}/.test(ausweis.id)) { + const id = ausweis.id.match(/[A-Z]{2}([0-9]{8})/) as RegExpMatchArray + // Dieser Ausweis wurde mit der alten Version erstellt, das PDF sollte bereits existieren. + pdf = await getS3File("ibc-pdfs", `ID_${id[1]}_Energieausweis.pdf`) + } else { + pdf = await getS3File("ibc-pdfs", `ID_${ausweis.id}_Energieausweis.pdf`) + } + } else { + if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) { + pdf = await pdfVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt); + } else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) { + pdf = await pdfVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt); + } else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) { + //todo + } } return new Response(pdf, { diff --git a/wipe-database.bash b/wipe-database.bash index b25a5c46..13d4c8a3 100644 --- a/wipe-database.bash +++ b/wipe-database.bash @@ -9,6 +9,22 @@ DB_NAME="main" TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") 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.' 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 fi -echo "📦 Backup wird erstellt..." -docker exec -t "$CONTAINER_NAME" pg_dumpall -c -U "$DB_USER" | brotli > "$FILE_NAME" -echo "✅ Backup abgeschlossen: $FILE_NAME" +if [[ "$SKIP_BACKUP" == false ]]; then + echo "📦 Backup wird erstellt..." + 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..." @@ -34,6 +52,7 @@ DECLARE r RECORD; sql TEXT := ''; BEGIN + -- Truncate all tables FOR r IN SELECT tablename FROM pg_tables @@ -42,6 +61,15 @@ BEGIN sql := sql || FORMAT('TRUNCATE 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; + EXECUTE sql; END $$;