From ac502169a9e416922af5aa6bc1cddbc5328558e2 Mon Sep 17 00:00:00 2001 From: Robert Jagtiani Date: Sun, 3 Aug 2025 22:34:40 +0200 Subject: [PATCH 1/5] landingpage partner header menu und Titel fix --- src/astro-typesafe-api-caller.ts | 12 +-- .../design/header/AusweisHeaderPartner.astro | 79 +++++++------------ 2 files changed, 33 insertions(+), 58 deletions(-) diff --git a/src/astro-typesafe-api-caller.ts b/src/astro-typesafe-api-caller.ts index 4c07b62c..69727bca 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-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"), + "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"), "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"), + "objekt": await import("../src/pages/api/objekt/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/components/design/header/AusweisHeaderPartner.astro b/src/components/design/header/AusweisHeaderPartner.astro index ec9328f7..f0f87051 100644 --- a/src/components/design/header/AusweisHeaderPartner.astro +++ b/src/components/design/header/AusweisHeaderPartner.astro @@ -39,63 +39,38 @@ const isNET = pathname.includes("immonet");
- + + + + +
@@ -186,7 +161,7 @@ background-repeat:no-repeat; background-position:right;`} font-family: "immo Sans"; font-weight:400; - div{@apply w-fit bg-white/75 py-6 px-16 rounded-lg ring-2 ring-black/15 text-[1.45rem];box-shadow:8px 8px 16px rgba(0,0,0,0.5);} + div{@apply w-fit bg-white/75 py-6 px-4 md:px-16 rounded-lg ring-2 ring-black/15 text-[1.45rem];box-shadow:8px 8px 16px rgba(0,0,0,0.5);} } .header-button { From 641fdf62134e00af4b773fa360be658991d706f0 Mon Sep 17 00:00:00 2001 From: Robert Jagtiani Date: Sun, 3 Aug 2025 22:47:02 +0200 Subject: [PATCH 2/5] Titel PY- --- src/components/design/header/AusweisHeaderPartner.astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/design/header/AusweisHeaderPartner.astro b/src/components/design/header/AusweisHeaderPartner.astro index f0f87051..7e7a8bdf 100644 --- a/src/components/design/header/AusweisHeaderPartner.astro +++ b/src/components/design/header/AusweisHeaderPartner.astro @@ -70,7 +70,7 @@ const isNET = pathname.includes("immonet");
From f56684a6e8df7902c90be8b12d10cb95e8a9c4de Mon Sep 17 00:00:00 2001 From: Moritz Utcke Date: Mon, 4 Aug 2025 17:23:04 -0400 Subject: [PATCH 3/5] Abrechnung Generierung --- backup-database.bash | 9 +- bun.lock | 33 +++-- package.json | 3 +- .../20250804180940_provisionen/migration.sql | 49 +++++++ .../migration.sql | 15 ++ prisma/schema/Benutzer.prisma | 2 + prisma/schema/Provisionen.prisma | 10 ++ recover-db-dev.bash | 6 +- src/astro-typesafe-api-caller.ts | 10 +- .../Abrechnung/AbrechnungTable.svelte | 117 ++++++++------- .../Dashboard/DashboardSidebar.svelte | 6 +- src/components/Tickets/TicketPopup.svelte | 10 +- src/generated/enums.ts | 1 + src/generated/zod/bedarfsausweiswohnen.ts | 16 +-- src/generated/zod/index.ts | 1 + src/generated/zod/provisionen.ts | 12 ++ src/pages/api/ticket/index.ts | 6 +- src/pages/dashboard/abrechnung/index.astro | 46 +++--- .../dashboard/abrechnung/monatlich.pdf.astro | 136 ++++++++++++++++++ src/pages/dashboard/objekte/index.astro | 2 +- src/templates/pdf/abrechnung.handlebars | 84 +++++++++++ 21 files changed, 459 insertions(+), 115 deletions(-) create mode 100644 prisma/migrations/20250804180940_provisionen/migration.sql create mode 100644 prisma/migrations/20250804182851_provisionen_ausweisart/migration.sql create mode 100644 prisma/schema/Provisionen.prisma create mode 100644 src/generated/zod/provisionen.ts create mode 100644 src/pages/dashboard/abrechnung/monatlich.pdf.astro create mode 100644 src/templates/pdf/abrechnung.handlebars diff --git a/backup-database.bash b/backup-database.bash index fee2a70d..5348a744 100644 --- a/backup-database.bash +++ b/backup-database.bash @@ -2,6 +2,7 @@ FILE_NAME=data-dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.br FILE_NAME_COMPLETE=full-dump_`date +%Y-%m-%d"_"%H_%M_%S`.sql.br +DATABASE_NAME=database # Das wird benötigt für AWS Ionos Kompatibilität. export AWS_REQUEST_CHECKSUM_CALCULATION=when_required @@ -11,19 +12,15 @@ export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required # IMPORTANT: Dieser Befehl benötigt das `ionos` Profil, sonst wird er nicht funktionieren. # Das Profil kann mit `aws configure --profile ionos` erstellt werden. # 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 $DATABASE_NAME 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-3.ionoscloud.com --storage-class STANDARD echo "Uploaded $FILE_NAME" -docker exec -t online-energieausweis-database-1 pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE +docker exec -t $DATABASE_NAME 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 bb6cacf8..0af6ee99 100644 --- a/bun.lock +++ b/bun.lock @@ -27,6 +27,7 @@ "express": "^4.21.2", "flag-icons": "^6.15.0", "fontkit": "^2.0.4", + "handlebars": "^4.7.8", "highlight.run": "^9.14.0", "is-base64": "^1.1.0", "js-cookie": "^3.0.5", @@ -39,7 +40,7 @@ "nodemailer": "^6.10.0", "pdf-lib": "^1.17.1", "postcss-nested": "^7.0.2", - "puppeteer": "^24.7.2", + "puppeteer": "^24.15.0", "radix-svelte-icons": "^1.0.0", "sass": "^1.83.4", "sharp": "^0.33.5", @@ -524,7 +525,7 @@ "@proload/core": ["@proload/core@0.3.3", "", { "dependencies": { "deepmerge": "^4.2.2", "escalade": "^3.1.1" } }, "sha512-7dAFWsIK84C90AMl24+N/ProHKm4iw0akcnoKjRvbfHifJZBLhaDsDus1QJmhG12lXj4e/uB/8mB/0aduCW+NQ=="], - "@puppeteer/browsers": ["@puppeteer/browsers@2.10.2", "", { "dependencies": { "debug": "^4.4.0", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", "semver": "^7.7.1", "tar-fs": "^3.0.8", "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" } }, "sha512-i4Ez+s9oRWQbNjtI/3+jxr7OH508mjAKvza0ekPJem0ZtmsYHP3B5dq62+IaBHKaGCOuqJxXzvFLUhJvQ6jtsQ=="], + "@puppeteer/browsers": ["@puppeteer/browsers@2.10.6", "", { "dependencies": { "debug": "^4.4.1", "extract-zip": "^2.0.1", "progress": "^2.0.3", "proxy-agent": "^6.5.0", "semver": "^7.7.2", "tar-fs": "^3.1.0", "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" } }, "sha512-pHUn6ZRt39bP3698HFQlu2ZHCkS/lPcpv7fVQcGBSzNNygw171UXAKrCUhy+TEMw4lEttOKDgNpb04hwUAJeiQ=="], "@rc-component/async-validator": ["@rc-component/async-validator@5.0.4", "", { "dependencies": { "@babel/runtime": "^7.24.4" } }, "sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg=="], @@ -1060,7 +1061,7 @@ "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], - "chromium-bidi": ["chromium-bidi@4.1.1", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-biR7t4vF3YluE6RlMSk9IWk+b9U+WWyzHp+N2pL9vRTk+UXHYRTVp7jTK58ZNzMLBgoLMHY4QyJMbeuw3eKxqg=="], + "chromium-bidi": ["chromium-bidi@7.2.0", "", { "dependencies": { "mitt": "^3.0.1", "zod": "^3.24.1" }, "peerDependencies": { "devtools-protocol": "*" } }, "sha512-gREyhyBstermK+0RbcJLbFhcQctg92AGgDe/h/taMJEOLRdtSswBAO9KmvltFSQWgM2LrwWu5SIuEUbdm3JsyQ=="], "ci-info": ["ci-info@4.1.0", "", {}, "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A=="], @@ -1244,7 +1245,7 @@ "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], - "devtools-protocol": ["devtools-protocol@0.0.1425554", "", {}, "sha512-uRfxR6Nlzdzt0ihVIkV+sLztKgs7rgquY/Mhcv1YNCWDh5IZgl5mnn2aeEnW5stYTE0wwiF4RYVz8eMEpV1SEw=="], + "devtools-protocol": ["devtools-protocol@0.0.1464554", "", {}, "sha512-CAoP3lYfwAGQTaAXYvA6JZR0fjGUb7qec1qf4mToyoH2TZgUFeIqYcjh6f9jNuhHfuZiEdH+PONHYrLhRQX6aw=="], "dezalgo": ["dezalgo@1.0.4", "", { "dependencies": { "asap": "^2.0.0", "wrappy": "1" } }, "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig=="], @@ -1518,6 +1519,8 @@ "h3": ["h3@1.14.0", "", { "dependencies": { "cookie-es": "^1.2.2", "crossws": "^0.3.2", "defu": "^6.1.4", "destr": "^2.0.3", "iron-webcrypto": "^1.2.1", "ohash": "^1.1.4", "radix3": "^1.1.2", "ufo": "^1.5.4", "uncrypto": "^0.1.3", "unenv": "^1.10.0" } }, "sha512-ao22eiONdgelqcnknw0iD645qW0s9NnrJHr5OBz4WOMdBdycfSas1EQf1wXRsm+PcB2Yoj43pjBPwqIpJQTeWg=="], + "handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="], + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], @@ -1980,6 +1983,8 @@ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + "neotraverse": ["neotraverse@0.6.18", "", {}, "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA=="], "netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="], @@ -2190,9 +2195,9 @@ "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], - "puppeteer": ["puppeteer@24.7.2", "", { "dependencies": { "@puppeteer/browsers": "2.10.2", "chromium-bidi": "4.1.1", "cosmiconfig": "^9.0.0", "devtools-protocol": "0.0.1425554", "puppeteer-core": "24.7.2", "typed-query-selector": "^2.12.0" }, "bin": { "puppeteer": "lib/cjs/puppeteer/node/cli.js" } }, "sha512-ifYqoY6wGs0yZeFuFPn8BE9FhuveXkarF+eO18I2e/axdoCh4Qh1AE+qXdJBhdaeoPt6eRNTY4Dih29Jbq8wow=="], + "puppeteer": ["puppeteer@24.15.0", "", { "dependencies": { "@puppeteer/browsers": "2.10.6", "chromium-bidi": "7.2.0", "cosmiconfig": "^9.0.0", "devtools-protocol": "0.0.1464554", "puppeteer-core": "24.15.0", "typed-query-selector": "^2.12.0" }, "bin": { "puppeteer": "lib/cjs/puppeteer/node/cli.js" } }, "sha512-HPSOTw+DFsU/5s2TUUWEum9WjFbyjmvFDuGHtj2X4YUz2AzOzvKMkT3+A3FR+E+ZefiX/h3kyLyXzWJWx/eMLQ=="], - "puppeteer-core": ["puppeteer-core@24.7.2", "", { "dependencies": { "@puppeteer/browsers": "2.10.2", "chromium-bidi": "4.1.1", "debug": "^4.4.0", "devtools-protocol": "0.0.1425554", "typed-query-selector": "^2.12.0", "ws": "^8.18.1" } }, "sha512-P9pZyTmJqKODFCnkZgemCpoFA4LbAa8+NumHVQKyP5X9IgdNS1ZnAnIh1sMAwhF8/xEUGf7jt+qmNLlKieFw1Q=="], + "puppeteer-core": ["puppeteer-core@24.15.0", "", { "dependencies": { "@puppeteer/browsers": "2.10.6", "chromium-bidi": "7.2.0", "debug": "^4.4.1", "devtools-protocol": "0.0.1464554", "typed-query-selector": "^2.12.0", "ws": "^8.18.3" } }, "sha512-2iy0iBeWbNyhgiCGd/wvGrDSo73emNFjSxYOcyAqYiagkYt5q4cPfVXaVDKBsukgc2fIIfLAalBZlaxldxdDYg=="], "qs": ["qs@6.13.0", "", { "dependencies": { "side-channel": "^1.0.6" } }, "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg=="], @@ -2566,7 +2571,7 @@ "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], - "tar-fs": ["tar-fs@3.0.8", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg=="], + "tar-fs": ["tar-fs@3.1.0", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-5Mty5y/sOF1YWj1J6GiBodjlDc05CUR8PKXrsnFAiSG0xA+GHeWLovaZPYUDXkH/1iKRf2+M5+OrRgzC7O9b7w=="], "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], @@ -2666,6 +2671,8 @@ "ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="], + "uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="], + "uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="], "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], @@ -2764,13 +2771,15 @@ "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + "wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "ws": ["ws@8.18.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w=="], + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], "xml-crypto": ["xml-crypto@6.0.0", "", { "dependencies": { "@xmldom/is-dom-node": "^1.0.1", "@xmldom/xmldom": "^0.8.10", "xpath": "^0.0.33" } }, "sha512-L3RgnkaDrHaYcCnoENv4Idzt1ZRj5U1z1BDH98QdDTQfssScx8adgxhd9qwyYo+E3fXbQZjEQH7aiXHLVgxGvw=="], @@ -2870,7 +2879,9 @@ "@prisma/schema-files-loader/fs-extra": ["fs-extra@11.1.1", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ=="], - "@puppeteer/browsers/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="], + "@puppeteer/browsers/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + + "@puppeteer/browsers/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], @@ -2968,6 +2979,8 @@ "gray-matter/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + "handlebars/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + "hasha/type-fest": ["type-fest@0.8.1", "", {}, "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="], "ignore-walk/minimatch": ["minimatch@5.1.6", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g=="], @@ -3066,6 +3079,8 @@ "proxy-agent/proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + "puppeteer-core/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + "rc-align/rc-util": ["rc-util@4.21.1", "", { "dependencies": { "add-dom-event-listener": "^1.1.0", "prop-types": "^15.5.10", "react-is": "^16.12.0", "react-lifecycles-compat": "^3.0.4", "shallowequal": "^1.1.0" } }, "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg=="], "rc-animate/rc-util": ["rc-util@4.21.1", "", { "dependencies": { "add-dom-event-listener": "^1.1.0", "prop-types": "^15.5.10", "react-is": "^16.12.0", "react-lifecycles-compat": "^3.0.4", "shallowequal": "^1.1.0" } }, "sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg=="], diff --git a/package.json b/package.json index 96dbcac3..12e5f6fd 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "express": "^4.21.2", "flag-icons": "^6.15.0", "fontkit": "^2.0.4", + "handlebars": "^4.7.8", "highlight.run": "^9.14.0", "is-base64": "^1.1.0", "js-cookie": "^3.0.5", @@ -53,7 +54,7 @@ "nodemailer": "^6.10.0", "pdf-lib": "^1.17.1", "postcss-nested": "^7.0.2", - "puppeteer": "^24.7.2", + "puppeteer": "^24.15.0", "radix-svelte-icons": "^1.0.0", "sass": "^1.83.4", "sharp": "^0.33.5", diff --git a/prisma/migrations/20250804180940_provisionen/migration.sql b/prisma/migrations/20250804180940_provisionen/migration.sql new file mode 100644 index 00000000..d965ea7d --- /dev/null +++ b/prisma/migrations/20250804180940_provisionen/migration.sql @@ -0,0 +1,49 @@ +/* + Warnings: + + - The `fenster_art_1` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `fenster_art_2` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `dachfenster_art` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `haustuer_art` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `dach_daemmung` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `decke_daemmung` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `aussenwand_daemmung` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - The `boden_daemmung` column on the `BedarfsausweisWohnen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + +*/ +-- AlterEnum +ALTER TYPE "BenutzerRolle" ADD VALUE 'RESELLER'; + +-- AlterTable +ALTER TABLE "BedarfsausweisWohnen" DROP COLUMN "fenster_art_1", +ADD COLUMN "fenster_art_1" DOUBLE PRECISION, +DROP COLUMN "fenster_art_2", +ADD COLUMN "fenster_art_2" DOUBLE PRECISION, +DROP COLUMN "dachfenster_art", +ADD COLUMN "dachfenster_art" DOUBLE PRECISION, +DROP COLUMN "haustuer_art", +ADD COLUMN "haustuer_art" DOUBLE PRECISION, +DROP COLUMN "dach_daemmung", +ADD COLUMN "dach_daemmung" DOUBLE PRECISION, +DROP COLUMN "decke_daemmung", +ADD COLUMN "decke_daemmung" DOUBLE PRECISION, +DROP COLUMN "aussenwand_daemmung", +ADD COLUMN "aussenwand_daemmung" DOUBLE PRECISION, +DROP COLUMN "boden_daemmung", +ADD COLUMN "boden_daemmung" DOUBLE PRECISION; + +-- CreateTable +CREATE TABLE "Provisionen" ( + "id" TEXT NOT NULL, + "ausweisart" TEXT NOT NULL, + "provision_prozent" DOUBLE PRECISION NOT NULL, + "provision_betrag" DOUBLE PRECISION NOT NULL, + "benutzer_id" VARCHAR(11), + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL, + + CONSTRAINT "Provisionen_pkey" PRIMARY KEY ("id") +); + +-- AddForeignKey +ALTER TABLE "Provisionen" ADD CONSTRAINT "Provisionen_benutzer_id_fkey" FOREIGN KEY ("benutzer_id") REFERENCES "benutzer"("id") ON DELETE SET NULL ON UPDATE CASCADE; diff --git a/prisma/migrations/20250804182851_provisionen_ausweisart/migration.sql b/prisma/migrations/20250804182851_provisionen_ausweisart/migration.sql new file mode 100644 index 00000000..a4a2d9a7 --- /dev/null +++ b/prisma/migrations/20250804182851_provisionen_ausweisart/migration.sql @@ -0,0 +1,15 @@ +/* + Warnings: + + - The primary key for the `Provisionen` table will be changed. If it partially fails, the table could be left without primary key constraint. + - The `id` column on the `Provisionen` table would be dropped and recreated. This will lead to data loss if there is data in the column. + - Changed the type of `ausweisart` on the `Provisionen` table. No cast exists, the column would be dropped and recreated, which cannot be done if there is data, since the column is required. + +*/ +-- AlterTable +ALTER TABLE "Provisionen" DROP CONSTRAINT "Provisionen_pkey", +DROP COLUMN "id", +ADD COLUMN "id" SERIAL NOT NULL, +DROP COLUMN "ausweisart", +ADD COLUMN "ausweisart" "Ausweisart" NOT NULL, +ADD CONSTRAINT "Provisionen_pkey" PRIMARY KEY ("id"); diff --git a/prisma/schema/Benutzer.prisma b/prisma/schema/Benutzer.prisma index 7a646d66..a4eb8ffe 100644 --- a/prisma/schema/Benutzer.prisma +++ b/prisma/schema/Benutzer.prisma @@ -2,6 +2,7 @@ enum BenutzerRolle { USER ADMIN + RESELLER } model Benutzer { @@ -50,6 +51,7 @@ model Benutzer { events Event[] @@map("benutzer") + Provisionen Provisionen[] } diff --git a/prisma/schema/Provisionen.prisma b/prisma/schema/Provisionen.prisma new file mode 100644 index 00000000..5921048f --- /dev/null +++ b/prisma/schema/Provisionen.prisma @@ -0,0 +1,10 @@ +model Provisionen { + id Int @id @default(autoincrement()) + ausweisart Ausweisart + provision_prozent Float + provision_betrag Float + benutzer_id String? @db.VarChar(11) + benutzer Benutzer? @relation(fields: [benutzer_id], references: [id]) + created_at DateTime @default(now()) + updated_at DateTime @updatedAt +} \ No newline at end of file diff --git a/recover-db-dev.bash b/recover-db-dev.bash index 110a1352..bc278caf 100644 --- a/recover-db-dev.bash +++ b/recover-db-dev.bash @@ -54,4 +54,8 @@ docker exec -i "online-energieausweis-database-1" env PGPASSWORD="hHMP8cd^N3SnzG echo "✅ Import complete." # === Optional: Clean up -rm "$FILENAME" "$SQL_FILE" \ No newline at end of file +# If custom file was provided, do not delete it +if [ -z "$CUSTOM_FILE" ]; then + echo "🧹 Cleaning up downloaded files..." + rm "$FILENAME" "$SQL_FILE" +fi \ No newline at end of file diff --git a/src/astro-typesafe-api-caller.ts b/src/astro-typesafe-api-caller.ts index 69727bca..eac47bb0 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"), + "aufnahme": await import("../src/pages/api/aufnahme/index.ts"), "auth/access-token": await import("../src/pages/api/auth/access-token.ts"), "auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"), "auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"), - "bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"), - "bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/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"), + "bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"), + "bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/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"), + "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"), - "objekt": await import("../src/pages/api/objekt/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/components/Abrechnung/AbrechnungTable.svelte b/src/components/Abrechnung/AbrechnungTable.svelte index dfbe44d9..c43f4495 100644 --- a/src/components/Abrechnung/AbrechnungTable.svelte +++ b/src/components/Abrechnung/AbrechnungTable.svelte @@ -1,13 +1,14 @@
@@ -89,9 +89,9 @@
diff --git a/src/generated/enums.ts b/src/generated/enums.ts index 791c1681..d52a9c21 100644 --- a/src/generated/enums.ts +++ b/src/generated/enums.ts @@ -19,6 +19,7 @@ export type Lueftungskonzept = (typeof Lueftungskonzept)[keyof typeof Lueftungsk export const BenutzerRolle = { USER: "USER", ADMIN: "ADMIN", + RESELLER: "RESELLER", } as const; export type BenutzerRolle = (typeof BenutzerRolle)[keyof typeof BenutzerRolle]; diff --git a/src/generated/zod/bedarfsausweiswohnen.ts b/src/generated/zod/bedarfsausweiswohnen.ts index a0159ec7..2abcdb06 100644 --- a/src/generated/zod/bedarfsausweiswohnen.ts +++ b/src/generated/zod/bedarfsausweiswohnen.ts @@ -38,19 +38,19 @@ export const BedarfsausweisWohnenSchema = z.object({ volumen: z.number().nullish(), dicht: z.boolean().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_art_2: z.string().nullish(), + fenster_art_2: z.number().nullish(), dachfenster_flaeche: z.number().nullish(), - dachfenster_art: z.string().nullish(), + dachfenster_art: z.number().nullish(), haustuer_flaeche: z.number().nullish(), - haustuer_art: z.string().nullish(), + haustuer_art: z.number().nullish(), dach_bauart: z.string().nullish(), decke_bauart: z.string().nullish(), - dach_daemmung: z.string().nullish(), - decke_daemmung: z.string().nullish(), - aussenwand_daemmung: z.string().nullish(), - boden_daemmung: z.string().nullish(), + dach_daemmung: z.number().nullish(), + decke_daemmung: z.number().nullish(), + aussenwand_daemmung: z.number().nullish(), + boden_daemmung: z.number().nullish(), aussenwand_bauart: z.string().nullish(), boden_bauart: z.string().nullish(), warmwasser_verteilung: z.string().nullish(), diff --git a/src/generated/zod/index.ts b/src/generated/zod/index.ts index 37875cdf..3ad91929 100644 --- a/src/generated/zod/index.ts +++ b/src/generated/zod/index.ts @@ -12,6 +12,7 @@ export * from "./gegnachweiswohnen" export * from "./klimafaktoren" export * from "./objekt" export * from "./postleitzahlen" +export * from "./provisionen" export * from "./rechnung" export * from "./refreshtokens" export * from "./tickets" diff --git a/src/generated/zod/provisionen.ts b/src/generated/zod/provisionen.ts new file mode 100644 index 00000000..1633010f --- /dev/null +++ b/src/generated/zod/provisionen.ts @@ -0,0 +1,12 @@ +import * as z from "zod" +import { Ausweisart } from "@prisma/client" + +export const ProvisionenSchema = z.object({ + id: z.number().int(), + ausweisart: z.nativeEnum(Ausweisart), + provision_prozent: z.number(), + provision_betrag: z.number(), + benutzer_id: z.string().nullish(), + created_at: z.date(), + updated_at: z.date(), +}) diff --git a/src/pages/api/ticket/index.ts b/src/pages/api/ticket/index.ts index 516a41dc..8b564ee1 100644 --- a/src/pages/api/ticket/index.ts +++ b/src/pages/api/ticket/index.ts @@ -50,15 +50,15 @@ export const PUT = defineApiRoute({ const url = new URL("https://api.trello.com/1/cards") url.searchParams.append("name", input.titel) - url.searchParams.append("desc", `User: ${input.email}\n\nDescription: ${input.beschreibung}\n\nCategory: ${category}`) + url.searchParams.append("desc", `User: ${input.email}\n\nDescription: ${input.beschreibung}\n\nKategorie: ${category}\n\nTelefon: ${(input.metadata as Record).telefon || "Nicht angegeben"}`) url.searchParams.append("pos", "top") url.searchParams.append("idLabels", (category && labels[category as keyof typeof labels]) || "650e909fdc09629a4d6d495d") url.searchParams.append("key", "e057eb39018368ea96e456c753ac41b4") - url.searchParams.append("idList", "650303186e721b4bef0c3980") - url.searchParams.append("token", "ATTA8b65b3587ab627167038cc32a3460650973eb181cde01dabb208ca1e90ed5467AC06A4F2") + url.searchParams.append("idList", "67d75ca7403fd22c49bc7447") + url.searchParams.append("token", "ATTA6f1774d98472db1897a2373ee7b55ab15f218c2445b6609dfef3071fe5203a90DB15678A") // Wir laden das Ticket zu Trello hoch. const result = await fetch(url, { diff --git a/src/pages/dashboard/abrechnung/index.astro b/src/pages/dashboard/abrechnung/index.astro index d0cbac99..bcedfb34 100644 --- a/src/pages/dashboard/abrechnung/index.astro +++ b/src/pages/dashboard/abrechnung/index.astro @@ -18,12 +18,6 @@ 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; @@ -152,12 +146,13 @@ if (start.isValid() && end.isValid()) { } // Wann wurde der partner_code zum ersten mal benutzt? -const partnerCodeErstesMal = ( - await prisma.rechnung.findFirst({ - select: { - created_at: true, - }, - where: { +if (!startdatum) { + startdatum = ( + await prisma.rechnung.findFirst({ + select: { + created_at: true, + }, + where: { partner_code: "immowelt", OR: [ { @@ -184,22 +179,30 @@ const partnerCodeErstesMal = ( created_at: "asc", }, }) -)?.created_at; +)?.created_at || moment().startOf("month").toDate(); +} + + +const provisionen = await prisma.provisionen.findMany({ + where: { + benutzer_id: benutzer.id + } +}) 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]; + provision += provisionen.find((p) => p.ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen)?.provision_betrag || 0; } if (bestellung.bedarfsausweis_wohnen) { ausweisarten.push(Enums.Ausweisart.BedarfsausweisWohnen); - provision += provisionen[Enums.Ausweisart.BedarfsausweisWohnen]; + provision += provisionen.find((p) => p.ausweisart === Enums.Ausweisart.BedarfsausweisWohnen)?.provision_betrag || 0; } if (bestellung.verbrauchsausweis_gewerbe) { ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisGewerbe); - provision += provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe]; + provision += provisionen.find((p) => p.ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe)?.provision_betrag || 0; } } --- @@ -210,9 +213,8 @@ for (const bestellung of bestellungen) { extrahiereAusweisAusFeldMitMehrerenAusweisen(bestellung) )} {provisionen} - {partnerCodeErstesMal} - startDate={startdatum} - endDate={enddatum} + startdatum={startdatum} + enddatum={enddatum} email={benutzer.email} client:load /> @@ -220,15 +222,15 @@ for (const bestellung of bestellungen) {
-

- Abrechnungsbetrag gesamt: {provision} € +

+ Abrechnungsbetrag gesamt: {provision.toFixed(2)} €

PDF für letzten Monat generieren.
diff --git a/src/pages/dashboard/abrechnung/monatlich.pdf.astro b/src/pages/dashboard/abrechnung/monatlich.pdf.astro new file mode 100644 index 00000000..66bd9f6f --- /dev/null +++ b/src/pages/dashboard/abrechnung/monatlich.pdf.astro @@ -0,0 +1,136 @@ +--- +import abrechnungTemplateHTML from "../../../templates/pdf/abrechnung.handlebars?raw"; +import puppeteer from "puppeteer"; +import Handlebars from "handlebars"; +import moment from "moment"; +import { getCurrentUser } from "#lib/server/user"; +import { prisma } from "#lib/server/prisma"; +import { extrahiereAusweisAusFeldMitMehrerenAusweisen } from "#lib/server/ausweis"; + +const datum = moment(Astro.url.searchParams.get("d")); +const benutzer = await getCurrentUser(Astro); + +if (!benutzer) { + return Astro.redirect("/404"); +} + +let 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: datum.startOf("month").toDate(), + }, + }, + { + created_at: { + lte: datum.endOf("month").toDate(), + }, + }, + ], + }, + 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, + }, + }, + }, + }, + }, +}); + +const provisionen = await prisma.provisionen.findMany({ + where: { + benutzer_id: benutzer.id + } +}) + +const ausweisBestellungen = bestellungen.map(bestellung => extrahiereAusweisAusFeldMitMehrerenAusweisen(bestellung)); + +console.log(ausweisBestellungen); + + +const browser = await puppeteer.launch({ + headless: true, + args: ["--no-sandbox", "--disable-setuid-sandbox"], +}); +const page = await browser.newPage(); + +// Wir splitten die Daten in Blöcke auf, der erste Block hat 11 Einträge, die folgenden Blöcke haben 15 Einträge. + +const blocks = []; +const firstBlock = ausweisBestellungen.slice(0, 16); +const remainingBlocks = ausweisBestellungen.slice(16); + +blocks.push(firstBlock); +for (let i = 0; i < remainingBlocks.length; i += 20) { + blocks.push(remainingBlocks.slice(i, i + 20)); +} + +Handlebars.registerHelper("get-provision-prozent", function (ausweisart) { + const provisionEintrag = provisionen.find((p) => p.ausweisart === ausweisart); + return provisionEintrag ? provisionEintrag.provision_prozent : 0; +}); + +Handlebars.registerHelper("get-provision-betrag", function (ausweisart) { + const provisionEintrag = provisionen.find((p) => p.ausweisart === ausweisart); + return provisionEintrag ? provisionEintrag.provision_betrag.toFixed(2) : "0.00"; +}); + +const template = Handlebars.compile(abrechnungTemplateHTML); +const html = template({ monat: datum.format("MMMM YYYY"), bestellungen: blocks }); +await page.goto(`data:text/html;charset=UTF-8,${encodeURIComponent(html)}`, { + waitUntil: "networkidle0", +}); +const pdf = await page.pdf({ path: "abrechnung.pdf", format: "A4" }); +await browser.close(); + +return new Response(pdf, { + headers: { + "Content-Type": "application/pdf", + "Content-Disposition": "attachment; filename=abrechnung.pdf", + }, +}); +--- diff --git a/src/pages/dashboard/objekte/index.astro b/src/pages/dashboard/objekte/index.astro index 2985d835..d1216236 100644 --- a/src/pages/dashboard/objekte/index.astro +++ b/src/pages/dashboard/objekte/index.astro @@ -23,7 +23,7 @@ const totalPageCount = await prisma.aufnahme.count({ : {}, }); -if (page < 1 || page > totalPageCount) { +if (page < 1 || page > totalPageCount && totalPageCount > 0) { return Astro.redirect("/dashboard/objekte?p=1"); } diff --git a/src/templates/pdf/abrechnung.handlebars b/src/templates/pdf/abrechnung.handlebars new file mode 100644 index 00000000..457a37c8 --- /dev/null +++ b/src/templates/pdf/abrechnung.handlebars @@ -0,0 +1,84 @@ + + + + + + Abrechnung + + + + {{#each bestellungen}} +
+ +
+

fon 040 · 209339850

+

fax 040 · 209339859

+

online-energieausweis.org

+
+
+
+ {{#if @first}} +
+
+

IB Cornelsen · Katendeich 5A · 21035 Hamburg

+
+
+

Immowelt GmbH

+

Nordostpark 3-5

+

90411 Nürnberg

+
+
+ {{/if}} +
+ {{#if @first}} +
+

Erzielte Conversions {{ @root.monat }}

+

Erstellt am 16.11.23

+
+ {{/if}} + + + + + + + + + + + + {{#each this}} + + {{#with ausweis}} + + + {{/with}} + + {{#with ausweis}} + + + {{/with}} + + {{/each}} + +
ID - DatumProduktProduktpreisProvision in %Betrag Netto
+

{{ id }}

+

{{ createdAt }}

+
+ {{ ausweisart }} + + {{ betrag }} € + + {{get-provision-prozent ausweisart}} % + + {{get-provision-betrag ausweisart}} € +
+
+
+
+

Copyright © 2018 · IB Cornelsen

+

info@online-energieausweis.org

+
+ {{/each}} + + \ No newline at end of file From cbfa49b7bcb90e5b17a64a7adcf298a42a19b7db Mon Sep 17 00:00:00 2001 From: Moritz Utcke Date: Mon, 4 Aug 2025 19:33:17 -0400 Subject: [PATCH 4/5] Fix? --- backup-database.bash | 6 ++-- docker-compose.yml | 3 ++ recover-db-dev.bash | 39 ++++++++++++++++++------- src/astro-typesafe-api-caller.ts | 6 ++-- src/pages/dashboard/objekte/index.astro | 3 +- wipe-database.bash | 34 ++++----------------- 6 files changed, 44 insertions(+), 47 deletions(-) diff --git a/backup-database.bash b/backup-database.bash index 5348a744..306038be 100644 --- a/backup-database.bash +++ b/backup-database.bash @@ -12,15 +12,15 @@ export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required # IMPORTANT: Dieser Befehl benötigt das `ionos` Profil, sonst wird er nicht funktionieren. # Das Profil kann mit `aws configure --profile ionos` erstellt werden. # Den Key dafür findet man auf https://dcd.ionos.com/latest/?lang=en#/key-management -docker exec -t $DATABASE_NAME pg_dump --data-only -U main main | brotli --best > $FILE_NAME +docker exec -t $DATABASE_NAME pg_dump --data-only -U main main | brotli --quality=3 > $FILE_NAME 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" -docker exec -t $DATABASE_NAME pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE +docker exec -t $DATABASE_NAME pg_dumpall -c -U main | brotli --quality=3 > $FILE_NAME_COMPLETE -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 echo "Uploaded $FILE_NAME_COMPLETE" diff --git a/docker-compose.yml b/docker-compose.yml index a96bb452..1b0d1117 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,9 @@ version: '3' services: database: + container_name: database + image: postgres:17.5 + build: ./ restart: always env_file: diff --git a/recover-db-dev.bash b/recover-db-dev.bash index bc278caf..7b931b23 100644 --- a/recover-db-dev.bash +++ b/recover-db-dev.bash @@ -4,19 +4,35 @@ BUCKET_NAME="ibc-db-backup" ENDPOINT_URL="https://s3.eu-central-3.ionoscloud.com" LOCAL_DOWNLOAD_DIR="./" # Where to save the file +DATABASE_NAME=database # === 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 + # Check if file exists locally if [ ! -f "$CUSTOM_FILE" ]; then - echo "❌ Custom file does not exist: $CUSTOM_FILE" - exit 1 + # Check if the file exists on the remote + if ! aws s3api head-object --bucket "$BUCKET_NAME" --key "$CUSTOM_FILE" --endpoint-url "$ENDPOINT_URL" > /dev/null 2>&1; then + echo "❌ Custom file does not exist in S3 bucket or locally." + exit 1 + else + echo "📥 Downloading $CUSTOM_FILE from S3" + aws s3 cp "s3://$BUCKET_NAME/$CUSTOM_FILE" "$LOCAL_DOWNLOAD_DIR" \ + --endpoint-url "$ENDPOINT_URL" + fi fi + LATEST_FILE="$CUSTOM_FILE" FILENAME=$(basename "$LATEST_FILE") - SQL_FILE="${FILENAME%.br}" # Remove .br suffix + if [[ "$FILENAME" == *.br ]]; then + echo "🗜️ Detected compressed file: $FILENAME" + # Remove the .br suffix for the SQL file + SQL_FILE="${FILENAME%.br}" # Remove .br suffix + brotli -d "$FILENAME" + else + SQL_FILE=$FILENAME + fi else echo "🔍 No custom file provided, searching for latest .sql.br file in S3" @@ -36,20 +52,21 @@ else 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" + + brotli -d "$FILENAME" + echo "🗜️ Decompressed to $SQL_FILE" fi -# === Decompress with Brotli === -echo "🗜️ Decompressing $FILENAME -> $SQL_FILE" -brotli -d "$FILENAME" # === Import into Postgres inside Docker === -echo "🐘 Importing into PostgreSQL (online-energieausweis-database-1:main)" -docker exec -i "online-energieausweis-database-1" env PGPASSWORD="hHMP8cd^N3SnzGRR" \ - psql -U "main" -d "main" < "$SQL_FILE" +echo "🐘 Importing into PostgreSQL ($DATABASE_NAME:main)" +docker exec -i "$DATABASE_NAME" env PGPASSWORD="hHMP8cd^N3SnzGRR" \ + psql -v ON_ERROR_STOP=0 -U main -d main < "$SQL_FILE" + + echo "✅ Import complete." diff --git a/src/astro-typesafe-api-caller.ts b/src/astro-typesafe-api-caller.ts index eac47bb0..a440b7ab 100644 --- a/src/astro-typesafe-api-caller.ts +++ b/src/astro-typesafe-api-caller.ts @@ -17,20 +17,20 @@ export const createCaller = createCallerFactory({ "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"), - "bedarfsausweis-wohnen/[id]": await import("../src/pages/api/bedarfsausweis-wohnen/[id].ts"), - "bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/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"), + "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"), "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/pages/dashboard/objekte/index.astro b/src/pages/dashboard/objekte/index.astro index d1216236..fc96ff3c 100644 --- a/src/pages/dashboard/objekte/index.astro +++ b/src/pages/dashboard/objekte/index.astro @@ -8,6 +8,7 @@ const page = Number(Astro.url.searchParams.get("p")); const user = await getCurrentUser(Astro); + if (!user) { return Astro.redirect("/auth/login"); } @@ -23,7 +24,7 @@ const totalPageCount = await prisma.aufnahme.count({ : {}, }); -if (page < 1 || page > totalPageCount && totalPageCount > 0) { +if (page < 1 || page > totalPageCount) { return Astro.redirect("/dashboard/objekte?p=1"); } diff --git a/wipe-database.bash b/wipe-database.bash index 13d4c8a3..5ccc60f2 100644 --- a/wipe-database.bash +++ b/wipe-database.bash @@ -3,7 +3,7 @@ set -e # Config -CONTAINER_NAME="online-energieausweis-database-1" +CONTAINER_NAME="database" DB_USER="main" DB_NAME="main" TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") @@ -39,40 +39,16 @@ fi if [[ "$SKIP_BACKUP" == false ]]; then echo "📦 Backup wird erstellt..." - docker exec -t "$CONTAINER_NAME" pg_dumpall -c -U "$DB_USER" | brotli > "$FILE_NAME" + docker exec -t "$CONTAINER_NAME" pg_dumpall -c -U "$DB_USER" | brotli --quality=1 > "$FILE_NAME" echo "✅ Backup abgeschlossen: $FILE_NAME" fi echo "🧨 Alle Daten aus allen Tabellen werden gelöscht..." # Generate and run TRUNCATE statements for all tables in the public schema -docker exec -i "$CONTAINER_NAME" psql -U "$DB_USER" "$DB_NAME" <<'EOSQL' -DO $$ -DECLARE - r RECORD; - sql TEXT := ''; -BEGIN - -- Truncate all tables - FOR r IN - SELECT tablename - FROM pg_tables - WHERE schemaname = 'public' - LOOP - 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 -$$; +docker exec -i "$CONTAINER_NAME" psql -U "$DB_USER" "postgres" <<'EOSQL' +DROP DATABASE IF EXISTS main; +CREATE DATABASE main WITH OWNER main ENCODING 'UTF8'; EOSQL echo "✅ Alle Tabellen gelöscht und Schema zurückgesetzt." From a05c32167e49fc33705774d525a9cebe2adfe25b Mon Sep 17 00:00:00 2001 From: Moritz Utcke Date: Mon, 4 Aug 2025 20:16:04 -0400 Subject: [PATCH 5/5] Benutzer Rolle Fix --- src/astro-typesafe-api-caller.ts | 8 ++++---- src/pages/api/aufnahme/[id]/bilder.ts | 2 +- src/pages/api/aufnahme/[id]/index.ts | 2 +- src/pages/api/bedarfsausweis-gewerbe/[id].ts | 2 +- src/pages/api/bedarfsausweis-gewerbe/index.ts | 2 +- src/pages/api/bedarfsausweis-wohnen/[id].ts | 2 +- src/pages/api/bedarfsausweis-wohnen/index.ts | 2 +- src/pages/api/geg-nachweis-gewerbe/[id].ts | 2 +- src/pages/api/geg-nachweis-gewerbe/index.ts | 2 +- src/pages/api/geg-nachweis-wohnen/[id].ts | 2 +- src/pages/api/geg-nachweis-wohnen/index.ts | 2 +- src/pages/api/objekt/[id]/index.ts | 2 +- .../api/verbrauchsausweis-gewerbe/[id].ts | 4 ++-- .../api/verbrauchsausweis-wohnen/[id].ts | 4 ++-- .../api/verbrauchsausweis-wohnen/index.ts | 2 +- src/pages/dashboard/aufnahme/[id].astro | 2 +- src/pages/dashboard/objekte/[id].astro | 4 ++-- src/pages/dashboard/objekte/index.astro | 19 +++++-------------- src/pages/dashboard/objekte/leer.astro | 15 +++++++++++++++ 19 files changed, 43 insertions(+), 37 deletions(-) create mode 100644 src/pages/dashboard/objekte/leer.astro diff --git a/src/astro-typesafe-api-caller.ts b/src/astro-typesafe-api-caller.ts index a440b7ab..988e475b 100644 --- a/src/astro-typesafe-api-caller.ts +++ b/src/astro-typesafe-api-caller.ts @@ -12,11 +12,11 @@ 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"), - "ausweise": await import("../src/pages/api/ausweise/index.ts"), - "aufnahme": await import("../src/pages/api/aufnahme/index.ts"), "auth/access-token": await import("../src/pages/api/auth/access-token.ts"), "auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"), "auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"), + "ausweise": await import("../src/pages/api/ausweise/index.ts"), + "aufnahme": await import("../src/pages/api/aufnahme/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"), "bedarfsausweis-wohnen/[id]": await import("../src/pages/api/bedarfsausweis-wohnen/[id].ts"), @@ -31,10 +31,10 @@ export const createCaller = createCallerFactory({ "rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"), "rechnung": await import("../src/pages/api/rechnung/index.ts"), "ticket": await import("../src/pages/api/ticket/index.ts"), - "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"), "verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"), + "user": await import("../src/pages/api/user/index.ts"), + "user/self": await import("../src/pages/api/user/self.ts"), "verbrauchsausweis-wohnen/[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"), diff --git a/src/pages/api/aufnahme/[id]/bilder.ts b/src/pages/api/aufnahme/[id]/bilder.ts index 8cf0d3fa..ed4a8168 100644 --- a/src/pages/api/aufnahme/[id]/bilder.ts +++ b/src/pages/api/aufnahme/[id]/bilder.ts @@ -64,7 +64,7 @@ export const GET = defineApiRoute({ const { id } = ctx.params; const aufnahme = await prisma.aufnahme.findUnique({ - where: user.rolle === Enums.BenutzerRolle.USER ? { + where: user.rolle !== Enums.BenutzerRolle.ADMIN ? { id, benutzer_id: user.id } : { id }, diff --git a/src/pages/api/aufnahme/[id]/index.ts b/src/pages/api/aufnahme/[id]/index.ts index 3f330279..2e15a173 100644 --- a/src/pages/api/aufnahme/[id]/index.ts +++ b/src/pages/api/aufnahme/[id]/index.ts @@ -63,7 +63,7 @@ export const GET = defineApiRoute({ const { id } = context.params; const aufnahme = await prisma.aufnahme.findUnique({ - where: user.rolle === Enums.BenutzerRolle.USER ? { + where: user.rolle !== Enums.BenutzerRolle.ADMIN ? { id, benutzer_id: user.id } : { id }, diff --git a/src/pages/api/bedarfsausweis-gewerbe/[id].ts b/src/pages/api/bedarfsausweis-gewerbe/[id].ts index c2c74657..7015592b 100644 --- a/src/pages/api/bedarfsausweis-gewerbe/[id].ts +++ b/src/pages/api/bedarfsausweis-gewerbe/[id].ts @@ -49,7 +49,7 @@ export const PATCH = defineApiRoute({ data: input }) - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, ctx.params.id as string) } }, diff --git a/src/pages/api/bedarfsausweis-gewerbe/index.ts b/src/pages/api/bedarfsausweis-gewerbe/index.ts index af81a364..52b95ce5 100644 --- a/src/pages/api/bedarfsausweis-gewerbe/index.ts +++ b/src/pages/api/bedarfsausweis-gewerbe/index.ts @@ -66,7 +66,7 @@ export const PUT = defineApiRoute({ } } }); - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, id) } return nachweis.id diff --git a/src/pages/api/bedarfsausweis-wohnen/[id].ts b/src/pages/api/bedarfsausweis-wohnen/[id].ts index 75901097..513c1f2a 100644 --- a/src/pages/api/bedarfsausweis-wohnen/[id].ts +++ b/src/pages/api/bedarfsausweis-wohnen/[id].ts @@ -48,7 +48,7 @@ export const PATCH = defineApiRoute({ }, data: input }) - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, ctx.params.id as string) } }, diff --git a/src/pages/api/bedarfsausweis-wohnen/index.ts b/src/pages/api/bedarfsausweis-wohnen/index.ts index 8fbe1439..ee338cf1 100644 --- a/src/pages/api/bedarfsausweis-wohnen/index.ts +++ b/src/pages/api/bedarfsausweis-wohnen/index.ts @@ -73,7 +73,7 @@ export const PUT = defineApiRoute({ }, }, }); - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, id) } return id; diff --git a/src/pages/api/geg-nachweis-gewerbe/[id].ts b/src/pages/api/geg-nachweis-gewerbe/[id].ts index 1c5419fc..81529d79 100644 --- a/src/pages/api/geg-nachweis-gewerbe/[id].ts +++ b/src/pages/api/geg-nachweis-gewerbe/[id].ts @@ -48,7 +48,7 @@ export const PATCH = defineApiRoute({ }, data: input }) - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, ctx.params.id as string) } }, diff --git a/src/pages/api/geg-nachweis-gewerbe/index.ts b/src/pages/api/geg-nachweis-gewerbe/index.ts index f1e0f2a7..7d2c57cd 100644 --- a/src/pages/api/geg-nachweis-gewerbe/index.ts +++ b/src/pages/api/geg-nachweis-gewerbe/index.ts @@ -83,7 +83,7 @@ export const PUT = defineApiRoute({ }, }, }); - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, id) } return { diff --git a/src/pages/api/geg-nachweis-wohnen/[id].ts b/src/pages/api/geg-nachweis-wohnen/[id].ts index 34b4830a..5c1f3173 100644 --- a/src/pages/api/geg-nachweis-wohnen/[id].ts +++ b/src/pages/api/geg-nachweis-wohnen/[id].ts @@ -48,7 +48,7 @@ export const PATCH = defineApiRoute({ }, data: input }) - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, ctx.params.id as string) } }, diff --git a/src/pages/api/geg-nachweis-wohnen/index.ts b/src/pages/api/geg-nachweis-wohnen/index.ts index b0f8c420..a696a8c0 100644 --- a/src/pages/api/geg-nachweis-wohnen/index.ts +++ b/src/pages/api/geg-nachweis-wohnen/index.ts @@ -83,7 +83,7 @@ export const PUT = defineApiRoute({ }, }, }); - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, id) } return { diff --git a/src/pages/api/objekt/[id]/index.ts b/src/pages/api/objekt/[id]/index.ts index 6013147c..3f6d6c31 100644 --- a/src/pages/api/objekt/[id]/index.ts +++ b/src/pages/api/objekt/[id]/index.ts @@ -66,7 +66,7 @@ export const GET = defineApiRoute({ const { id } = ctx.params; const objekt = await prisma.objekt.findUnique({ - where: user.rolle === Enums.BenutzerRolle.USER ? { + where: user.rolle !== Enums.BenutzerRolle.ADMIN ? { id, benutzer_id: user.id } : { id }, diff --git a/src/pages/api/verbrauchsausweis-gewerbe/[id].ts b/src/pages/api/verbrauchsausweis-gewerbe/[id].ts index 6c6f52ef..9330a9ce 100644 --- a/src/pages/api/verbrauchsausweis-gewerbe/[id].ts +++ b/src/pages/api/verbrauchsausweis-gewerbe/[id].ts @@ -46,7 +46,7 @@ export const PATCH = defineApiRoute({ data: input }) - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, ctx.params.id as string) } }, @@ -173,7 +173,7 @@ export const GET = defineApiRoute({ } const ausweis = await prisma.verbrauchsausweisGewerbe.findUnique({ - where: user.rolle === Enums.BenutzerRolle.USER ? { + where: user.rolle !== Enums.BenutzerRolle.ADMIN ? { id, benutzer_id: user.id } : { id }, diff --git a/src/pages/api/verbrauchsausweis-wohnen/[id].ts b/src/pages/api/verbrauchsausweis-wohnen/[id].ts index b960bf04..fcd313c3 100644 --- a/src/pages/api/verbrauchsausweis-wohnen/[id].ts +++ b/src/pages/api/verbrauchsausweis-wohnen/[id].ts @@ -47,7 +47,7 @@ export const PATCH = defineApiRoute({ data: input }) - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, ctx.params.id as string) } }, @@ -174,7 +174,7 @@ export const GET = defineApiRoute({ } const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({ - where: user.rolle === Enums.BenutzerRolle.USER ? { + where: user.rolle !== Enums.BenutzerRolle.ADMIN ? { id, benutzer_id: user.id } : { id }, diff --git a/src/pages/api/verbrauchsausweis-wohnen/index.ts b/src/pages/api/verbrauchsausweis-wohnen/index.ts index f2708961..f064ec01 100644 --- a/src/pages/api/verbrauchsausweis-wohnen/index.ts +++ b/src/pages/api/verbrauchsausweis-wohnen/index.ts @@ -103,7 +103,7 @@ export const PUT = defineApiRoute({ }, }); - if (user.rolle === Enums.BenutzerRolle.USER) { + if (user.rolle !== Enums.BenutzerRolle.ADMIN) { await sendAusweisGespeichertMail(user, id); } return { diff --git a/src/pages/dashboard/aufnahme/[id].astro b/src/pages/dashboard/aufnahme/[id].astro index 15600ab6..01526fcb 100644 --- a/src/pages/dashboard/aufnahme/[id].astro +++ b/src/pages/dashboard/aufnahme/[id].astro @@ -28,7 +28,7 @@ if (!user) { const aufnahme = await prisma.aufnahme.findUnique({ - where: user.rolle === Enums.BenutzerRolle.USER ? { + where: user.rolle !== Enums.BenutzerRolle.ADMIN ? { benutzer: { id: user.id }, diff --git a/src/pages/dashboard/objekte/[id].astro b/src/pages/dashboard/objekte/[id].astro index 5c910d3e..ecc37278 100644 --- a/src/pages/dashboard/objekte/[id].astro +++ b/src/pages/dashboard/objekte/[id].astro @@ -15,7 +15,7 @@ if (!user) { const totalPageCount = await prisma.aufnahme.count({ where: - user.rolle === Enums.BenutzerRolle.USER + user.rolle !== Enums.BenutzerRolle.ADMIN ? { benutzer: { id: user.id, @@ -27,7 +27,7 @@ const totalPageCount = await prisma.aufnahme.count({ let ausweis; // Wir fragen den neuesten Ausweis ab // Falls der Nutzer ein Admin ist dann kommt der ganz neueste ansonsten der neueste des eingeloggten Benutzers. -if (user.rolle === Enums.BenutzerRolle.USER) { +if (user.rolle !== Enums.BenutzerRolle.ADMIN) { const adapter = getPrismaAusweisAdapter(id); ausweis = await adapter?.findUnique({ where: { diff --git a/src/pages/dashboard/objekte/index.astro b/src/pages/dashboard/objekte/index.astro index fc96ff3c..713f2576 100644 --- a/src/pages/dashboard/objekte/index.astro +++ b/src/pages/dashboard/objekte/index.astro @@ -2,20 +2,18 @@ import { Enums, prisma } from "#lib/server/prisma"; import UserLayout from "#layouts/DashboardLayout.astro"; import { getCurrentUser } from "#lib/server/user"; -import moment from "moment"; const page = Number(Astro.url.searchParams.get("p")); const user = await getCurrentUser(Astro); - if (!user) { return Astro.redirect("/auth/login"); } const totalPageCount = await prisma.aufnahme.count({ where: - user.rolle === Enums.BenutzerRolle.USER + user.rolle !== Enums.BenutzerRolle.ADMIN || Enums.BenutzerRolle.RESELLER ? { benutzer: { id: user.id, @@ -24,14 +22,16 @@ const totalPageCount = await prisma.aufnahme.count({ : {}, }); -if (page < 1 || page > totalPageCount) { +if ((page < 1 || page > totalPageCount) && totalPageCount > 0) { return Astro.redirect("/dashboard/objekte?p=1"); +} else if (totalPageCount === 0) { + return Astro.redirect("/dashboard/objekte/leer"); } let result: { id: string; updated_at: Date }[] = []; // Wir fragen den neuesten Ausweis ab // Falls der Nutzer ein Admin ist dann kommt der ganz neueste ansonsten der neueste des eingeloggten Benutzers. -if (user.rolle === Enums.BenutzerRolle.USER) { +if (user.rolle !== Enums.BenutzerRolle.ADMIN || user.rolle === Enums.BenutzerRolle.RESELLER) { result = await prisma.$queryRaw`SELECT id, updated_at FROM "VerbrauchsausweisWohnen" WHERE benutzer_id = ${user.id} UNION ALL SELECT id, updated_at FROM "VerbrauchsausweisGewerbe" WHERE benutzer_id = ${user.id} UNION ALL @@ -41,15 +41,6 @@ if (user.rolle === Enums.BenutzerRolle.USER) { SELECT id, updated_at FROM "GEGNachweisGewerbe" WHERE benutzer_id = ${user.id} ORDER BY updated_at DESC LIMIT 1 OFFSET ${page - 1}`; } else { - const date = moment().subtract(2, "hours").toDate() - - // SELECT id, updated_at FROM "VerbrauchsausweisWohnen" WHERE created_at >= ${date} AND bestellt = ${true} UNION ALL - // SELECT id, updated_at FROM "VerbrauchsausweisGewerbe" WHERE created_at >= ${date} AND bestellt = ${true} UNION ALL - // SELECT id, updated_at FROM "BedarfsausweisWohnen" WHERE created_at >= ${date} AND bestellt = ${true} UNION ALL - // SELECT id, updated_at FROM "BedarfsausweisGewerbe" WHERE created_at >= ${date} AND bestellt = ${true} UNION ALL - // SELECT id, updated_at FROM "GEGNachweisWohnen" WHERE created_at >= ${date} AND bestellt = ${true} UNION ALL - // SELECT id, updated_at FROM "GEGNachweisGewerbe" WHERE created_at >= ${date} AND bestellt = ${true} - result = await prisma.$queryRaw`SELECT id, updated_at FROM "VerbrauchsausweisWohnen" WHERE ausgestellt = ${false} AND bestellt = ${true} UNION ALL SELECT id, updated_at FROM "VerbrauchsausweisGewerbe" WHERE ausgestellt = ${false} AND bestellt = ${true} UNION ALL diff --git a/src/pages/dashboard/objekte/leer.astro b/src/pages/dashboard/objekte/leer.astro new file mode 100644 index 00000000..6928ab12 --- /dev/null +++ b/src/pages/dashboard/objekte/leer.astro @@ -0,0 +1,15 @@ +--- +import DashboardLayout from "#layouts/DashboardLayout.astro"; +import { getCurrentUser } from "#lib/server/user"; + +const user = await getCurrentUser(Astro); + +if (!user) { + return Astro.redirect("/auth/login"); +} + +--- + + +

Sie haben bisher keine Ausweise erstellt. Klicken sie hier, um einen neuen Ausweis zu erstellen.

+
\ No newline at end of file