217 Commits

Author SHA1 Message Date
Moritz Utcke
a588837605 Verwendungszweck 2025-04-21 20:24:57 -03:00
Moritz Utcke
cfc6d3c230 Rechnung Optional 2025-04-21 20:06:11 -03:00
Jens Cornelsen
b6aa1fdf6d Merge remote-tracking branch 'origin/dev' into dashboard 2025-04-22 00:59:41 +02:00
Jens Cornelsen
68bffa8944 Auto stash before rebase of "dashboard" onto "origin/dashboard" 2025-04-22 00:47:02 +02:00
Moritz Utcke
f8e890e9a9 Bestätigungsmail weg 2025-04-21 19:09:57 -03:00
Moritz Utcke
64eb0d4e15 Fix 2025-04-21 18:18:31 -03:00
Moritz Utcke
d7a862e061 Fix 2025-04-21 17:56:23 -03:00
Moritz Utcke
6a2c386b5d GEGNachweise 2025-04-21 17:55:37 -03:00
Moritz Utcke
62e6dd44b9 Dashboard Template 2025-04-21 17:53:19 -03:00
Moritz Utcke
05b31a4862 Dashboard 2025-04-21 16:15:47 -03:00
Moritz Utcke
55305f31b7 Unnötige Dateien entfernt 2025-04-21 15:35:29 -03:00
Moritz Utcke
1f86a063ef Ausweis erstellen aus Dashboard 2025-04-21 15:23:59 -03:00
Moritz Utcke
217885587e Merge remote-tracking branch 'origin/dev' into dev 2025-04-21 15:18:48 -03:00
Moritz Utcke
28f8933f72 Ausweis als Admin bearbeiten 2025-04-21 15:18:41 -03:00
Moritz Utcke
5360ec3d24 Ausweis als Admin bearbeiten 2025-04-21 15:08:43 -03:00
Moritz Utcke
6339a3aeda Merge remote-tracking branch 'origin/main' into dev 2025-04-21 15:06:04 -03:00
Jens Cornelsen
974d0e28a1 Kühlungszuschlag fix 2025-04-21 19:57:15 +02:00
Jens Cornelsen
e9dab58a57 . 2025-04-21 19:23:15 +02:00
Jens Cornelsen
3aa72ea258 Warmwasserzuschlag fix 2025-04-21 19:10:14 +02:00
Moritz Utcke
0b161cf53e Bedarfsausweis Wohnen Sektion Rausgenomment 2025-04-21 13:00:04 -03:00
Jens Cornelsen
590723b297 Merge pull request #515 from IBCornelsen/dev
Datum Fetch, Rechnung, Mollie, etc
2025-04-21 16:33:14 +02:00
Jens Cornelsen
fd390238d9 Ausweis Box Design Änderung Text 2025-04-21 16:30:19 +02:00
Moritz Utcke
6388669d66 Verbrauch Datum 2025-04-21 09:34:07 -04:00
Moritz Utcke
b475e4dd79 fix GetRechung 2025-04-20 20:55:22 -04:00
Moritz Utcke
f5373fc7b1 Fix 2025-04-20 20:49:37 -04:00
Moritz Utcke
265e58d80d Fix Undefined 2025-04-20 20:37:46 -04:00
Moritz Utcke
d2fac65a6d Bugfixes 2025-04-20 20:34:29 -04:00
Moritz Utcke
b0df7fc4cf bump astro-typesafe-api 2025-04-20 19:41:42 -04:00
Moritz Utcke
e21a829cb6 Bugfixes 2025-04-20 17:21:46 -04:00
Jens Cornelsen
bef1cff348 Dashboard Verbrauchsausweis 2025-04-19 22:02:12 +02:00
Jens Cornelsen
f9555c7a1e Merge pull request #514 from IBCornelsen/main
get main
2025-04-19 02:41:59 +02:00
Jens Cornelsen
03389a04ba Zusammenfassung Verbrauchsausweis 2025-04-19 02:35:55 +02:00
Jens Cornelsen
008a6f05a5 Zusammenfassung Eingaben 2025-04-19 01:48:35 +02:00
Jens Cornelsen
6aa8816dd1 . 2025-04-18 18:12:59 +02:00
Jens Cornelsen
70427e8a45 . 2025-04-18 16:15:28 +02:00
Jens Cornelsen
51ea0ec007 . 2025-04-18 16:03:52 +02:00
Jens Cornelsen
1381f5787a Merge pull request #513 from IBCornelsen/dev
Verbrauchsausweis Gewerbe  Anzeige Zuschläge korrigiert
2025-04-18 15:37:46 +02:00
Jens Cornelsen
722db2d2ec . 2025-04-18 15:27:28 +02:00
Jens Cornelsen
72458f4631 . 2025-04-18 14:59:42 +02:00
Jens Cornelsen
bde6b3e102 . 2025-04-18 14:37:36 +02:00
Jens Cornelsen
936ca5abaa Kühlungszuschlag Strom 2025-04-18 14:27:43 +02:00
Jens Cornelsen
1f03bf5570 Leerstandszuschlag Strom 2025-04-18 13:57:22 +02:00
Jens Cornelsen
e7e2390bcd Kühlungszuschlag korrigiert 2025-04-18 13:41:48 +02:00
Jens Cornelsen
3ac6164c82 Warmwasserzuschlag raus 2025-04-18 13:26:30 +02:00
Jens Cornelsen
3bb6778e67 Leerstandszuschlag 2025-04-18 13:04:06 +02:00
Jens Cornelsen
fa797c00c2 Merge pull request #512 from IBCornelsen/main
get main
2025-04-18 12:27:28 +02:00
Jens Cornelsen
f0ae1a9205 . 2025-04-17 23:34:45 +02:00
Jens Cornelsen
af7da9c07f . 2025-04-17 23:29:36 +02:00
Jens Cornelsen
4106253b58 . 2025-04-17 23:26:43 +02:00
Jens Cornelsen
c787dce10c . 2025-04-17 23:18:04 +02:00
Jens Cornelsen
b265910b2a . 2025-04-17 23:03:17 +02:00
Jens Cornelsen
5e3f4c0f59 . 2025-04-17 22:46:02 +02:00
Jens Cornelsen
2fe07ebfad Zusammenfasssung Ausweisseite 2025-04-17 22:39:20 +02:00
Jens Cornelsen
7be766d2c7 Zahllinks erstmal entfernt 2025-04-17 20:58:37 +02:00
Jens Cornelsen
15651fc803 Fix Kühlung "nicht vorhanden" 2025-04-17 18:13:22 +02:00
Jens Cornelsen
5b3b81551e Merge remote-tracking branch 'origin/main' into dev 2025-04-17 18:03:03 +02:00
Jens Cornelsen
330841f8ee . 2025-04-17 01:46:45 +02:00
Jens Cornelsen
0708c6ce43 . 2025-04-17 01:41:23 +02:00
Jens Cornelsen
2c1945584d . 2025-04-17 01:36:49 +02:00
Jens Cornelsen
183178f943 . 2025-04-17 01:30:16 +02:00
Jens Cornelsen
b1b95159fa plz und ort in Ausweis pdf eingefügt 2025-04-17 01:20:18 +02:00
Jens Cornelsen
b0828592c5 Filter nur bestellte Ausweise und nicht ausgestellte im Dashboard für Admins 2025-04-17 01:02:58 +02:00
Jens Cornelsen
21446b3bf3 Filter nur bestellte Ausweise und nicht ausgestellte im Dashboard für Admins 2025-04-17 00:52:09 +02:00
Jens Cornelsen
935fbfba78 Firma in Adresse 2025-04-16 17:34:48 +02:00
Jens Cornelsen
fa195a79f5 Firma Benutzer in Adresse 2025-04-16 17:28:14 +02:00
Jens Cornelsen
f6a367c567 Adresse DB Rückgängig 2025-04-16 17:18:02 +02:00
Jens Cornelsen
bf6d8f47e7 Kühlung repariert VWBWTKEN9TR 2025-04-16 11:12:47 +02:00
Jens Cornelsen
02761610d1 Korrektur Kreuz 2025-04-15 20:37:14 +02:00
Jens Cornelsen
bf3107d3b7 Kühlungszuschlag 2025-04-15 18:24:28 +02:00
Jens Cornelsen
66e596bb57 Nochmal Zuschlag Kühlung 2025-04-15 18:12:22 +02:00
Jens Cornelsen
cdfdb6c001 PDF gefixt !! 2025-04-15 17:49:58 +02:00
Jens Cornelsen
c583229cc8 PDF Anzeige 2025-04-15 17:39:52 +02:00
Jens Cornelsen
417009fd6e PDF Verbrauchsausweis Anzeige gefixt 2025-04-15 17:08:34 +02:00
Jens Cornelsen
d3ffbca858 . 2025-04-15 17:01:22 +02:00
Jens Cornelsen
db4fc19c1a . 2025-04-15 16:57:40 +02:00
Jens Cornelsen
eefae0635a . 2025-04-15 16:49:55 +02:00
Jens Cornelsen
1d7c12ec60 . 2025-04-15 16:46:43 +02:00
Jens Cornelsen
4d7f94e292 . 2025-04-15 16:34:39 +02:00
Jens Cornelsen
e13810b16a . 2025-04-15 16:25:37 +02:00
Jens Cornelsen
d4be779cf1 . 2025-04-15 16:17:45 +02:00
Jens Cornelsen
3912262f4b fix pdf Verbrauchsausweis gewerbe 2025-04-15 16:05:24 +02:00
Jens Cornelsen
ed753b71c1 . 2025-04-15 15:47:37 +02:00
Jens Cornelsen
5b78e8b075 x statt haken 2025-04-15 15:41:01 +02:00
Jens Cornelsen
71dd1de503 test 2025-04-15 15:30:09 +02:00
Jens Cornelsen
2a95f7750a . 2025-04-15 15:26:13 +02:00
Jens Cornelsen
6d3dcb503a unicode 2025-04-15 15:21:38 +02:00
Jens Cornelsen
57c6bbd96c . 2025-04-15 15:18:08 +02:00
Jens Cornelsen
3f18ad9c59 . 2025-04-15 15:12:50 +02:00
Jens Cornelsen
c09cdcc788 . 2025-04-15 15:06:56 +02:00
Jens Cornelsen
473ff8d774 haken alternative 2025-04-15 14:58:17 +02:00
Jens Cornelsen
4ec3f42a8b . 2025-04-15 14:55:07 +02:00
Jens Cornelsen
36a4d7415c . 2025-04-15 14:37:26 +02:00
Jens Cornelsen
df81964b86 Elemente pdf 2025-04-15 14:24:46 +02:00
Carl Mahnke
7130b6ba65 Verbrauchsausweis Gewerbe ausstellen 2025-04-15 13:36:19 +02:00
Jens Cornelsen
bfa79fb06e Anzeige Elemente PDF - fix 2025-04-15 13:05:44 +02:00
Jens Cornelsen
52e2459d47 Bereiche wieder aktiviert 2025-04-14 17:45:57 +02:00
Jens Cornelsen
5081f70570 Höhe Dashboard full 2025-04-14 17:10:41 +02:00
Jens Cornelsen
f4e6b7baf8 dashboard layout 2025-04-14 17:07:55 +02:00
Jens Cornelsen
e55388e4b7 . 2025-04-14 17:06:50 +02:00
Jens Cornelsen
f14c376791 Pfad gefixr 2025-04-14 16:54:20 +02:00
Jens Cornelsen
071fd8c7be Höhe full 2025-04-14 16:51:00 +02:00
Jens Cornelsen
2bb2bd74db Nutzfläche gerundet 2025-04-14 11:41:36 +02:00
Jens Cornelsen
9d9fdebf3a . 2025-04-14 11:29:30 +02:00
Jens Cornelsen
0d9675fb35 . 2025-04-14 11:21:18 +02:00
Jens Cornelsen
7b5b272c17 . 2025-04-14 11:00:02 +02:00
Jens Cornelsen
a7427c3462 . 2025-04-14 10:45:58 +02:00
Jens Cornelsen
2b8ebcf182 . 2025-04-14 10:41:31 +02:00
Jens Cornelsen
eb72b600b4 . 2025-04-14 10:38:10 +02:00
Jens Cornelsen
606b851661 . 2025-04-14 10:26:23 +02:00
Jens Cornelsen
15f94c7752 Kühlungszuschlag bei Kühlung vorhanden 2025-04-14 10:21:18 +02:00
Jens Cornelsen
04dbd4adcd . 2025-04-14 00:50:08 +02:00
Jens Cornelsen
853fe54e3b Kundenprüfung Anteil WW 2025-04-14 00:37:16 +02:00
Jens Cornelsen
e2490f2296 . 2025-04-14 00:16:50 +02:00
Jens Cornelsen
cbddcf0968 Anzeige Nutzfläche gefixt 2025-04-14 00:01:42 +02:00
Jens Cornelsen
8b1e5df851 kuehlung fix 2025-04-13 23:07:36 +02:00
Jens Cornelsen
29d8e5e7b3 . 2025-04-13 21:53:59 +02:00
Jens Cornelsen
e86328b0c2 VG . 2025-04-13 20:07:50 +02:00
Jens Cornelsen
b8d37d4e38 bestellt bei BW auf false wenn keine Rechnung und user nicht 2025-04-13 19:55:32 +02:00
Jens Cornelsen
fd93f3fd54 . 2025-04-13 15:48:37 +02:00
Jens Cornelsen
9035de79ce . 2025-04-13 15:42:09 +02:00
Jens Cornelsen
2304de45b1 . 2025-04-13 13:53:22 +02:00
Jens Cornelsen
f1007d325f . 2025-04-13 13:37:29 +02:00
Jens Cornelsen
44679dbef0 . 2025-04-13 13:33:40 +02:00
Jens Cornelsen
682c97b3e7 . 2025-04-13 13:29:30 +02:00
Jens Cornelsen
b65c3eeeaa . 2025-04-13 13:24:27 +02:00
Jens Cornelsen
883c019293 . 2025-04-13 13:22:11 +02:00
Jens Cornelsen
50c2e3a6ce . 2025-04-13 13:14:35 +02:00
Jens Cornelsen
b7082e2318 Korrektur reset 2025-04-13 13:01:20 +02:00
Jens Cornelsen
f30b1cbd09 Besteller hinzugefügt 2025-04-13 11:57:45 +02:00
Jens Cornelsen
8936479c78 . 2025-04-13 02:32:15 +02:00
Jens Cornelsen
f02b30c6b5 . 2025-04-13 02:25:57 +02:00
Jens Cornelsen
fd34f6bcf7 . 2025-04-13 02:08:54 +02:00
Jens Cornelsen
e9eb113c33 . 2025-04-13 01:56:12 +02:00
Jens Cornelsen
1caee4e19e . 2025-04-13 01:22:35 +02:00
Jens Cornelsen
e18188d2a8 . 2025-04-13 01:10:50 +02:00
Jens Cornelsen
682cf056b6 . 2025-04-13 01:02:58 +02:00
Jens Cornelsen
5d11889fb2 Dashboard 2025-04-13 00:57:59 +02:00
Jens Cornelsen
566780b5e2 . 2025-04-13 00:49:12 +02:00
Jens Cornelsen
2d025b9fde . 2025-04-13 00:35:11 +02:00
Jens Cornelsen
64e97b6593 . 2025-04-13 00:23:05 +02:00
Jens Cornelsen
a05daedc54 . 2025-04-13 00:06:49 +02:00
Jens Cornelsen
e5756abb4d . 2025-04-12 23:48:20 +02:00
Jens Cornelsen
bfd30ace70 . 2025-04-12 23:37:27 +02:00
Jens Cornelsen
5858bff825 Dashboard 2025-04-12 23:26:19 +02:00
Jens Cornelsen
99c1a127b4 . 2025-04-12 23:04:09 +02:00
Jens Cornelsen
70af2e2d07 . 2025-04-12 22:35:55 +02:00
Jens Cornelsen
7db145af7c Dashboard 2025-04-12 22:24:11 +02:00
Jens Cornelsen
dfe13dd6bd . 2025-04-12 21:27:03 +02:00
Jens Cornelsen
33596e4b61 . 2025-04-12 21:21:26 +02:00
Jens Cornelsen
ca9c1b025a . 2025-04-12 21:14:22 +02:00
Jens Cornelsen
ca5102cd77 Dashboard 2025-04-12 21:01:02 +02:00
Jens Cornelsen
cfe160f34d . 2025-04-12 20:34:12 +02:00
Jens Cornelsen
d0a7033bf4 . 2025-04-12 20:29:52 +02:00
Jens Cornelsen
415291b083 . 2025-04-12 20:17:13 +02:00
Jens Cornelsen
4208c3ecc5 . 2025-04-12 20:09:32 +02:00
Jens Cornelsen
76dbe27c5d . 2025-04-12 20:00:59 +02:00
Jens Cornelsen
cfbf1dd69b . 2025-04-12 19:52:18 +02:00
Jens Cornelsen
313b6e328e . 2025-04-12 19:51:01 +02:00
Jens Cornelsen
22532f3783 . 2025-04-12 19:50:13 +02:00
Jens Cornelsen
3ced32b235 . 2025-04-12 19:46:08 +02:00
Jens Cornelsen
300b1d5ea3 . 2025-04-12 19:31:19 +02:00
Jens Cornelsen
40df8c7104 Dashboard 2025-04-12 19:22:19 +02:00
Carl Mahnke
83727ac71d Migrationsskripte Verbrauchsausweis Wohnen + Gewerbe 2025-04-12 18:13:40 +02:00
Carl Mahnke
f31d710b20 Migrationsskript Bedarfsausweis Wohnen Ohne Limit 2025-04-12 17:36:31 +02:00
Carl Mahnke
6da7c0e501 Migrationsskript Bedarfsausweis Wohnen Limit 10 2025-04-12 17:27:51 +02:00
Carl Mahnke
f7b6a50482 Migrationsskript Bedarfsausweis Wohnen Test 2025-04-12 17:14:02 +02:00
Carl Mahnke
48f72a2f0f Migrations Skripte 2025-04-12 16:40:21 +02:00
Jens Cornelsen
43d2c114f4 Merge pull request #511 from IBCornelsen/main
update dev
2025-04-12 13:40:34 +02:00
Jens Cornelsen
aa84dd967e . 2025-04-11 21:07:52 +02:00
Jens Cornelsen
c413f76fe2 . 2025-04-11 20:58:52 +02:00
Jens Cornelsen
7762310bf3 . 2025-04-11 20:48:12 +02:00
Jens Cornelsen
7dd3a6c60d . 2025-04-11 20:29:22 +02:00
Jens Cornelsen
80a6992f5b . 2025-04-11 20:03:22 +02:00
Jens Cornelsen
4b651b733b . 2025-04-11 19:37:34 +02:00
Jens Cornelsen
c269306d9d . 2025-04-11 19:31:51 +02:00
Jens Cornelsen
cf0f0bdee0 . 2025-04-11 19:19:22 +02:00
Jens Cornelsen
d4e2d50e00 Skala und Rchnung 2025-04-11 18:58:11 +02:00
Jens Cornelsen
e303c44822 PDF Name auf Energieausweis geändert 2025-04-11 17:33:40 +02:00
Jens Cornelsen
3eb30d2248 Auto stash before rebase of "main" onto "origin/main" 2025-04-11 17:10:52 +02:00
Carl Mahnke
9b6b30ae30 Kuehlung gefixt 2025-04-11 15:06:28 +02:00
Moritz Utcke
9d9e6f7786 Merge branch 'dev' 2025-04-10 00:34:03 -04:00
Moritz Utcke
98f32ca279 Ausstellen 2025-04-10 00:33:54 -04:00
Moritz Utcke
ab7e5bc6d6 Merge branch 'dev' 2025-04-09 22:17:11 -04:00
Moritz Utcke
636c5463b2 Ausstellen 2025-04-09 22:17:00 -04:00
Moritz Utcke
85c0216e9d Merge branch 'dev' 2025-04-09 21:45:33 -04:00
Moritz Utcke
5e2861546f Ausstellen Error 2025-04-09 21:45:04 -04:00
Moritz Utcke
c1fc08ecba Merge branch 'dev' 2025-04-09 21:35:43 -04:00
Moritz Utcke
458a6ab254 Ausstellen 2025-04-09 21:35:24 -04:00
Moritz Utcke
1259f642e1 Merge pull request #508 from IBCornelsen/revert-507-revert-506-dev
Revert "Revert "Bugfixes""
2025-04-09 20:16:35 -04:00
Moritz Utcke
3cb71b8e2c Revert "Revert "Bugfixes"" 2025-04-09 20:13:52 -04:00
Moritz Utcke
eb8bae6d69 Merge pull request #507 from IBCornelsen/revert-506-dev
Revert "Bugfixes"
2025-04-09 19:25:36 -04:00
Moritz Utcke
4f382c150d Revert "Bugfixes" 2025-04-09 19:25:21 -04:00
Moritz Utcke
53ea51885a Merge pull request #506 from IBCornelsen/dev
Bugfixes
2025-04-09 19:11:44 -04:00
Moritz Utcke
f5ae2cd0d4 Mollie 2025-04-09 13:54:39 -04:00
Moritz Utcke
8860750487 Mollie 2025-04-09 13:25:06 -04:00
Moritz Utcke
a58c8d466e Verbrauchsausweis Gewerbe 2025-04-09 13:10:11 -04:00
Moritz Utcke
8daee69576 Bugfixes 2025-04-09 11:46:27 -04:00
Moritz Utcke
7665141a5a Formular Button 2025-04-09 09:18:11 -04:00
Moritz Utcke
7327d39c57 Ausweis ID im Ausweis 2025-04-09 09:06:43 -04:00
Moritz Utcke
9177ca18f0 Merge pull request #505 from IBCornelsen/dev
Updates und Verbesserungen
2025-04-08 19:59:34 -04:00
Moritz Utcke
0956744878 Ausstellen 2025-04-08 19:34:51 -04:00
Moritz Utcke
b0235056a7 Adresse 2025-04-08 18:50:27 -04:00
Moritz Utcke
d354189d3c Ausweis, Ausstellung, Adresse 2025-04-08 18:49:29 -04:00
Moritz Utcke
07760aa26a Bugfix Process not defined 2025-04-08 15:13:17 -04:00
Moritz Utcke
13322836aa Recover DB 2025-04-08 13:53:32 -04:00
Moritz Utcke
d8acd0476a Actions 2025-04-08 13:06:42 -04:00
Moritz Utcke
a2e0d50b1f Update .gitignore 2025-04-08 10:23:14 -04:00
Moritz Utcke
176f1c08ad Klimafaktoren 2025-04-07 23:55:42 -04:00
Moritz Utcke
1970a105a9 Webhook 2025-04-07 21:41:27 -04:00
Moritz Utcke
71438a39eb Ausstellen 2025-04-07 21:31:47 -04:00
Moritz Utcke
ba7792a4b9 Ausstellen 2025-04-07 21:27:38 -04:00
Moritz Utcke
145bf46ee1 Partner Code 2025-04-07 20:36:47 -04:00
Moritz Utcke
ecdce5b279 Suche 2025-04-07 18:46:28 -04:00
Moritz Utcke
c0d4ede483 Daten Umziehen 2025-04-07 18:45:33 -04:00
Moritz Utcke
3fa207ea9c Merge remote-tracking branch 'origin/main' 2025-04-07 18:38:21 -04:00
Moritz Utcke
2a302a4b59 astro-typesafe-api-caller entfernt 2025-04-07 18:37:39 -04:00
Moritz Utcke
42e0907bb9 Merge pull request #504 from IBCornelsen/Jens
Preise Bedarfsausweis
2025-04-07 18:37:30 -04:00
119 changed files with 43911 additions and 2215 deletions

View File

@@ -1,10 +1,10 @@
name: Dev Pipeline
name: Development Pipeline
on:
pull_request:
branches: [main]
branches: [dev]
push:
branches: [main]
branches: [dev]
jobs:
deploy:
@@ -26,8 +26,8 @@ jobs:
export PATH=$HOME/.nvm/versions/node/v22.14.0/bin:$PATH
echo $PATH
cd ~/online-energieausweis
git reset --hard origin/main
git reset --hard origin/dev
git clean -f -d
git pull origin main
git pull origin dev
git status
make prod

31
.github/workflows/prod-pipeline.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Production Pipeline
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Bun
run: |
curl -fsSL https://bun.sh/install | bash
- uses: appleboy/ssh-action@master
with:
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.PROD_USERNAME }}
password: ${{ secrets.PROD_PASSWORD }}
port: 22
script: |
export PATH=$HOME/.bun/bin:$PATH
export PATH=$HOME/.nvm/versions/node/v22.14.0/bin:$PATH
echo $PATH
cd ~/online-energieausweis
git reset --hard origin/main
git clean -f -d
git pull origin main
git status
make prod

2
.gitignore vendored
View File

@@ -34,7 +34,7 @@ dbml/schema.dbml
prisma/migrations/20250315143314_/migration.sql
src/astro-typesafe-api-caller.ts
# src/astro-typesafe-api-caller.ts
src/testing/ausweise.csv
src/testing/users.csv

View File

@@ -41,7 +41,7 @@ stop-database:
- docker stop $(DB_CONTAINER_NAME)
- docker rm $(DB_CONTAINER_NAME)
wait-fordatabase:
wait-for-database:
@while ! docker exec $(DB_CONTAINER_NAME) pg_isready -U $(DB_USER) -h localhost -p $(DB_PORT) > /dev/null 2>&1; do \
sleep 1; \
done
@@ -68,4 +68,4 @@ prod: install-dependencies prisma-studio backup-database-cronjob
backup-database-cronjob:
- pm2 delete daily-db-backup
pm2 start backup-database.bash --name "daily-db-backup" --cron "0 0 * * *"
pm2 start bash --name "daily-db-backup" --cron "0 0 * * *" -- backup-database.bash

View File

@@ -2,20 +2,27 @@
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
# Wir exportieren die Datenbank und komprimieren sie.
docker exec -t online-energieausweis-database-1 pg_dump --data-only -U main main | brotli --best > $FILE_NAME
docker exec -t online-energieausweis-database-1 pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE
# Das wird benötigt für AWS Ionos Kompatibilität.
export AWS_REQUEST_CHECKSUM_CALCULATION=when_required
export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required
# Wir exportieren die Datenbank und komprimieren sie.
# 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
aws s3 cp $FILE_NAME s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-1.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
aws s3 cp $FILE_NAME_COMPLETE s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-1.ionoscloud.com --storage-class STANDARD
echo "Uploaded $FILE_NAME_COMPLETE"
# Wir entfernen das Backup
rm $FILE_NAME
rm $FILE_NAME_COMPLETE

View File

@@ -18,7 +18,7 @@
"@trpc/client": "^10.45.2",
"@trpc/server": "^10.45.2",
"astro": "^4.16.17",
"astro-typesafe-api": "^0.2.2",
"astro-typesafe-api": "^0.2.4",
"body-scroll-lock": "^4.0.0-beta.0",
"buffer": "^6.0.3",
"bun": "^1.2.5",
@@ -44,6 +44,7 @@
"siema": "^1.5.1",
"soap": "^1.1.8",
"sqids": "^0.3.0",
"ssh2-sftp-client": "^12.0.0",
"svelte": "^3.59.2",
"svelte-dialogs": "^1.2.2",
"svelte-preprocess": "^5.1.4",
@@ -67,6 +68,7 @@
"@types/nodemailer": "^6.4.17",
"@types/papaparse": "^5.3.15",
"@types/siema": "^1.4.11",
"@types/ssh2-sftp-client": "^9.0.4",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
@@ -82,11 +84,11 @@
"postcss-import": "^16.1.0",
"postcss-nesting": "^13.0.1",
"prettier": "^2.8.8",
"prisma": "^6.4.1",
"prisma": "6.4.1",
"prisma-dbml-generator": "^0.12.0",
"prisma-generator-fake-data": "^0.14.3",
"tsx": "^4.19.3",
"typescript": "^5",
"typescript": "^5.8.3",
"zod-prisma": "^0.5.4",
},
},
@@ -807,6 +809,10 @@
"@types/sizzle": ["@types/sizzle@2.3.9", "", {}, "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w=="],
"@types/ssh2": ["@types/ssh2@1.15.5", "", { "dependencies": { "@types/node": "^18.11.18" } }, "sha512-N1ASjp/nXH3ovBHddRJpli4ozpk6UdDYIX4RJWFa9L1YKnzdhTlVmiGHm4DZnj/jLbqZpes4aeR30EFGQtvhQQ=="],
"@types/ssh2-sftp-client": ["@types/ssh2-sftp-client@9.0.4", "", { "dependencies": { "@types/ssh2": "^1.0.0" } }, "sha512-gnIn56MTB9W3A3hPL/1sHI23t8YwcE3eVYa1O2XjT9vaqimFdtNHxyQiy5Y78+ociQTKazMSD8YyMEO4QjNMrg=="],
"@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="],
"@types/uuid": ["@types/uuid@9.0.8", "", {}, "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA=="],
@@ -909,7 +915,7 @@
"astro": ["astro@4.16.18", "", { "dependencies": { "@astrojs/compiler": "^2.10.3", "@astrojs/internal-helpers": "0.4.1", "@astrojs/markdown-remark": "5.3.0", "@astrojs/telemetry": "3.1.0", "@babel/core": "^7.26.0", "@babel/plugin-transform-react-jsx": "^7.25.9", "@babel/types": "^7.26.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.1.3", "@types/babel__core": "^7.20.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.1.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^0.7.2", "cssesc": "^3.0.0", "debug": "^4.3.7", "deterministic-object-hash": "^2.0.2", "devalue": "^5.1.1", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.5.4", "esbuild": "^0.21.5", "estree-walker": "^3.0.3", "fast-glob": "^3.3.2", "flattie": "^1.1.1", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", "html-escaper": "^3.0.3", "http-cache-semantics": "^4.1.1", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.14", "magicast": "^0.3.5", "micromatch": "^4.0.8", "mrmime": "^2.0.0", "neotraverse": "^0.6.18", "ora": "^8.1.1", "p-limit": "^6.1.0", "p-queue": "^8.0.1", "preferred-pm": "^4.0.0", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.6.3", "shiki": "^1.23.1", "tinyexec": "^0.3.1", "tsconfck": "^3.1.4", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3", "vite": "^5.4.11", "vitefu": "^1.0.4", "which-pm": "^3.0.0", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "zod": "^3.23.8", "zod-to-json-schema": "^3.23.5", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.33.3" }, "bin": { "astro": "astro.js" } }, "sha512-G7zfwJt9BDHEZwlaLNvjbInIw2hPryyD654314KV/XT34pJU6SfN1S+mWa8RAkALcZNJnJXCJmT3JXLQStD3Lw=="],
"astro-typesafe-api": ["astro-typesafe-api@0.2.2", "", { "dependencies": { "es-codec": "^0.5.0", "globby": "^14.0.2" }, "peerDependencies": { "astro": "^4.16.17", "typescript": "^5.0.0", "zod": "^3.24.1" }, "bin": { "astro-typesafe-api": "src/cli.ts" } }, "sha512-SEHV2iPyIrdpYdYb0mIN1WmcvC61bvsCQqb/X+R4EOcFjuozJ9fJhSiFGxJMvNoxJ9S3P3GKLyDnxXvFlKq0mw=="],
"astro-typesafe-api": ["astro-typesafe-api@0.2.4", "", { "dependencies": { "es-codec": "^0.5.0", "globby": "^14.0.2" }, "peerDependencies": { "astro": "^4.16.17", "typescript": "^5.0.0", "zod": "^3.24.1" }, "bin": { "astro-typesafe-api": "src/cli.ts" } }, "sha512-KiAw7+QJyuzz606GSkeaTdav8vttDUEYVaFAdVRlDuSvUdhcYsJB14zHkMe6ZSMfRNBQRxaMZBgPgEtWb1mf1w=="],
"async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="],
@@ -975,6 +981,10 @@
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
"buildcheck": ["buildcheck@0.0.6", "", {}, "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A=="],
"bun": ["bun@1.2.5", "", { "optionalDependencies": { "@oven/bun-darwin-aarch64": "1.2.5", "@oven/bun-darwin-x64": "1.2.5", "@oven/bun-darwin-x64-baseline": "1.2.5", "@oven/bun-linux-aarch64": "1.2.5", "@oven/bun-linux-aarch64-musl": "1.2.5", "@oven/bun-linux-x64": "1.2.5", "@oven/bun-linux-x64-baseline": "1.2.5", "@oven/bun-linux-x64-musl": "1.2.5", "@oven/bun-linux-x64-musl-baseline": "1.2.5", "@oven/bun-windows-x64": "1.2.5", "@oven/bun-windows-x64-baseline": "1.2.5" }, "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "bun": "bin/bun.exe", "bunx": "bin/bun.exe" } }, "sha512-fbQLt+DPiGUrPKdmsHRRT7cQAlfjdxPVFvLZrsUPmKiTdv+pU50ypdx9yRJluknSbyaZchFVV7Lx2KXikXKX2Q=="],
"bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="],
@@ -1083,6 +1093,8 @@
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"concat-stream": ["concat-stream@2.0.0", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="],
"consola": ["consola@3.4.0", "", {}, "sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA=="],
"console-control-strings": ["console-control-strings@1.1.0", "", {}, "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="],
@@ -1107,6 +1119,8 @@
"core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
"cpu-features": ["cpu-features@0.0.10", "", { "dependencies": { "buildcheck": "~0.0.6", "nan": "^2.19.0" } }, "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA=="],
"crc-32": ["crc-32@1.2.2", "", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="],
"crc32-stream": ["crc32-stream@4.0.3", "", { "dependencies": { "crc-32": "^1.2.0", "readable-stream": "^3.4.0" } }, "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw=="],
@@ -2395,6 +2409,10 @@
"sqids": ["sqids@0.3.0", "", {}, "sha512-lOQK1ucVg+W6n3FhRwwSeUijxe93b51Bfz5PMRMihVf1iVkl82ePQG7V5vwrhzB11v0NtsR25PSZRGiSomJaJw=="],
"ssh2": ["ssh2@1.16.0", "", { "dependencies": { "asn1": "^0.2.6", "bcrypt-pbkdf": "^1.0.2" }, "optionalDependencies": { "cpu-features": "~0.0.10", "nan": "^2.20.0" } }, "sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg=="],
"ssh2-sftp-client": ["ssh2-sftp-client@12.0.0", "", { "dependencies": { "concat-stream": "^2.0.0", "ssh2": "^1.16.0" } }, "sha512-k+ocDsx6N2eDwQlIRwJFa0I1bkQpFPhIc+cv1iplaQaIPXFt9YM1ZnXCJOW4OILS5dzE+12OlhYIF5g0AzgVfg=="],
"sshpk": ["sshpk@1.18.0", "", { "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", "bcrypt-pbkdf": "^1.0.0", "dashdash": "^1.12.0", "ecc-jsbn": "~0.1.1", "getpass": "^0.1.1", "jsbn": "~0.1.0", "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" }, "bin": { "sshpk-conv": "bin/sshpk-conv", "sshpk-sign": "bin/sshpk-sign", "sshpk-verify": "bin/sshpk-verify" } }, "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ=="],
"statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="],
@@ -2539,6 +2557,8 @@
"type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="],
"typedarray": ["typedarray@0.0.6", "", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="],
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
"ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="],
@@ -2741,6 +2761,8 @@
"@sveltejs/vite-plugin-svelte/vitefu": ["vitefu@0.2.5", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["vite"] }, "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q=="],
"@types/ssh2/@types/node": ["@types/node@18.19.86", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ=="],
"@typescript-eslint/typescript-estree/globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="],
"@typescript-eslint/utils/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
@@ -3001,6 +3023,8 @@
"@prisma/internals/globby/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"@types/ssh2/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
"@typescript-eslint/typescript-estree/globby/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="],
"@typescript-eslint/utils/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="],

View File

@@ -32,7 +32,7 @@
"@trpc/client": "^10.45.2",
"@trpc/server": "^10.45.2",
"astro": "^4.16.17",
"astro-typesafe-api": "^0.2.2",
"astro-typesafe-api": "^0.2.4",
"body-scroll-lock": "^4.0.0-beta.0",
"buffer": "^6.0.3",
"bun": "^1.2.5",
@@ -58,6 +58,7 @@
"siema": "^1.5.1",
"soap": "^1.1.8",
"sqids": "^0.3.0",
"ssh2-sftp-client": "^12.0.0",
"svelte": "^3.59.2",
"svelte-dialogs": "^1.2.2",
"svelte-preprocess": "^5.1.4",
@@ -81,6 +82,7 @@
"@types/nodemailer": "^6.4.17",
"@types/papaparse": "^5.3.15",
"@types/siema": "^1.4.11",
"@types/ssh2-sftp-client": "^9.0.4",
"@types/uuid": "^9.0.8",
"@typescript-eslint/eslint-plugin": "^5.62.0",
"@typescript-eslint/parser": "^5.62.0",
@@ -96,7 +98,7 @@
"postcss-import": "^16.1.0",
"postcss-nesting": "^13.0.1",
"prettier": "^2.8.8",
"prisma": "^6.4.1",
"prisma": "6.4.1",
"prisma-dbml-generator": "^0.12.0",
"prisma-generator-fake-data": "^0.14.3",
"tsx": "^4.19.3",

BIN
persistent/images/haken.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

View File

@@ -0,0 +1,17 @@
-- AlterTable
ALTER TABLE "BedarfsausweisGewerbe" ADD COLUMN "ausweisart" "Ausweisart" NOT NULL DEFAULT 'BedarfsausweisGewerbe';
-- AlterTable
ALTER TABLE "BedarfsausweisWohnen" ADD COLUMN "ausweisart" "Ausweisart" NOT NULL DEFAULT 'BedarfsausweisWohnen';
-- AlterTable
ALTER TABLE "GEGNachweisGewerbe" ADD COLUMN "ausweisart" "Ausweisart" NOT NULL DEFAULT 'GEGNachweisGewerbe';
-- AlterTable
ALTER TABLE "GEGNachweisWohnen" ADD COLUMN "ausweisart" "Ausweisart" NOT NULL DEFAULT 'GEGNachweisWohnen';
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ADD COLUMN "ausweisart" "Ausweisart" NOT NULL DEFAULT 'VerbrauchsausweisGewerbe';
-- AlterTable
ALTER TABLE "VerbrauchsausweisWohnen" ADD COLUMN "ausweisart" "Ausweisart" NOT NULL DEFAULT 'VerbrauchsausweisWohnen';

View File

@@ -26,6 +26,7 @@ model BedarfsausweisGewerbe {
klimatisierung Boolean? @default(false)
nachweistyp AusweisTyp @default(Standard)
ausweisart Ausweisart @default(BedarfsausweisGewerbe)
created_at DateTime @default(now())
updated_at DateTime @updatedAt @default(now())

View File

@@ -100,6 +100,7 @@ model BedarfsausweisWohnen {
pruefpunkt_fenster Boolean? @default(false)
ausweistyp AusweisTyp @default(Standard)
ausweisart Ausweisart @default(BedarfsausweisWohnen)
benutzer Benutzer? @relation(fields: [benutzer_id], references: [id], onDelete: NoAction, onUpdate: NoAction)

View File

@@ -17,6 +17,7 @@ model GEGNachweisGewerbe {
beschreibung String? @db.Text
nachweistyp AusweisTyp @default(Standard)
ausweisart Ausweisart @default(GEGNachweisGewerbe)
created_at DateTime @default(now())
updated_at DateTime @updatedAt @default(now())

View File

@@ -17,6 +17,7 @@ model GEGNachweisWohnen {
beschreibung String? @db.Text
nachweistyp AusweisTyp @default(Standard)
ausweisart Ausweisart @default(GEGNachweisWohnen)
created_at DateTime @default(now())
updated_at DateTime @updatedAt @default(now())

View File

@@ -74,6 +74,7 @@ model VerbrauchsausweisGewerbe {
updated_at DateTime @updatedAt @default(now())
ausweistyp AusweisTyp @default(Standard)
ausweisart Ausweisart @default(VerbrauchsausweisGewerbe)
pruefpunkt_heizungsalter Boolean? @default(false)
pruefpunkt_verbrauch_niedrig Boolean? @default(false)

View File

@@ -75,6 +75,7 @@ model VerbrauchsausweisWohnen {
kontrolldatei_angefragt Boolean? @default(false)
ausweistyp AusweisTyp @default(Standard)
ausweisart Ausweisart @default(VerbrauchsausweisWohnen)
created_at DateTime @default(now())
updated_at DateTime @updatedAt @default(now())

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

41
recover-db-dev.bash Normal file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
# === Configuration ===
BUCKET_NAME="ibc-db-backup"
ENDPOINT_URL="https://s3-eu-central-1.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 file was found ===
if [ "$LATEST_FILE" == "None" ] || [ -z "$LATEST_FILE" ]; then
echo "❌ No matching .sql.br file found."
exit 1
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"
# === 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 "✅ Import complete."
# === Optional: Clean up
rm "$FILENAME" "$SQL_FILE"

View File

@@ -9,16 +9,15 @@ export const createCaller = createCallerFactory({
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
"admin/erinnern": await import("../src/pages/api/admin/erinnern.ts"),
"admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"),
"admin/post-ausstellen": await import("../src/pages/api/admin/post-ausstellen.ts"),
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"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"),
"ausweise": await import("../src/pages/api/ausweise/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"),
@@ -35,9 +34,9 @@ export const createCaller = createCallerFactory({
"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"),
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.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"),
"aufnahme/[id]/bilder": await import("../src/pages/api/aufnahme/[id]/bilder.ts"),
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),
"aufnahme/[id]/unterlagen": await import("../src/pages/api/aufnahme/[id]/unterlagen.ts"),

View File

@@ -1,5 +1,4 @@
import { api } from "astro-typesafe-api/client";
import { exclude } from "#lib/exclude.js";
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import {
@@ -566,7 +565,7 @@ export async function ausweisSpeichern(
return;
}
aufnahme.id = aufnahme_id;
aufnahme.id = aufnahme_id as string;
if (ausweisart == Enums.Ausweisart.VerbrauchsausweisWohnen) {
const id = await verbrauchsausweisWohnenSpeichern(

View File

@@ -1,5 +1,4 @@
<script lang="ts">
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import ThickArrowDown from "radix-svelte-icons/src/lib/icons/ThickArrowDown.svelte";
import {
BedarfsausweisWohnenClient,
@@ -9,8 +8,9 @@
VerbrauchsausweisWohnenClient,
} from "./types.js";
import ThickArrowUp from "radix-svelte-icons/src/lib/icons/ThickArrowUp.svelte";
import { Enums } from "#lib/client/prisma";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { Enums } from "#lib/client/prisma.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";
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let aufnahme: AufnahmeClient;
@@ -21,7 +21,9 @@
[Enums.Ausweisart.VerbrauchsausweisGewerbe]: 1000,
[Enums.Ausweisart.VerbrauchsausweisWohnen]: 250,
[Enums.Ausweisart.BedarfsausweisWohnen]: 250,
[Enums.Ausweisart.BedarfsausweisGewerbe]: 250
[Enums.Ausweisart.BedarfsausweisGewerbe]: 0,
[Enums.Ausweisart.GEGNachweisGewerbe]: 0,
[Enums.Ausweisart.GEGNachweisWohnen]: 0,
}[ausweisart];
/**
@@ -64,9 +66,9 @@
(async () => {
let result;
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
result = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt);
result = await endEnergieVerbrauchVerbrauchsausweis_2016_Client(ausweis, aufnahme, objekt);
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
result = await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis, aufnahme, objekt);
result = await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client(ausweis, aufnahme, objekt);
}
if (!result) {

View File

@@ -63,8 +63,15 @@
fuelMap[fuel[0]].push(fuel[1]);
}
let month = moment(ausweis.startdatum).month();
let year = moment(ausweis.startdatum).year();
// Falls der Ausweis bereits einmal gespeichert wurde mit einem Startdatum sollten wir dieses benutzen.
let month: number, year: number;
if (ausweis.startdatum) {
month = moment(ausweis.startdatum).get("month")
year = moment(ausweis.startdatum).get("year")
} else {
month = availableDates[availableDates.length - 1].month;
year = availableDates[availableDates.length - 1].year;
}
$: {
if (typeof month === "number" && typeof year === "number") {

View File

@@ -52,7 +52,7 @@ $: {
<!-- % Anteil Warmwasser -->
<div class="input-standard order-2 md:order-2 xl:order-2">
<Inputlabel title="% Anteil Warmwasser"></Inputlabel>
<Inputlabel title="% Anteil Kühlung"></Inputlabel>
<input
name="anteil_kuehlung_1"

View File

@@ -40,15 +40,15 @@
"Dezember",
];
const startDate = moment(aufnahme.erstellungsdatum || Date.now())
const earlistPossibleStartDate = moment(aufnahme.erstellungsdatum || Date.now())
.subtract(4, "years")
.subtract(6, "months");
const endDate = moment(aufnahme.erstellungsdatum || Date.now()).subtract(
const lastPossibleEndDate = moment(aufnahme.erstellungsdatum || Date.now()).subtract(
3,
"years"
);
for (let m = moment(startDate); m.isBefore(endDate); m.add(1, "month")) {
for (let m = moment(earlistPossibleStartDate); m.isBefore(lastPossibleEndDate); m.add(1, "month")) {
availableDates.push({
year: m.year(),
month: m.month(),
@@ -62,8 +62,15 @@
fuelMap[fuel[0]].push(fuel[1]);
}
let month = availableDates[availableDates.length - 1].month;
let year = availableDates[availableDates.length - 1].year;
// Falls der Ausweis bereits einmal gespeichert wurde mit einem Startdatum sollten wir dieses benutzen.
let month: number, year: number;
if (ausweis.startdatum) {
month = moment(ausweis.startdatum).get("month")
year = moment(ausweis.startdatum).get("year")
} else {
month = availableDates[availableDates.length - 1].month;
year = availableDates[availableDates.length - 1].year;
}
$: {
if (typeof month === "number" && typeof year === "number") {

View File

@@ -15,13 +15,21 @@
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { Enums, Objekt } from "#lib/client/prisma.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { addNotification } from "#components/Notifications/shared.js";
import { addNotification, updateNotification } from "#components/Notifications/shared.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";
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient;
export let aufnahme: AufnahmeKomplettClient;
export let rechnung: RechnungClient;
export let rechnung: RechnungClient | null;
export let objekt: Objekt;
export let benutzer: BenutzerClient;
import { FileText } from "radix-svelte-icons";
import NotificationProvider from "#components/NotificationProvider/NotificationProvider.svelte";
import DashboardNotification from "./DashboardNotification.svelte";
import { notifications } from "#components/NotificationProvider/shared.js";
import { Bell } from "radix-svelte-icons";
import { A13BerechnungRechnerischeLaufzeitHeizung } from "#lib/Berechnungen/BedarfsausweisWohnen/A13BerechnungRechnerischeLaufzeitHeizung.js";
const progress = ausweis.ausgestellt ? 100 : ausweis.bestellt ? 66 : 33;
const ausweisart = getAusweisartFromId(ausweis.id);
@@ -86,15 +94,15 @@
let calculations = null;
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
calculations = endEnergieVerbrauchVerbrauchsausweis_2016(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt);
calculations = endEnergieVerbrauchVerbrauchsausweis_2016_Client(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt);
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
calculations = endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt);
calculations = endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt);
}
async function registriernummerAnfordern() {
async function registriernummer() {
try {
const result = await api.admin.registriernummer.GET.fetch({
uid: ausweis.id
id: ausweis.id
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
@@ -114,7 +122,7 @@
async function stornieren() {
try {
const response = await api.admin.stornieren.PUT.fetch({
uid_ausweis: ausweis.id
ausweis_id: ausweis.id
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
@@ -141,17 +149,33 @@
}
}
async function ausweisAusstellen() {
async function ausstellen(post = false) {
const notification = addNotification({
message: "Ausweis wird ausgestellt.",
subtext: "Der Ausweis wird nun ausgestellt, bitte habe einen Augenblick geduld..",
type: "info",
timeout: 0,
})
try {
await api.admin.ausstellen.GET.fetch({
id_ausweis: ausweis.id
id_ausweis: ausweis.id,
post
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
ausweis.ausgestellt = true;
updateNotification(notification, {
message: "Ausweis ausgestellt.",
subtext: "Der Ausweis wurde erfolgreich ausgestellt.",
timeout: 3000,
type: "success",
})
} catch(e) {
addNotification({
updateNotification(notification, {
message: "Das hat nicht geklappt.",
subtext: e as string,
timeout: 3000,
@@ -161,64 +185,7 @@
}
</script>
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4">
<div class="max-w-screen-xl mx-auto py-6 px-4 bg-white shadow">
<!-- Obere Zeile: Titel -->
<div class="border-b flex flex-row pb-2">
<div class="text-xl font-bold">
Verbrauchsausweis Wohnen mit Beratung (Post, Same Day)
</div>
<div class="bg-red-600 ml-auto px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Gespeichert</div>
</div>
<!-- Navigation (1/3) -->
<div class="border-b pt-4 mb-4 flex justify-between items-center">
<button class="bg-gray-300 text-gray-700 px-2 py-1 rounded hover:bg-gray-400">
&laquo;
</button>
<p class="text-gray-700 font-medium">
Ausweis 1/3
</p>
<button class="bg-gray-300 text-gray-700 px-2 py-1 rounded hover:bg-gray-400">
&raquo;
</button>
</div>
<!-- Erster Block: Drei Spalten -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
<!-- Linke Spalte: Bild + ID -->
<div class="flex-shrink-0 bg-gray-100 flex flex-col items-center border text-2xl rounded-b-lg pb-2 max-w-[220px]">
<img
src="../../images/placeholder.png"
alt="Gebäudevorschau"
class="rounded-t-lg mb-2"
/>
<div class="grid grid-cols-1 md:grid-cols-2 gap-2 bg-white">
<!-- PDF-Icon / Ausweis -->
<div class="m-1">
<img
src="../../images/dashboard/AusweisKreuz.svg"
alt="PDF Symbol für Verbrauchsausweis"
class="h-auto w-auto p-2 border border-black rounded-lg"
/>
<span class="text-xs font-medium ml-2">Verbrauchsausweis</span>
</div>
<!-- PDF-Icon / Datenblatt -->
<div class="m-1">
<img
src="../../images/dashboard/DatenblattKreuz.svg"
alt="PDF Symbol für Datenblatt"
class="h-auto w-auto p-2 border border-black rounded-lg"
/>
<span class="text-xs font-medium ml-2">Datenblatt</span>
</div>
</div>
<div class="p-4">Ausweis ID: <b>BWWICR32</b></div>
</div>
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4">
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4 mr-4">
{#if ausweis.storniert}
<div
class="absolute top-0 left-0 w-full h-full bg-[rgba(0,0,0,0.7)] z-[5] rounded-lg select-none"
@@ -257,6 +224,17 @@
</ul>
</div>
<div class="flex flex-row flex-wrap items-center gap-2">
{#if ausweis.ausgestellt}
<span class="bg-green-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Ausgestellt</span>
{:else if ausweis.bestellt}
<span class="bg-primary px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Bestellt</span>
{:else}
{#if ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe || ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe}
<span class="bg-red-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Angefordert</span>
{:else}
<span class="bg-red-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Gespeichert</span>
{/if}
{/if}
<div class="text-lg font-semibold">
{#if ausweisart == Enums.Ausweisart.VerbrauchsausweisWohnen}
Verbrauchsausweis Wohnen
@@ -271,23 +249,15 @@
{:else if ausweisart == Enums.Ausweisart.BedarfsausweisGewerbe}
Bedarfsausweis Gewerbe
{/if}
</div>
</div>
<div class="badge badge-accent font-semibold text-black text-m">
{#if ausweis.ausweistyp === Enums.AusweisTyp.Beratung || ausweis.ausweistyp === Enums.AusweisTyp.BeratungXL}
(Beratung)
mit Beratung
{:else if ausweis.ausweistyp === Enums.AusweisTyp.Offline || ausweis.ausweistyp === Enums.AusweisTyp.OfflineXL}
(Offline)
Offline
{/if}
</div>
{#if ausweis.ausgestellt}
<span class="bg-green-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Ausgestellt</span>
{:else if ausweis.bestellt}
<span class="bg-primary px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Bestellt</span>
{:else}
<span class="bg-red-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Gespeichert</span>
{/if}
</div>
<div class="badge badge-accent font-semibold text-black text-m">{objekt.adresse}</div>
<div class="mb-4 flex flex-row items-center gap-4">
<div class="w-full border rounded-lg my-2">
<div class="bg-green-600 h-4 rounded-lg" class:bg-red-600={progress == 33} class:bg-primary={progress == 66} style="width: {progress}%;"></div>
@@ -296,17 +266,16 @@
>{progress}%</span
>
</div>
{#if ausweis.bestellt}
{#if ausweis.ausweistyp === Enums.AusweisTyp.Beratung || ausweis.ausweistyp === Enums.AusweisTyp.BeratungXL}
<p class="text-sm font-semibold">Sie haben Hilfe zu diesem Ausweis angefordert. Sie werden innerhalb der nächsten 48 Stunden über die hinterlegte Telefonnummer vom IB Cornelsen kontaktiert.</p>
{:else if ausweis.ausweistyp === Enums.AusweisTyp.Offline || ausweis.ausweistyp === Enums.AusweisTyp.OfflineXL}
<p class="text-sm font-semibold">Sie haben die offline Variant zu diesem Ausweis angefordert. Bitte übermitteln Sie uns die letzten drei Jahre der Energieabrechnungen Ihres Energieversorgers.</p>
{:else}
<p class="text-sm font-semibold">Der Ausweis wurde von Ihnen freigegeben und befindet sich in Prüfung vom IB Cornelsen</p>
{/if}
{/if}
{#await calculations then calculations}
<div class="flex flex-col gap-2">
<div class="flex flex-col mb-4">
<div class="flex flex-row justify-between">
<span>Erstellungsdatum</span>
<span class="font-bold text-base-content"
>{moment(aufnahme.erstellungsdatum).format(
"DD.MM.YYYY"
)}</span
>
</div>
<div class="flex flex-row justify-between">
<span>Energieverbrauch</span>
<span class="font-bold text-base-content"
@@ -319,14 +288,6 @@
>{calculations?.co2EmissionenGesamt}Kg/A</span
>
</div>
<div class="flex flex-row justify-between">
<span>Erstellungsdatum</span>
<span class="font-bold text-base-content"
>{moment(aufnahme.erstellungsdatum).format(
"DD.MM.YYYY"
)}</span
>
</div>
<div class="flex flex-row justify-between">
<span>Baujahr</span>
<span
@@ -344,16 +305,37 @@
: "N/A"}</span
>
</div>
<div class="flex flex-row justify-between">
<span>ID</span>
<span class="font-bold text-base-content"
>{id}</span
>
</div>
</div>
{/await}
<div class="flex flex-row justify-end items-center gap-4 mt-4">
<div class="flex flex-row justify-start items-center mb-4">
<a
class="p-1 rounded-lg hover:bg-gray-200 mr-2 border-2 border-gray-300"
title="PDF Herunterladen"
target="_blank"
href="/pdf/ansichtsausweis?id={ausweis.id}"
>
{#if ausweis.ausgestellt}
<img src="../../images/dashboard/AusweisHaken.svg" width="65" alt="Energieausweis">
{:else}
<img src="../../images/dashboard/AusweisKreuz.svg" width="65" alt="Energieausweis">
{/if}
</a>
<a
class="p-1 rounded-lg hover:bg-gray-200 border-2 border-gray-300"
title="PDF Herunterladen"
target="_blank"
href="/pdf/datenblatt?id={ausweis.id}"
>
{#if ausweis.ausgestellt}
<img src="../../images/dashboard/DatenblattHaken.svg" width="65" alt="Energieausweis">
{:else}
<img src="../../images/dashboard/DatenblattKreuz.svg" width="65" alt="Energieausweis">
{/if}
</a>
<div class="flex flex-col gap-2 justify-end items-center ml-4">
{#if !ausweis.storniert && !ausweis.ausgestellt}
<!--
<a
@@ -400,128 +382,264 @@
href="/angebot-anfragen/bedarfsausweis-gewerbe-anfragen?id={ausweis.id}"
>Bearbeiten</a>
{/if}
{/if}
{#if benutzer.rolle === Enums.BenutzerRolle.ADMIN}
{#if ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?id={ausweis.id}"
>Bearbeiten</a>
>Formular</a>
{:else if ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-gewerbe?id={ausweis.id}"
>Bearbeiten</a>
>Formular</a>
{:else if ausweisart === Enums.Ausweisart.BedarfsausweisWohnen}
<a
class="button text-sm"
href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude?id={ausweis.id}"
>Bearbeiten</a>
{:else if ausweisart === Enums.Ausweisart.GEGNachweisWohnen}
<a
class="button text-sm"
href="/angebot-anfragen/geg-nachweis-wohnen-anfragen?id={ausweis.id}"
>Bearbeiten</a>
{:else if ausweisart === Enums.Ausweisart.GEGNachweisGewerbe}
<a
class="button text-sm"
href="/angebot-anfragen/geg-nachweis-gewerbe-anfragen?id={ausweis.id}"
>Bearbeiten</a>
{:else if ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe}
<a
class="button text-sm"
href="/angebot-anfragen/bedarfsausweis-gewerbe-anfragen?id={ausweis.id}"
>Bearbeiten</a>
{/if}
{/if}
{#if benutzer.rolle === Enums.BenutzerRolle.ADMIN}
<!-- TODO -->
{#if ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?id={ausweis.id}"
>Formular</a>
{:else if ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe}
<a
class="button text-sm"
href="/energieausweis-erstellen/verbrauchsausweis-gewerbe?id={ausweis.id}"
>Formular</a>
{/if}
{/if}
{#if benutzer.rolle === Enums.BenutzerRolle.ADMIN}
<button class="button text-sm" on:click={ausweisAusstellen}>A</button>
<button class="button text-sm" on:click={stornieren}>S</button>
<button class="button text-sm" on:click={registriernummerAnfordern}>R</button>
<button class="button text-sm" title="Ausstellen" on:click={() => ausstellen(false)}>A</button>
<button class="button text-sm" title="Ausstellen mit Postversand" on:click={() => ausstellen(true)}>P</button>
<button class="button text-sm" title="Stornieren" on:click={stornieren}>S</button>
<button class="button text-sm" title="Registriernummer anfordern" on:click={registriernummer}>R</button>
{/if}
</div>
</div>
<div class="mt-8">
{#if ausweis.bestellt}
{#if ausweis.ausweistyp === Enums.AusweisTyp.Beratung || ausweis.ausweistyp === Enums.AusweisTyp.BeratungXL}
<p class="text-sm">Sie haben Hilfe zu diesem Ausweis angefordert. Sie werden <span class="font-bold">innerhalb der nächsten 48 Stunden</span> über die hinterlegte Telefonnummer vom IB Cornelsen kontaktiert.</p>
{:else if ausweis.ausweistyp === Enums.AusweisTyp.Offline || ausweis.ausweistyp === Enums.AusweisTyp.OfflineXL}
<p class="text-sm">Sie haben die offline Variant zu diesem Ausweis angefordert. Bitte <span class="font-bold">übermitteln Sie uns die letzten drei Jahre der Energieabrechnungen</span> Ihres Energieversorgers.</p>
{:else if !ausweis.ausgestellt}
<p class="text-sm">Der Ausweis wurde von Ihnen freigegeben und befindet sich <span class="font-bold">in Prüfung durch IB Cornelsen</span></p>
{/if}
{/if}
</div>
</div>
</div>
<a
class="p-2 rounded-lg hover:bg-gray-200"
title="PDF Herunterladen"
target="_blank"
href="/pdf/ansichtsausweis?id={ausweis.id}"
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4 mr-4">
<div class="card-body">
<div class="flex flex-row flex-wrap items-center gap-2">
<div class="text-lg font-semibold">{aufnahme.gebaeudetyp}
{#if (aufnahme.einheiten > 0 && aufnahme.einheiten !== null)}
mit {aufnahme.einheiten} Wohneinheiten
{/if}
</div>
<div class="text-sm">
<span class="font-bold">Gebäude (Bj {aufnahme.baujahr_gebaeude})</span> mit
{#if aufnahme.flaeche > 0 && aufnahme.flaeche !== null}
{aufnahme.flaeche} m² Wohnfläche
sowie
{/if}
{aufnahme.nutzflaeche} m² energetische Nutzfläche. Als Ausstellgrund wurde {ausweis.ausstellgrund} angegeben.
{aufnahme.gebaeudeteil === "Wohnen"
? "Die eingegebenen Daten beziehen sich auf den Wohnteil eines gemischt genutzten Gebäudes."
: "Die eingegebenen Daten beziehen sich auf das gesamte Gebäude."}
{aufnahme.saniert ? "Das Gebäude ist in unsaniertem Zustand." : "Das Gebäude ist in saniertem Zustand."}
</div>
{#if ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe}
<div class="text-sm">
<span class="font-bold">Gebäudestrom</span> der Jahre vom
{moment(ausweis.startdatum).format("MM.YYYY")} bis {moment(ausweis.startdatum).add("3", "years").format("MM.YYYY")} beträgt
{ausweis.strom_1} kWh, {ausweis.strom_2} kWh und {ausweis.strom_3} kWh.
Im Stromverbrauch enthalten sind
{ausweis.stromverbrauch_enthealt_heizung ? "Heizung, " : ""}
{ausweis.stromverbrauch_enthaelt_warmwasser ? "Warmwasser, " : ""}
{ausweis.stromverbrauch_enthaelt_lueftung ? "Lüftung, " : ""}
{ausweis.stromverbrauch_enthaelt_beleuchtung ? "Beleuchtung, " : ""}
{ausweis.stromverbrauch_enthaelt_kuehlung ? "Kühlung, " : ""}
{#if ausweis.stromverbrauch_sonstig !== null}
sowie {ausweis.stromverbrauch_enthaelt_sonstige}.
{/if}
</div>
{/if}
<div class="text-sm">
<span class="font-bold">Heizung (Bj {aufnahme.baujahr_heizung})</span> wird mit {ausweis.brennstoff_1} betrieben. Die Verbräuche vom
{moment(ausweis.startdatum).format("MM.YYYY")} bis {moment(ausweis.startdatum).add("3", "years").format("MM.YYYY")} betragen
{ausweis.verbrauch_1} {ausweis.einheit_1}, {ausweis.verbrauch_2} {ausweis.einheit_1} und {ausweis.verbrauch_3} {ausweis.einheit_1}.
{#if ausweis.zusaetzliche_heizquelle} -
Eine weitere Heizung wird mit {ausweis.brennstoff_2} betrieben mit den Verbräuchen {ausweis.verbrauch_4} {ausweis.einheit_2}, {ausweis.verbrauch_5}
{ausweis.einheit_2} und {ausweis.verbrauch_6} {ausweis.einheit_2}.
{/if}
</div>
<div class="text-sm">
{#if ausweis.anteil_warmwasser_1 !== null && ausweis.anteil_warmwasser_1 > 0}
{#if aufnahme.solarsystem_warmwasser}
Da ein Solarsystem für Warmwasser vorhanden ist,
wurde ein Warmwasseranteil von {ausweis.anteil_warmwasser_1 * 0.6}% berücksichtigt.
{:else}
Es wurde ein Warmwasseranteil von {ausweis.anteil_warmwasser_1}% berücksichtigt.
{/if}
{:else}
{#if aufnahme.solarsystem_warmwasser}
Da ein Solarsystem für Warmwasser vorhanden ist, wurde ein reduzierter Warmwasserzuschlag von 12 kWh/m²a angesetzt.
{:else}
Es wurde ein Warmwasserzuschlag von 20 kWh/m²a angesetzt.
{/if}
{/if}
{#if !ausweis.alternative_heizung && !ausweis.alternative_warmwasser && !ausweis.alternative_lueftung && !ausweis.alternative_kuehlung}
Alternative Energieversorgung wird nicht verwendet
{:else}
Alternative Energieversorgung wird verwendet für {ausweis.alternative_heizung ? "Heizung, " : ""}{ausweis.alternative_warmwasser ? "Warmwasser, " : ""}{ausweis.alternative_lueftung ? "Lüftung, " : ""}{ausweis.alternative_kuehlung ? "Kühlung, " : ""}
{/if}.
Der Leerstand beträgt {aufnahme.leerstand}%. Das Gebäude verfügt über eine
{#if aufnahme.lueftung === Enums.Lueftungskonzept.Fensterlueftung}
Fensterlüftung
{:else if aufnahme.lueftung === Enums.Lueftungskonzept.Schachtlueftung}
Schachtlüftung
{:else if aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageMitWaermerueckgewinnung}
Lüftungsanlage mit Wärmerückgewinnung
{:else if aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageOhneWaermerueckgewinnung}
Lüftungsanlage ohne Wärmerückgewinnung
{/if}
{#if ausweis.kuehlung_enthalten && ausweis.kuehlung_entahlten !== null}
und wird thermisch gekühlt.
{:else if aufnahme.kuehlung === "1" && aufnahme.kuhlung !== null}
und wird gekühlt.
{:else}
und wird nicht gekühlt.
{/if}
</div>
<div class="text-sm">
<span class="font-bold">Heizung: </span>
{aufnahme.zentralheizung ? "Zentral/Etagenheizung, " : ""}
{aufnahme.einzelofen ? "Einzelofen, " : ""}
{aufnahme.waermepumpe ? "Wärmepumpe, " : ""}
{aufnahme.niedertemperatur_kessel ? "Niedertemperaturkessel, " : ""}
{aufnahme.standard_kessel ? "Standardkessel, " : ""}
{aufnahme.durchlauf_erhitzer ? "Durchlauferhitzer, " : ""}
{aufnahme.solarsystem_warmwasser ? "Solarsystem für Warmwasser, " : ""}
{aufnahme.waermepumpe ? "Wärmepumpe, " : ""}
{aufnahme.brennwert_kessel ? "Brennwertkessel, " : ""}
{aufnahme.standard_kessel ? "Standardkessel, " : ""}
{aufnahme.warmwasser_rohre_gedaemmt ? "Warmwasserrohre gedämmt, " : ""}
{aufnahme.heizungsrohre_gedaemmt ? "Heizungsrohre gedämmt, " : ""}
{aufnahme.photovoltaik ? "Photovoltaik, " : ""}
{aufnahme.raum_temperatur_regler ? "Raumtemperaturregler, " : ""}
{aufnahme.zirkulation ? "Zirkulation, " : ""}
</div>
<div class="text-sm">
<span class="font-bold">Fenster: </span>
{aufnahme.isolier_verglasung ? "Fenster Isolierglas, " : ""}
{aufnahme.dreifach_verglasung ? "Dreifachverglasung, " : ""}
{aufnahme.doppel_verglasung ? "Doppelverglasung, " : ""}
{aufnahme.einfach_verglasung ? "Einfachverglasung, " : ""}
{aufnahme.fenster_dicht ? "Fenster dicht, " : ""}
{aufnahme.fenster_teilweise_undicht ? "Fenster teilweise undicht, " : ""}
{aufnahme.tueren_undicht ? "Türen undicht, " : ""}
{aufnahme.tueren_dicht ? "Türen dicht, " : ""}
{aufnahme.rolllaeden_kaesten_gedaemmt ? "Rollladenkästen gedämmt" : ""}
</div>
<div class="text-sm">
<span class="font-bold">Dämmung: </span>
{aufnahme.dachgeschoss_gedaemmt ? "Dachgeschoss gedämmt, " : ""}
{aufnahme.aussenwand_gedaemmt ? "Außenwand gedämmt, " : ""}
{aufnahme.keller_decke_gedaemmt ? "Kellerdecke gedämmt, " : ""}
{aufnahme.keller_wand_gedaemmt ? "Kellerwand gedämmt, " : ""}
{aufnahme.oberste_geschossdecke_gedaemmt ? "oberste Geschossdecke gedämmt, " : ""}
{aufnahme.oberste_geschossdecke_min_12cm_gedaemmt ? "oberste Geschossdecke min. 12cm gedämmt, " : ""}
{aufnahme.dachgeschoss_min_12cm_gedaemmt ? "Dachgeschoss min. 12cm gedämmt, " : ""}
{aufnahme.aussenwand_min_12cm_gedaemmt ? "Außenwand min. 12cm gedämmt" : ""}
</div>
<div class="text-xs space-y-1 p-2">
<span class="font-semibold">Hiermit bestätige ich {benutzer.vorname} {benutzer.name} als Besteller folgende Angaben:</span><br>
{#if ausweis.pruefpunkt_heizungsalter}
<div>Das Heizungsalter ist jünger als 3 Jahre. Es betrifft einen Heizungstausch ohne energetische Verbesserung.</div>
{/if}
{#if ausweis.pruefpunkt_verbrauch_niedrig}
<div>Ich habe die Verbrauchsangaben kontrolliert. Der niedrige Energiekennwert ist korrekt.</div>
{/if}
{#if ausweis.pruefpunkt_verbrauch_hoch}
<div>Ich habe die Verbrauchsangaben kontrolliert. Der hohe Energiekennwert ist korrekt.</div>
{/if}
{#if ausweis.pruefpunkt_verbrauch_null}
<div>Die eingegebenen Heizverbräuche sind korrekt und alle 3 Felder wurden vollständig eingegeben.</div>
{/if}
{#if ausweis.pruefpunkt_verbrauch_abweichung}
<div>Die eingegebenen Heizverbräuche sind korrekt und die Abweichung lässt sich begründen.</div>
{/if}
{#if ausweis.pruefpunkt_wohnflaeche_einheiten}
<div>Die Angabe der Wohnfläche ist korrekt und bezieht sich auf das gesamte Gebäude.</div>
{/if}
{#if ausweis.pruefpunkt_strom_null}
<div>Die eingegebenen Stromverbräuche sind korrekt. Alle 3 Felder wurden vollständig eingegeben.</div>
{/if}
{#if ausweis.pruefpunkt_strom_abweichung}
<div>Die eingegebenen Stromverbräuche sind korrekt und die Abweichung lässt sich begründen.</div>
{/if}
{#if ausweis.pruefpunkt_heizungsanlage}
<div>Das Baujahr der Heizungsanlage ist kleiner als das Baujahr des Gebäudes und begründet.</div>
{/if}
{#if ausweis.pruefpunkt_anteil_warmwasser}
<div>Ich habe den Warmwasseranteil nochmal überprüft. Dieser ist korrekt und begründet.</div>
{/if}
{#if ausweis.pruefpunkt_wohnflaeche}
<div>Ich habe die Wohnfläche nochmal überprüft und bestätige die Richtigkeit. Es handelt sich lediglich um die Wohnfläche innerhalb des Gebäudes.</div>
{/if}
<div>Ich habe die AGB und DSGVO im <a href="/impressum#agb" target="_blank" rel="noopener noreferrer">Impressum</a> gelesen und akzeptiert. Ich bestätige die Richtigkeit der Eingabe.</div>
</div>
</div>
</div>
</div>
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4">
<div class="card-body">
<div class="flex flex-row flex-wrap items-center gap-2">
<div class="text-sm">
<span class="font-bold">Rechnungsadresse</span><br>
{rechnung?.empfaenger},
{#if rechnung?.zusatzzeile !== null}
{rechnung?.zusatzzeile},
{/if}
{rechnung?.strasse}, {rechnung?.plz} {rechnung?.ort}
</div>
<div class="text-sm mb-2">
<span class="font-bold">Versandadresse</span><br>
{rechnung?.versand_empfaenger},
{#if rechnung?.versand_zusatzzeile !== null}
{rechnung?.versand_zusatzzeile},
{/if}
{rechnung?.versand_strasse}, {rechnung?.versand_plz} {rechnung?.versand_ort}
</div>
<div class="text-lg font-semibold">Unterlagen</div>
<div class="text-sm">
<a href="" target="_blank" class="text-black flex flex-row items-center gap-2 bg-base-200 rounded-lg p-1"><FileText size={24}></FileText>Grundrissplan_O....pdf</a>
<a href="" target="_blank" class="text-black flex flex-row items-center gap-2 bg-base-200 rounded-lg p-1"><FileText size={24}></FileText>Grundrissplan_OG....pdf</a>
<a href="" target="_blank" class="text-black flex flex-row items-center gap-2 bg-base-200 rounded-lg p-1"><FileText size={24}></FileText>Grundrissplan_OG....pdf</a>
</div>
</div>
<div class="dropdown dropdown-top items-end absolute bottom-4 right-4 z-50">
<div class="indicator">
{#if Object.keys($notifications).length > 0}
<span class="indicator-item badge badge-accent text-xs"
>{Object.keys($notifications).length}</span
>
<img src="/images/ausweis.webp" width="32" alt="Energieausweis">
</a>
<a
class="p-2 rounded-lg hover:bg-gray-200"
title="PDF Herunterladen"
target="_blank"
href="/pdf/datenblatt?id={ausweis.id}"
{/if}
<button
tabindex="0"
class="hover:bg-gray-200 p-3 rounded-lg"
>
<img src="/images/datenblatt.webp" width="32" alt="Datenblatt">
</a>
</div>
</div>
</div>
<div class="flex-shrink-0 bg-gray-100 flex flex-col border text-xl rounded-lg p-4">
<p><b>Ausweisdaten</b><br>Anlass: Vermietung/Verkauf<br>
Gebäudetyp: Mehrfamilienhaus<br>
Anzahl Wohneinheiten: 3<br>
Keller beheizt / DG beheizt<br>
Gebäudeteil: gesamt<br>
<br>
<b>Heizverbräuche (kWh, kg)</b><br>vom 03.2022 - 03.2025<br>
Erdgas 13600, 14600, 15000<br>Brennholz 400, 500, 600<br>
Warmwasser enthalten, 20%<br>
Alternative Energieversorgung: Warmwasser, Heizung, Lüftung, Kühlung<br>
Leerstand 20%, Fensterlüftung, Kühlung<br><br>
<b>Sanierungszustand:</b><br>Zentralheizung, Warmwasserrohre gedämmt, Brennwertkessel, Photovoltaik, Dreifachverglasung, alle Fenster dicht, Dachgeschoß gedämmt, Außenwand gedämmt</p>
</div>
</div>
<!-- Zweiter Block: Ansprechpartner und Ausweisdaten in zwei Spalten -->
<div class="flex flex-row md:flex-row gap-4 mb-4">
<p class="text-lg text-gray-700 mb-1">
<strong>Besteller:</strong> Norma Müller
</p>
<p class="text-lg text-gray-700">
<strong>Telefon:</strong> 0700 / 123456
</p>
<p class="text-lg text-gray-700">
<strong>E-Mail:</strong> norma.mueller@web.de
</p>
<p class="text-lg text-gray-700">
<strong>Erstelldatum:</strong> 22.03.2025
</p>
</div>
<!-- Fußzeile: Navigation (1/3) -->
<div class="border-t pt-4 flex justify-between items-center">
<button class="bg-gray-300 text-gray-700 px-2 py-1 rounded hover:bg-gray-400">
&laquo;
</button>
<p class="text-gray-700 font-medium">
Ausweis 1/3
</p>
<button class="bg-gray-300 text-gray-700 px-2 py-1 rounded hover:bg-gray-400">
&raquo;
<Bell size={24} />
</button>
</div>
<ul
class="dropdown-content mb-2 border border-base-300 z-10 menu py-4 px-0 bg-base-200 rounded-box w-80"
>
<NotificationProvider component={DashboardNotification} />
</ul>
</div>
</div>
</div>
@@ -562,3 +680,10 @@
</div>
</div>
</dialog>
<style lang="postcss">
*{@apply font-sans
}
</style>

View File

@@ -47,19 +47,6 @@
<div class="text-sm text-center">Energieausweis</div>
</a>
{/if}
{#if objekt.aufnahmen.at(-1)?.bedarfsausweise_wohnen.length}
{@const ausweis = objekt.aufnahmen.at(-1)?.bedarfsausweise_wohnen.at(-1)}
<a href="/pdf/ansichtsausweis?id={ausweis.id}" target="_blank">
<div class="inline-block border rounded-lg bg-white">
{#if ausweis?.ausgestellt}
<img src="/images/dashboard/AusweisHaken.svg" class="h-auto w-auto max-h-[150px] max-w-full object-contain p-1" alt="Energieausweis ausgestellt">
{:else}
<img src="/images/dashboard/AusweisKreuz.svg" class="h-auto w-auto max-h-[150px] max-w-full object-contain p-1" alt="Energieausweis ausgestellt">
{/if}
</div>
<div class="text-sm text-center">Energieausweis</div>
</a>
{/if}
</div>
<div class="flex flex-col gap-4">
{#each objekt.aufnahmen as aufnahme}

View File

@@ -1,147 +1,206 @@
<script lang="ts">
import { ripple } from "svelte-ripple-action";
import type { RippleOptions } from "svelte-ripple-action/dist/constants.js";
import { Reader, Bell, Gear, LockClosed, CaretDown } from "radix-svelte-icons"
import {
Reader,
Bell,
Gear,
LockClosed,
CaretDown,
} from "radix-svelte-icons";
import NotificationProvider from "#components/NotificationProvider/NotificationProvider.svelte";
import DashboardNotification from "./DashboardNotification.svelte";
import { notifications } from "#components/NotificationProvider/shared.js";
import ThemeController from "#components/ThemeController.svelte";
import { BenutzerClient, ObjektKomplettClient } from "#components/Ausweis/types.js";
import {
BenutzerClient,
ObjektKomplettClient,
} from "#components/Ausweis/types.js";
export let lightTheme: boolean;
export let benutzer: BenutzerClient;
const rippleOptions: RippleOptions = {
center: false,
color: lightTheme ? "rgba(233,233,233,0.1)" : "rgba(113, 128, 150, 0.1)",
};
let headerOpen = false;
</script>
<aside class:hidden={!headerOpen} class="fixed left-0 top-16 w-full h-[calc(100%-4rem)] flex md:relative md:h-auto md:w-auto md:top-0 md:flex bg-base-200 border-r border-r-base-300 flex-col py-4">
<div class="flex flex-row items-center px-4">
<aside class="rounded-lg bg-white box px-6 py-5">
<div class="flex flex-row items-center">
<div class="flex flex-row mr-6">
<a href="/"><img src="/images/header/logo-IBC-big.svg" class="h-16" alt="IBCornelsen - Logo"/></a>
<a href="/"
><img
src="/images/header/logo-IBC-big.svg"
class="h-16"
alt="IBCornelsen - Logo"
/></a
>
</div>
<div class="flex-col items-end">
<div class="text-base-content font-semibold text-left flex"
>{benutzer.vorname} {benutzer.name}</div>
<div class="text-base-content font-semibold text-left flex">
{benutzer.vorname}
{benutzer.name}
</div>
<div class="text-base-content text-sm flex">{benutzer.email}</div>
<a href="/auth/logout" class="text-xs">Logout</a>
</div>
</div>
<div class="flex flex-col gap-2 mt-0 md:mt-8 px-0">
<a use:ripple={rippleOptions} class="button-tab" href="/dashboard">
<a class="button-tab" href="/dashboard">
<Reader width={22} height={22} />
Vorgänge
</a>
<a use:ripple={rippleOptions} class="button-tab" href="/dashboard">
<Reader width={22} height={22} />
Inbox
Ausweise
</a>
<hr class="border-gray-600">
<hr class="border-gray-600" />
Besteller
<div class="flex flex-row mb-4">
<div class="item-center mr-4">
<img src="../../images/profile-placeholder.svg" alt="profile icon" width="40" height="40" />
</div>
<div>
<div>
MIchael Makler
</div>
<div class="text-xs text-gray-500">
Eigentümer oder im Auftrag
</div>
<div class="text-xs text-gray-500">
<!-- Soll für den Aussteller sichtbar sein -->
Telefon {benutzer.telefon}
</div>
</div>
</div>
<hr class="border-gray-600" />
<!--
<div class="text-base-content text-xl px-4 mt-4">Mitwirkende</div>
<div class="flex flex-col gap-4 px-4">
{#each [
{ name: "Max Mustermann", image: "/images/profile-placeholder.svg", profession: "Architekt" },
{ name: "Erika Musterfrau", image: "/images/profile-placeholder.svg", profession: "Ingenieurin" },
{ name: "Hans Beispiel", image: "/images/profile-placeholder.svg", profession: "Energieberater" },
{ name: "Anna Beispiel", image: "/images/profile-placeholder.svg", profession: "Bauleiterin" }
] as person}
<div class="flex items-center gap-4">
<img src={person.image} alt={person.name} class="w-12 h-12 rounded-full object-cover" />
<div class="flex flex-col">
<span class="text-base-content font-medium">{person.name}</span>
<span class="text-sm text-gray-500">{person.profession}</span>
Mitwirkende
<div class="flex flex-row mb-1">
<div class="item-center mr-4">
<img src="../../images/profile-placeholder.svg" alt="profile icon" width="40" height="40" />
</div>
<button class="ml-auto btn btn-primary btn-sm">Chat</button>
<div>
<div>
Ernie Energieberater
</div>
{/each}
<div class="text-xs text-gray-500">
Energieberater
</div>
</div>
</div>
<div class="flex flex-row mb-1">
<div class="item-center mr-4">
<img src="../../images/profile-placeholder.svg" alt="profile icon" width="40" height="40" />
</div>
<div>
<div>
Peter Planer
</div>
<div class="text-xs text-gray-500">
Architekt
</div>
</div>
</div>
<div class="flex flex-row mb-1">
<div class="item-center mr-4">
<img src="../../images/profile-placeholder.svg" alt="profile icon" width="40" height="40" />
</div>
<div>
<div>
Hans Meier
</div>
<div class="text-xs text-gray-500">
Eigentümer
</div>
</div>
</div>
<hr class="border-gray-600" />
Experten in der Nähe
<div class="flex flex-row mb-1">
<div class="item-center mr-4">
<img src="../../images/profile-placeholder.svg" alt="profile icon" width="40" height="40" />
</div>
<div>
<div>
Thorsten Maas
</div>
<div class="text-xs text-gray-500">
Energieberater
</div>
</div>
</div>
<div class="flex flex-row mb-1">
<div class="item-center mr-4">
<img src="../../images/profile-placeholder.svg" alt="profile icon" width="40" height="40" />
</div>
<div>
<div>
Herbert Holm
</div>
<div class="text-xs text-gray-500">
Gutachter
</div>
</div>
</div>
<hr class="border-gray-600" />
<div class="flex justify-end mt-2 mb-2">
<button class="button flex flex-row rounded-lg gap-2 bg-secondary text-white text-center">
Einladen
</button>
</div>
-->
<!-- <button use:ripple={rippleOptions} class="button-tab">
<EnvelopeClosed width={22} height={22} />
Kontakt
</button>
<li><details class="[&_.caret]:open:rotate-180">
<summary class="button-tab w-full outline-0 hover:outline-0">
<Cube width={22} height={22} />
Services <CaretDown size={24} class="caret ml-auto transition-transform"></CaretDown></summary>
<ul>
<li>
<button use:ripple={rippleOptions} class="button-tab">
Kontakt
</button>
</li>
<li>
<button use:ripple={rippleOptions} class="button-tab">
Kontakt
</button>
</li>
</ul>
</details></li> -->
{#if benutzer.rolle === "ADMIN"}
<li><details class="[&_.caret]:open:rotate-180" open>
<summary class="button-tab w-full outline-0 hover:outline-0 cursor-pointer">
<li>
<details class="[&_.caret]:open:rotate-180" open>
<summary
class="button-tab w-full outline-0 hover:outline-0 cursor-pointer"
>
<LockClosed width={22} height={22} />
Admin <CaretDown size={24} class="caret ml-auto transition-transform"></CaretDown></summary>
Admin <CaretDown
size={24}
class="caret ml-auto transition-transform"
></CaretDown></summary
>
<ul>
<li>
<a use:ripple={rippleOptions} class="button-tab" href="/dashboard/admin/ausweise-pruefen">
<a
class="button-tab"
href="/dashboard/admin/ausweise-pruefen"
>
Ausweise Prüfen
</a>
</li>
<li>
<a use:ripple={rippleOptions} class="button-tab" href="/dashboard/admin/impersonate-user">
<a
class="button-tab"
href="/dashboard/admin/impersonate-user"
>
Impersonate User
</a>
</li>
</ul>
</details></li>
</details>
</li>
{/if}
</div>
<div class="mt-10 flex flex-col gap-4 px-8">
<div class="flex flex-row justify-between items-center">
<ThemeController bind:lightTheme></ThemeController>
<div class="dropdown dropdown-top">
<div class="indicator">
{#if Object.keys($notifications).length > 0}
<span class="indicator-item badge badge-accent text-xs">{Object.keys($notifications).length}</span>
{/if}
<button tabindex="0" class="hover:bg-gray-200 p-3 rounded-lg">
<Bell size={24} />
</button>
</div>
<ul class="dropdown-content mb-2 border border-base-300 z-10 menu py-4 px-0 bg-base-200 rounded-box w-80">
<NotificationProvider component={DashboardNotification} />
</ul>
</div>
<a href="/dashboard/einstellungen"
<div class="items-end bottom-4 right-4 z-50 mt-4">
<div class="flex flex-row justify-end items-end">
<a
href="/dashboard/einstellungen"
class="hover:bg-gray-200 p-3 rounded-lg"
>
<Gear size={24} />
</a>
</div>
</div>
<div class="divider px-8"></div>
<a
href="/dashboard/einstellungen"
use:ripple={rippleOptions}
class="hover:bg-gray-200 no-animation focus:shadow-none justify-start py-4 h-auto px-8 rounded-none w-full flex flex-row gap-4"
>
</a>
</aside>
<style>

View File

@@ -28,6 +28,12 @@ export function updateNotification(uid: string, updater: Partial<Notification>)
value[uid] = { ...defaults, ...value[uid], ...updater } as Notification;
return value;
})
if (updater.timeout) {
setTimeout(() => {
deleteNotification(uid);
}, updater.timeout);
}
}
export function addNotification(notification: Partial<Notification>): string {

View File

@@ -1,5 +1,5 @@
import * as z from "zod"
import { Ausstellgrund, AusweisTyp } from "@prisma/client"
import { Ausstellgrund, AusweisTyp, Ausweisart } from "@prisma/client"
export const BedarfsausweisGewerbeSchema = z.object({
id: z.string(),
@@ -20,6 +20,7 @@ export const BedarfsausweisGewerbeSchema = z.object({
bauteilaktivierung: z.boolean().nullish(),
klimatisierung: z.boolean().nullish(),
nachweistyp: z.nativeEnum(AusweisTyp),
ausweisart: z.nativeEnum(Ausweisart),
created_at: z.date(),
updated_at: z.date(),
benutzer_id: z.string().describe("Die ID des Benutzers, welchem dieser Ausweis gehört").nullish(),

View File

@@ -1,5 +1,5 @@
import * as z from "zod"
import { Ausstellgrund, AusweisTyp } from "@prisma/client"
import { Ausstellgrund, AusweisTyp, Ausweisart } from "@prisma/client"
export const BedarfsausweisWohnenSchema = z.object({
id: z.string(),
@@ -86,6 +86,7 @@ export const BedarfsausweisWohnenSchema = z.object({
pruefpunkt_geometrie: z.boolean().nullish(),
pruefpunkt_fenster: z.boolean().nullish(),
ausweistyp: z.nativeEnum(AusweisTyp),
ausweisart: z.nativeEnum(Ausweisart),
rechnung_id: z.string().nullish(),
aufnahme_id: z.string().describe("ID der korrespondierenden Gebäudeaufnahme"),
})

View File

@@ -1,5 +1,5 @@
import * as z from "zod"
import { Ausstellgrund, AusweisTyp } from "@prisma/client"
import { Ausstellgrund, AusweisTyp, Ausweisart } from "@prisma/client"
export const GEGNachweisGewerbeSchema = z.object({
id: z.string(),
@@ -10,6 +10,7 @@ export const GEGNachweisGewerbeSchema = z.object({
zurueckgestellt: z.boolean().describe("Falls der Nachweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen").nullish(),
beschreibung: z.string().describe("Beschreibung des Bauvorhabens").nullish(),
nachweistyp: z.nativeEnum(AusweisTyp),
ausweisart: z.nativeEnum(Ausweisart),
created_at: z.date(),
updated_at: z.date(),
benutzer_id: z.string().describe("Die ID des Benutzers, welchem dieser Ausweis gehört").nullish(),

View File

@@ -1,5 +1,5 @@
import * as z from "zod"
import { Ausstellgrund, AusweisTyp } from "@prisma/client"
import { Ausstellgrund, AusweisTyp, Ausweisart } from "@prisma/client"
export const GEGNachweisWohnenSchema = z.object({
id: z.string(),
@@ -10,6 +10,7 @@ export const GEGNachweisWohnenSchema = z.object({
zurueckgestellt: z.boolean().describe("Falls der Nachweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen").nullish(),
beschreibung: z.string().describe("Beschreibung des Bauvorhabens").nullish(),
nachweistyp: z.nativeEnum(AusweisTyp),
ausweisart: z.nativeEnum(Ausweisart),
created_at: z.date(),
updated_at: z.date(),
benutzer_id: z.string().describe("Die ID des Benutzers, welchem dieser Ausweis gehört").nullish(),

View File

@@ -1,5 +1,5 @@
import * as z from "zod"
import { Ausstellgrund, AusweisTyp } from "@prisma/client"
import { Ausstellgrund, AusweisTyp, Ausweisart } from "@prisma/client"
export const VerbrauchsausweisGewerbeSchema = z.object({
id: z.string(),
@@ -52,6 +52,7 @@ export const VerbrauchsausweisGewerbeSchema = z.object({
created_at: z.date(),
updated_at: z.date(),
ausweistyp: z.nativeEnum(AusweisTyp),
ausweisart: z.nativeEnum(Ausweisart),
pruefpunkt_heizungsalter: z.boolean().nullish(),
pruefpunkt_verbrauch_niedrig: z.boolean().nullish(),
pruefpunkt_verbrauch_hoch: z.boolean().nullish(),

View File

@@ -1,5 +1,5 @@
import * as z from "zod"
import { Ausstellgrund, AusweisTyp } from "@prisma/client"
import { Ausstellgrund, AusweisTyp, Ausweisart } from "@prisma/client"
export const VerbrauchsausweisWohnenSchema = z.object({
id: z.string().describe("ID des Ausweises"),
@@ -38,6 +38,7 @@ export const VerbrauchsausweisWohnenSchema = z.object({
beschreibung: z.string().nullish(),
kontrolldatei_angefragt: z.boolean().describe("Ob bei der Anfrage der Registriernummer eine Kontrolldatei angefragt wurde").nullish(),
ausweistyp: z.nativeEnum(AusweisTyp),
ausweisart: z.nativeEnum(Ausweisart),
created_at: z.date(),
updated_at: z.date(),
pruefpunkt_heizungsalter: z.boolean().nullish(),

View File

@@ -3,22 +3,19 @@
import "../style/global.css";
import "../../svelte-dialogs.config.js";
import DashboardSidebar from "../components/Dashboard/DashboardSidebar.svelte";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import { BenutzerClient, ObjektClient } from "#components/Ausweis/types";
const valid = validateAccessTokenServer(Astro)
if (!valid) {
Astro.redirect("/auth/login", 302)
}
import { BenutzerClient } from "#components/Ausweis/types";
export interface Props {
title: string;
user: BenutzerClient
user: BenutzerClient;
}
const { title, user } = Astro.props;
if (!user) {
Astro.redirect("/auth/login", 302);
}
const schema = JSON.stringify({
"@context": "http://schema.org",
"@type": "Corporation",
@@ -53,22 +50,22 @@ let lightTheme = Astro.cookies.get("theme")?.value === "light";
if (import.meta.env.PROD) {
H.init("1jdkoe52", {
serviceName: "online-energieausweis",
backendUrl: "https://highlight-backend.online-energieausweis.org/public",
backendUrl:
"https://highlight-backend.online-energieausweis.org/public",
tracingOrigins: true,
networkRecording: {
enabled: true,
recordHeadersAndBody: true
}
})
recordHeadersAndBody: true,
},
});
}
</script>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
<script type="application/ld+json" set:html={schema}></script>
<script type="application/ld+json" set:html={schema} />
<link rel="icon" type="image/svg+xml" href="/favicon.jpg" />
<meta
@@ -112,7 +109,6 @@ let lightTheme = Astro.cookies.get("theme")?.value === "light";
</head>
<body>
<main
class="p-0 grid max-w-[1920px]
xs:grid-cols-[minmax(1fr,1fr)] xs:gap-1 xs:p-0
@@ -122,16 +118,15 @@ let lightTheme = Astro.cookies.get("theme")?.value === "light";
xl:grid-cols-[minmax(150px,350px)1fr] xl:gap-4 xl:p-6
2xl:grid-cols-[minmax(150px,300px)1fr] 2xl:gap-5 2xl:p-6"
>
<DashboardSidebar
lightTheme={lightTheme}
benutzer={user}
client:load
/>
<DashboardSidebar lightTheme={lightTheme} benutzer={user} client:load>
</DashboardSidebar>
<article class="box rounded-tl-none
xl:px-10 py-8">
<article class="box px-6 py-5 h-full">
<slot />
</article>
</main>
</body>
</html>

View File

@@ -1,42 +0,0 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { z } from "zod";
import { verbrauchsausweisWohnenPDFValidator } from "./validators/verbrauchsausweis-wohnen-pdf-validator";
export function convertAusweisData(
inputs: Partial<VerbrauchsausweisWohnenClient>
): Record<string, string> {
// Wir wollen alle Werte zu einem Flachen Objekt umwandeln, sodass wir dass später benutzen können.
// Dazu kommen noch einige wichtige Eigenschaften die man im PDF brauchen könnte.
let pdfInputs: z.infer<typeof verbrauchsausweisWohnenPDFValidator> = {
...inputs,
pdf: {
"brennstoff": [inputs.aufnahme?.brennstoff_1, inputs.aufnahme?.brennstoff_2].filter(x => x).join(", ")
}
}
let result = recursiveFlatten(inputs, "");
// Außerdem müssen wir alle Werte zu strings umwandeln.
for (const key in result) {
result[key] = String(result[key]);
}
return result;
}
function recursiveFlatten(obj: any, parentKey = ""): Record<string, string> {
const result: Record<string, string> = {};
for (const key in obj) {
const value = obj[key];
const newKey = parentKey ? `${parentKey}.${key}` : key;
if (typeof value === "object") {
Object.assign(result, recursiveFlatten(value, newKey));
} else {
result[newKey] = value;
}
}
return result;
}

View File

@@ -2,7 +2,8 @@ import { AufnahmeClient, ObjektClient, VerbrauchsausweisGewerbeClient } from "#c
import { getKlimafaktoren } from "#lib/Klimafaktoren.js";
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor.js";
import moment from "moment";
import bauwerkskatalog from "./bauwerkskatalog.json" assert { type: "json" }
import bauwerkskatalog from "./bauwerkskatalog.json" with { type: "json" }
import { getKlimafaktorenServer } from "#lib/server/klimafaktoren.js";
function vergleichsWertNichtWohngebaeude(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient) {
let tekWerte = new Array(8).fill(0);
@@ -59,43 +60,13 @@ function vergleichsWertNichtWohngebaeude(ausweis: VerbrauchsausweisGewerbeClient
* @param Ausweis ausweis Ein Ausweis dessen Energiebedarf berechnet werden soll
* @return VerbrauchsausweisGewerbeCalculationResult
*/
export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient) {
if (!aufnahme || !objekt || !ausweis) {
export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, klimafaktoren: { month: number, year: number, klimafaktor: number }[]) {
if (!aufnahme || !objekt || !ausweis || !klimafaktoren) {
return null;
}
const nutzflaeche = aufnahme.nutzflaeche || 0;
let startdatum = moment(ausweis.startdatum);
let klimafaktoren: Awaited<ReturnType<typeof getKlimafaktoren>> = [{
month: startdatum.month(),
year: startdatum.year(),
klimafaktor: 1
},
{
month: startdatum.month(),
year: startdatum.year() + 1,
klimafaktor: 1
},
{
month: startdatum.month(),
year: startdatum.year() + 2,
klimafaktor: 1
}];
try {
const response = await getKlimafaktoren(ausweis.startdatum, objekt.plz)
if (response) {
klimafaktoren = response
}
} catch (e) {
// TODO: Entweder setzen wir hier mit falschen Klimafaktoren fort, oder wir geben null zurück.
// Im Moment setzen wir einfach fort, aber das ist nicht unbedingt die beste Lösung.
// return null
}
// Endenergieverbrauch
// Um den EEV auszurechnen, müssen die Verbräuche zu kWh konvertiert werden.
let brennstoff_1 = { coe: 0, energietraeger: "", einheit: "", umrechnungsfaktor: 0, primaerenergiefaktor: 0 }, brennstoff_2 = { coe: 0, energietraeger: "", einheit: "", umrechnungsfaktor: 0, primaerenergiefaktor: 0 };
@@ -114,13 +85,13 @@ export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis:
let energieVerbrauchWarmwasser_1 = 0;
let energieVerbrauchWarmwasser_2 = 0;
if (ausweis.warmwasser_enthalten && ausweis.anteil_warmwasser_1 != 0) {
if (ausweis.warmwasser_enthalten && ausweis.anteil_warmwasser_1 != 0 && ausweis.anteil_warmwasser_1 !== null) {
// Wenn Warmwasser enthalten und Anteil bekannt
energieVerbrauchWarmwasser_1 = energieVerbrauchGesamt_1 * ((ausweis.anteil_warmwasser_1 || 0) / 100);
energieVerbrauchWarmwasser_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_warmwasser_2 || 0) / 100);
} else if (ausweis.warmwasser_enthalten && ausweis.anteil_warmwasser_1 == 0){
} else if (ausweis.warmwasser_enthalten && (ausweis.anteil_warmwasser_1 == 0 || ausweis.anteil_warmwasser_1 === null)) {
if (aufnahme.gebaeudetyp == "Krankenhäuser (ohne Forschung und Lehre)" || aufnahme.gebaeudetyp == "Krankenhäuser (ohne Forschung und Lehre) & teilstationäre Versorgung" || aufnahme.gebaeudetyp == "Schwimmhallen") {
energieVerbrauchWarmwasser_1 = energieVerbrauchGesamt_1 * 0.5;
energieVerbrauchWarmwasser_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_warmwasser_2 || 0) / 100);
@@ -136,8 +107,14 @@ export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis:
energieVerbrauchWarmwasser_2 = 0;
}
let kuehlungsZuschlag_1: number = 0, kuehlungsZuschlag_2: number = 0;
if (aufnahme.kuehlung) {
let kuehlungsZuschlag_1: number = 0, kuehlungsZuschlag_2: number = 0; let kuehlungsZuschlag = 0;
if (aufnahme.kuehlung === "1" && aufnahme.kuehlung !== null && (ausweis.stromverbrauch_enthaelt_kuehlung === false || ausweis.stromverbrauch_enthaelt_kuehlung === null)) {
kuehlungsZuschlag = 6 * nutzflaeche * 3;
}
if (ausweis.kuehlung_enthalten && ausweis.kuehlung_enthalten !== null)
{
kuehlungsZuschlag_1 = energieVerbrauchGesamt_1 * ((ausweis.anteil_kuehlung_1 || 0) / 100);
kuehlungsZuschlag_2 = energieVerbrauchGesamt_2 * ((ausweis.anteil_kuehlung_2 || 0) / 100);
}
@@ -174,7 +151,7 @@ export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis:
let energieVerbrauchStrom = (ausweis.strom_1 || 0) + (ausweis.strom_2 || 0) + (ausweis.strom_3 || 0);
let leerstandsZuschlagStrom = leerstand * energieVerbrauchStrom;
let endEnergieVerbrauchStrom = (energieVerbrauchStrom + leerstandsZuschlagStrom) / (3 * nutzflaeche);
let endEnergieVerbrauchStrom = (energieVerbrauchStrom + leerstandsZuschlagStrom + (kuehlungsZuschlag || 0)) / (3 * nutzflaeche);
let primaerEnergieVerbrauchStrom = endEnergieVerbrauchStrom * 1.8;
let co2EmissionenStrom = endEnergieVerbrauchStrom * 0.560;
@@ -197,7 +174,7 @@ export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis:
let co2EmissionenKuehlungsZuschlag_1 = endEnergieVerbrauchKuehlungsZuschlag_1 * brennstoff_1.coe;
let co2EmissionenKuehlungsZuschlag_2 = endEnergieVerbrauchKuehlungsZuschlag_2 * brennstoff_2.coe;
let endEnergieVerbrauchGesamt = endEnergieVerbrauch_1 + endEnergieVerbrauch_2 + endEnergieVerbrauchLeerstandsZuschlag;
let endEnergieVerbrauchGesamt = endEnergieVerbrauch_1 + endEnergieVerbrauch_2 + endEnergieVerbrauchLeerstandsZuschlag + (kuehlungsZuschlag / (3 * nutzflaeche));
let primaerEnergieVerbrauchGesamt = primaerEnergieVerbrauch_1 + primaerEnergieVerbrauch_2 + primaerEnergieVerbrauchLeerstandsZuschlag + primaerEnergieVerbrauchStrom;
let co2EmissionenGesamt = co2Emissionen_1 + co2Emissionen_2 + co2EmissionenLeerstandsZuschlag + co2EmissionenStrom;
@@ -209,6 +186,7 @@ export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis:
brennstoff_2,
kuehlungsZuschlag_1 : Math.round(kuehlungsZuschlag_1),
kuehlungsZuschlag_2: Math.round(kuehlungsZuschlag_2),
kuehlungsZuschlag: Math.round(kuehlungsZuschlag),
durchschnittsKlimafaktor : Math.round(durchschnittsKlimafaktor * 100) / 100,
Klimafaktor_1 : klimafaktoren[0],
Klimafaktor_2 : klimafaktoren[1],

View File

@@ -0,0 +1,39 @@
import moment from "moment";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "./VerbrauchsausweisGewerbe_2016.js";
import { Aufnahme, Objekt, VerbrauchsausweisGewerbe } from "#lib/server/prisma.js";
import { getKlimafaktoren } from "#lib/Klimafaktoren.js";
export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client(
ausweis: VerbrauchsausweisGewerbe,
aufnahme: Aufnahme,
objekt: Objekt,
) {
const startdatum = moment(ausweis.startdatum);
let klimafaktoren = await getKlimafaktoren(
objekt.plz as string,
startdatum.toDate(),
startdatum.add(2, "years").toDate()
);
if (!klimafaktoren || klimafaktoren.length === 0) {
klimafaktoren = [
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year"),
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 1,
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 2,
},
];
}
return await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis, aufnahme, objekt, klimafaktoren)
}

View File

@@ -0,0 +1,39 @@
import moment from "moment";
import { getKlimafaktorenServer } from "#lib/server/klimafaktoren.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "./VerbrauchsausweisGewerbe_2016.js";
import { Aufnahme, Objekt, VerbrauchsausweisGewerbe } from "#lib/server/prisma.js";
export async function endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Server(
ausweis: VerbrauchsausweisGewerbe,
aufnahme: Aufnahme,
objekt: Objekt,
) {
const startdatum = moment(ausweis.startdatum);
let klimafaktoren = await getKlimafaktorenServer(
objekt.plz as string,
startdatum.toDate(),
startdatum.add(2, "years").toDate()
);
if (klimafaktoren.length === 0) {
klimafaktoren = [
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year"),
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 1,
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 2,
},
];
}
return await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis, aufnahme, objekt, klimafaktoren)
}

View File

@@ -1,8 +1,6 @@
import { AufnahmeClient, ObjektClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { getKlimafaktoren } from "#lib/Klimafaktoren.js";
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor.js";
import { Enums } from "#lib/client/prisma.js";
import moment from "moment";
export function energetischeNutzflaecheVerbrauchsausweisWohnen_2016(
ausweis: VerbrauchsausweisWohnenClient,
@@ -24,43 +22,13 @@ export function energetischeNutzflaecheVerbrauchsausweisWohnen_2016(
export async function endEnergieVerbrauchVerbrauchsausweis_2016(
ausweis: VerbrauchsausweisWohnenClient,
aufnahme: AufnahmeClient,
objekt: ObjektClient
objekt: ObjektClient,
klimafaktoren: {month: number, year: number, klimafaktor: number}[]
) {
if (!aufnahme || !objekt || !ausweis) {
if (!aufnahme || !objekt || !ausweis || !klimafaktoren) {
return null;
}
let startdatum = moment(ausweis.startdatum);
let klimafaktoren: Awaited<ReturnType<typeof getKlimafaktoren>> = [{
month: startdatum.month(),
year: startdatum.year(),
klimafaktor: 1
},
{
month: startdatum.month(),
year: startdatum.year() + 1,
klimafaktor: 1
},
{
month: startdatum.month(),
year: startdatum.year() + 2,
klimafaktor: 1
}];
try {
const response = await getKlimafaktoren(ausweis.startdatum, objekt.plz)
if (response) {
klimafaktoren = response
}
} catch (e) {
// TODO: Entweder setzen wir hier mit falschen Klimafaktoren fort, oder wir geben null zurück.
// Im Moment setzen wir einfach fort, aber das ist nicht unbedingt die beste Lösung.
// return null
}
// Endenergieverbrauch
// Um den EEV auszurechnen, müssen die Verbräuche zu kWh konvertiert werden.
let brennstoff_1 = getHeizwertfaktor(
@@ -92,7 +60,7 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
// Leerstand wird in Prozent angegeben, muss hier aber in eine Zahl zwischen 0 und 1 umgerechnet werden.
let leerstand = (aufnahme.leerstand || 0) / 100;
if (ausweis.warmwasser_enthalten && ausweis.warmwasser_anteil_bekannt) {
if (ausweis.warmwasser_enthalten && ausweis.warmwasser_anteil_bekannt && ausweis.anteil_warmwasser_1 !== 0) {
if (aufnahme.solarsystem_warmwasser) {
// Wenn Warmwasser enthalten und Anteil bekannt und Solarsystem
energieVerbrauchWarmwasser_1 =

View File

@@ -0,0 +1,43 @@
import {
VerbrauchsausweisWohnenClient,
AufnahmeClient,
ObjektClient,
} from "#components/Ausweis/types.js";
import { getKlimafaktoren } from "#lib/Klimafaktoren.js";
import moment from "moment";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "./VerbrauchsausweisWohnen_2016.js";
export async function endEnergieVerbrauchVerbrauchsausweis_2016_Client(
ausweis: VerbrauchsausweisWohnenClient,
aufnahme: AufnahmeClient,
objekt: ObjektClient,
) {
const startdatum = moment(ausweis.startdatum);
let klimafaktoren = await getKlimafaktoren(
objekt.plz as string,
startdatum.toDate(),
startdatum.add(2, "years").toDate()
);
if (!klimafaktoren || klimafaktoren.length === 0) {
klimafaktoren = [
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year"),
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 1,
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 2,
},
];
}
return await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt, klimafaktoren)
}

View File

@@ -0,0 +1,48 @@
import {
VerbrauchsausweisWohnenClient,
AufnahmeClient,
ObjektClient,
} from "#components/Ausweis/types.js";
import moment from "moment";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "./VerbrauchsausweisWohnen_2016.js";
import { getKlimafaktorenServer } from "#lib/server/klimafaktoren.js";
export async function endEnergieVerbrauchVerbrauchsausweis_2016_Server(
ausweis: VerbrauchsausweisWohnenClient,
aufnahme: AufnahmeClient,
objekt: ObjektClient
) {
const startdatum = moment(ausweis.startdatum);
let klimafaktoren = await getKlimafaktorenServer(
objekt.plz as string,
startdatum.toDate(),
startdatum.add(2, "years").toDate()
);
if (klimafaktoren.length === 0) {
klimafaktoren = [
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year"),
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 1,
},
{
klimafaktor: 1,
month: startdatum.get("m"),
year: startdatum.get("year") + 2,
},
];
}
return await endEnergieVerbrauchVerbrauchsausweis_2016(
ausweis,
aufnahme,
objekt,
klimafaktoren
);
}

View File

@@ -1,13 +0,0 @@
import type { VerbrauchsausweisWohnen } from "#lib/client/prisma";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "./VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import { AufnahmeClient, ObjektClient } from "#components/Ausweis/types.js";
export async function endEnergieVerbrauch(ausweis: VerbrauchsausweisWohnen, aufnahme: AufnahmeClient, objekt: ObjektClient): Promise<number> {
const result = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt);
if (!result) {
return 0;
}
return result.endEnergieVerbrauchGesamt;
}

View File

@@ -18,8 +18,6 @@ export const getKlimafaktoren = memoize(async (date: Date, plz: string) => {
});
return response;
} catch (e) {
console.log(e);
return null;
}
});

View File

@@ -112,4 +112,4 @@ export const SERVICES: Record<
};
export const BASE_URI = process.env.NODE_ENV == "production" ? "https://online-energieausweis.org" : "http://localhost:3000";
export const LEX_OFFICE_API_KEY = process.env.NODE_ENV == "production" ? "iwQLCU_ZAq6bVV7hmR8RO8MiC8Q" : "znjmkmbA3Hbx9dC7wdKp7TnOf1pcRl_tCUwEBZys7bj-QRPG"
export const LEX_OFFICE_API_KEY = process.env.NODE_ENV == "production" ? "iwQLCU_ZAq6bVV7hmR8RO8MiC8Q" : "iwQLCU_ZAq6bVV7hmR8RO8MiC8Q"

View File

@@ -3,13 +3,13 @@ import * as fs from "fs"
import { PDFDocument, StandardFonts } from "pdf-lib";
import { xml2pdf } from "./elements/xml2pdf.js";
import moment from "moment";
import { Enums, Heizungsstatus } from "#lib/server/prisma.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { Enums, Heizungsstatus, Rechnung } from "#lib/server/prisma.js";
import { copyPage } from "./utils/copyPage.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Server } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016_Server.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, benutzer: BenutzerClient, bilder: BildClient[]) {
export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, rechnung: Rechnung | null, bilder: BildClient[]) {
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("../../../public/pdf/templates/Leerseite_Datenblatt.pdf", import.meta.url), "base64");
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const page3 = copyPage(pdf.getPages()[0]);
@@ -18,7 +18,7 @@ export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: Verbrauchsa
// const template = VerbrauchsausweisWohnen2016Template as Template;
const berechnungen = await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis, aufnahme, objekt);
const berechnungen = await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Server(ausweis, aufnahme, objekt);
const height = pages[0].getHeight()
const width = pages[0].getWidth()
@@ -32,14 +32,6 @@ export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: Verbrauchsa
const marginX = 60;
const marginY = 150;
benutzer = benutzer || {
vorname: "Max",
name: "Mustermann",
adresse: "Musterstraße 123",
plz: "12345",
ort: "Beispielhausen"
};
const translateHeizungsstatus: Record<Heizungsstatus, string> = {
BEHEIZT: "beheizt",
NICHT_VORHANDEN: "nicht vorhanden",
@@ -70,9 +62,10 @@ export async function pdfDatenblattVerbrauchsausweisGewerbe(ausweis: Verbrauchsa
}
const layout = xml2pdf(`<layout height="${pages[0].getHeight()}" width="${pages[0].getWidth()}" marginTop="150" marginLeft="${marginX}" marginRight="${marginX}">
<text size="12" lineHeight="14">${benutzer.vorname} ${benutzer.name}</text>
<text size="12" lineHeight="14">${benutzer.adresse}</text>
<text size="12" lineHeight="14">${benutzer.plz} ${benutzer.ort}</text>
<text size="12" lineHeight="14">${rechnung?.versand_empfaenger || ""}</text>
<text size="12" lineHeight="14">${rechnung?.versand_zusatzzeile || ""}</text>
<text size="12" lineHeight="14">${rechnung?.versand_strasse || ""}</text>
<text size="12" lineHeight="14">${rechnung?.versand_plz || ""} ${rechnung?.versand_ort || ""}</text>
<flex direction="row" justify="space-between" marginTop="55" width="${innerWidth}">
<text size="12" font="bold">Datenblatt Energieausweis</text>
<text size="12">Ausweis ID: ${ausweis.id}</text>

View File

@@ -1,15 +1,15 @@
import { AufnahmeClient, BenutzerClient, BildClient, ObjektClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import { AufnahmeClient, BildClient, ObjektClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import * as fs from "fs"
import { PDFDocument, StandardFonts } from "pdf-lib";
import { xml2pdf } from "./elements/xml2pdf.js";
import moment from "moment";
import { Enums, Heizungsstatus } from "#lib/server/prisma.js";
import { Enums, Heizungsstatus, Rechnung } from "#lib/server/prisma.js";
import { copyPage } from "./utils/copyPage.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016_Server } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016_Server.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, benutzer: BenutzerClient, bilder: BildClient[]) {
export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, rechnung: Rechnung | null, bilder: BildClient[]) {
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("../../../public/pdf/templates/Leerseite_Datenblatt.pdf", import.meta.url), "base64");
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const page3 = copyPage(pdf.getPages()[0]);
@@ -19,7 +19,7 @@ export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: Verbrauchsau
// const template = VerbrauchsausweisWohnen2016Template as Template;
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt);
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016_Server(ausweis, aufnahme, objekt);
const height = pages[0].getHeight()
const width = pages[0].getWidth()
@@ -33,14 +33,6 @@ export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: Verbrauchsau
const marginX = 60;
const marginY = 150;
benutzer = benutzer || {
vorname: "Max",
name: "Mustermann",
adresse: "Musterstraße 123",
plz: "12345",
ort: "Beispielhausen"
};
const translateHeizungsstatus: Record<Heizungsstatus, string> = {
BEHEIZT: "beheizt",
NICHT_VORHANDEN: "nicht vorhanden",
@@ -52,9 +44,10 @@ export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: Verbrauchsau
const id = ausweis.id;
const layout = xml2pdf(`<layout height="${pages[0].getHeight()}" width="${pages[0].getWidth()}" marginTop="150" marginLeft="${marginX}" marginRight="${marginX}">
<text size="12" lineHeight="14">${benutzer.vorname} ${benutzer.name}</text>
<text size="12" lineHeight="14">${benutzer.adresse}</text>
<text size="12" lineHeight="14">${benutzer.plz} ${benutzer.ort}</text>
<text size="12" lineHeight="14">${rechnung?.versand_empfaenger || ""}</text>
<text size="12" lineHeight="14">${rechnung?.versand_zusatzzeile || ""}</text>
<text size="12" lineHeight="14">${rechnung?.versand_strasse || ""}</text>
<text size="12" lineHeight="14">${rechnung?.versand_plz || ""} ${rechnung?.versand_ort || ""}</text>
<flex direction="row" justify="space-between" marginTop="55" width="${innerWidth}">
<text size="12" font="bold">Datenblatt Energieausweis</text>
<text size="12">Ausweis ID: ${id}</text>
@@ -332,8 +325,5 @@ export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: Verbrauchsau
await layoutPage2.draw(pages[1], 0, pages[1].getHeight())
await layoutPage3.draw(pages[2], 0, pages[2].getHeight())
console.log("DONE");
return pdf.save();
}

View File

@@ -1,24 +1,23 @@
import { AufnahmeClient, BenutzerClient, BildClient, ObjektClient, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.js";
import { getEmpfehlungen } from "#lib/XML/getEmpfehlungen.js";
import { Enums } from "#lib/server/prisma.js";
import * as fs from "fs"
import moment from "moment";
import { PDFDocument, PDFFont, PDFImage, PDFPage, StandardFonts } from "pdf-lib";
import { addCheckMark } from "./utils/checkbox.js";
import { addText } from "./utils/text.js";
import { addAnsichtsausweisLabel, addDatumGEG } from "./utils/helpers.js";
import { addAnsichtsausweisLabel, addDatumGEG, addRegistriernummer } from "./utils/helpers.js";
import { getS3File } from "#lib/s3.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Server } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016_Server.js";
export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient) {
export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewerbeClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, vorschau = true) {
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("../../../public/pdf/templates/GEG24_Nichtwohngebaeude.pdf", import.meta.url), "base64");
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const pages = pdf.getPages()
// const template = VerbrauchsausweisWohnen2016Template as Template;
const berechnungen = await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis, aufnahme, objekt);
const berechnungen = await endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Server(ausweis, aufnahme, objekt);
const empfehlungen = getEmpfehlungen(ausweis, aufnahme, objekt)
@@ -30,7 +29,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
const form = pdf.getForm()
form.updateFieldAppearances(font)
pages[0].drawText(`ID: ${aufnahme.id || ""}`, {
pages[0].drawText(`ID: ${ausweis.id || ""}`, {
x: 211,
y: height - 112.5,
size: 10
@@ -103,7 +102,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
})
if (ausweis.warmwasser_enthalten) {
pages[0].drawText(`${ausweis.brennstoff_1}, ${ausweis.brennstoff_2 || ""}`, {
pages[3].drawText(`${ausweis.brennstoff_1}, ${ausweis.brennstoff_2 || ""}`, {
x: 211,
y: height - 299,
size: 10
@@ -112,30 +111,82 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
if (aufnahme.lueftung === Enums.Lueftungskonzept.Fensterlueftung) {
addCheckMark(pages[0], 213, height - 334)
pages[0].drawText("x", {
x: 214,
y: height - 342,
size: 10,
font: bold
})
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.Schachtlueftung) {
addCheckMark(pages[0], 213, height - 345)
pages[0].drawText("x", {
x: 214,
y: height - 353,
size: 10,
font: bold
})
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageMitWaermerueckgewinnung) {
addCheckMark(pages[0], 355, height - 334)
pages[0].drawText("x", {
x: 356,
y: height - 342,
size: 10,
font: bold
})
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageOhneWaermerueckgewinnung) {
addCheckMark(pages[0], 355, height - 345)
pages[0].drawText("x", {
x: 356,
y: height - 353,
size: 10,
font: bold
})
}
// Kühlung
if (aufnahme.kuehlung) {
addCheckMark(pages[0], 213, height - 362.5)
} else {
addCheckMark(pages[0], 355, height - 373.5)
if (aufnahme.kuehlung === "1" && aufnahme.kuehlung !== null) {
pages[0].drawText("x", {
x: 356,
y: height - 370.5,
size: 10,
font: bold
})
}
if (ausweis.kuehlung_enthalten === true && ausweis.kuehlung_enthalten !== null) {
pages[0].drawText("x", {
x: 356,
y: height - 381.5,
size: 10,
font: bold
})
}
if (ausweis.ausstellgrund === Enums.Ausstellgrund.Neubau) {
addCheckMark(pages[0], 213, height - 406)
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Vermietung) {
addCheckMark(pages[0], 213, height - 417)
pages[0].drawText("x", {
x: 214,
y: height - 414,
size: 10,
font: bold
})
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Vermietung || ausweis.ausstellgrund === Enums.Ausstellgrund.Verkauf) {
pages[0].drawText("x", {
x: 214,
y: height - 425,
size: 10,
font: bold
})
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Modernisierung) {
addCheckMark(pages[0], 344.5, height - 406)
pages[0].drawText("x", {
x: 345.5,
y: height - 414,
size: 10,
font: bold
})
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Sonstiges) {
addCheckMark(pages[0], 463, height - 417)
pages[0].drawText("x", {
x: 464,
y: height - 425,
size: 10,
font: bold
})
}
// Aushangpflicht
// addCheckMark(pages[0], 463, height - 406)
@@ -161,11 +212,21 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
}
}
// Checkmark Angabe energetische Qualität des Gebäudes.
addCheckMark(pages[0], 40, height - 550)
// Checkmark Verbrauchsausweis.
pages[0].drawText("x", {
x: 41,
y: height - 558,
size: 10,
font: bold
})
// Datenerhebung durch Eigentümer
addCheckMark(pages[0], 295, height - 580)
pages[0].drawText("x", {
x: 296.5,
y: height - 587.5,
size: 10,
font: bold
})
// Ausstellungsdatum
pages[0].drawText(moment().format("DD.MM.YYYY"), {
@@ -184,9 +245,9 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
})
// Stempel und Unterschrift
if (ausweis.ausgestellt) {
if (ausweis.ausgestellt || !vorschau) {
const stempel = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/stempel-unterschrift.png", import.meta.url), "base64"));
const stempelHeight = 60
const stempelHeight = 65
pages[0].drawImage(stempel, {
x: 450,
@@ -200,10 +261,10 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
// Aussteller
const aussteller = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/aussteller.png", import.meta.url), "base64"));
pages[0].drawImage(aussteller, {
x: 40,
y: height - 750,
width: 100,
height: 50
x: 260,
y: height - 755,
width: 130,
height: 65
})
@@ -213,15 +274,20 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
const addEnergieverbrauchSkalaPfeile = async (page: PDFPage) => {
const pfeilNachUnten = await pdf.embedPng(fs.readFileSync(new URL("../../../public/images/pfeil-nach-unten.png", import.meta.url), "base64"))
const pfeilNachOben = await pdf.embedPng(fs.readFileSync(new URL("../../../public/images/pfeil-nach-oben.png", import.meta.url), "base64"))
// Wir müssen den berechneten Wert zwischen 0 und 1000 als Wert zwischen 0 und 1 festlegen
const endenergieverbrauchTranslationPercentage = Math.min(1000, Math.max(0, berechnungen?.endEnergieVerbrauchGesamt || 0)) / 1000
const stromVerbrauchTranslationPercentage = Math.min(1000, Math.max(0, berechnungen?.endEnergieVerbrauchStrom || 0)) / 1000
const endenergieverbrauchTranslationPercentage = Math.min((berechnungen?.vergleichsWertWaerme * 2), Math.max(0, berechnungen?.endEnergieVerbrauchGesamt || 0)) / (berechnungen?.vergleichsWertWaerme * 2)
const stromVerbrauchTranslationPercentage = Math.min((berechnungen?.vergleichsWertStrom * 2), Math.max(0, berechnungen?.endEnergieVerbrauchStrom || 0)) / (berechnungen?.vergleichsWertStrom * 2)
const vergleichsWertWaermeTranslationPercentage = Math.min((berechnungen?.vergleichsWertWaerme * 2), Math.max(0, berechnungen?.vergleichsWertWaerme || 0)) / (berechnungen?.vergleichsWertWaerme * 2)
const vergleichsWertStromTranslationPercentage = Math.min((berechnungen?.vergleichsWertStrom * 2), Math.max(0, berechnungen?.vergleichsWertStrom || 0)) / (berechnungen?.vergleichsWertStrom * 2)
const minTranslation = 78
const maxTranslation = 512
const endenergieverbrauchTranslationX = minTranslation + (maxTranslation - minTranslation) * endenergieverbrauchTranslationPercentage;
const stromVerbrauchTranslationX = minTranslation + (maxTranslation - minTranslation) * stromVerbrauchTranslationPercentage;
const vergleichsWertWaermeTranslationX = minTranslation + (maxTranslation - minTranslation) * vergleichsWertWaermeTranslationPercentage;
const vergleichsWertStromTranslationX = minTranslation + (maxTranslation - minTranslation) * vergleichsWertStromTranslationPercentage;
const pfeilWidth = 20
const margin = 5;
@@ -233,12 +299,68 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
height: 30
})
const endEnergieVerbrauchGesamtText = `${berechnungen?.endEnergieVerbrauchGesamt.toString()}kWh/(m²a)`;
const stromVerbrauchGesamtText = `${berechnungen?.endEnergieVerbrauchStrom.toString()}kWh/(m²a)`;
page.drawImage(pfeilNachOben, {
x: vergleichsWertWaermeTranslationX,
y: height - 293,
width: pfeilWidth,
height: 30
})
page.drawText("0", {
x: 85,
y: height - 241,
size: 13,
font: bold
})
const vergleichswertWaermeText2 = `${Math.round(berechnungen?.vergleichsWertWaerme).toString()}`
page.drawText(vergleichswertWaermeText2, {
x: 295,
y: height - 241,
size: 13,
font: bold
})
const maxVergleichswertWaermeText = `> ${Math.round(berechnungen?.vergleichsWertWaerme * 2).toString()}`;
page.drawText(maxVergleichswertWaermeText, {
x: vergleichsWertWaermeTranslationX * 2 - 78,
y: height - 241,
size: 13,
font: bold
})
page.drawText("0", {
x: 85,
y: height - 385,
size: 13,
font: bold
})
const vergleichswertStromText2 = `${Math.round(berechnungen?.vergleichsWertStrom).toString()}`
page.drawText(vergleichswertStromText2, {
x: 295,
y: height - 385,
size: 13,
font: bold
})
const maxVergleichswertStromText = `> ${Math.round(berechnungen?.vergleichsWertStrom * 2).toString()}`;
page.drawText(maxVergleichswertStromText, {
x: vergleichsWertStromTranslationX * 2 - 78,
y: height - 385,
size: 13,
font: bold
})
const endEnergieVerbrauchGesamtText = `${Math.round(berechnungen?.endEnergieVerbrauchGesamt ?? 0).toString()}kWh/(m²a)`;
if (endenergieverbrauchTranslationPercentage > 0.5) {
page.drawText("Endenergieverbrauch Wärme", {
x: endenergieverbrauchTranslationX - margin - font.widthOfTextAtSize("Endenergieverbrauch", 10),
x: endenergieverbrauchTranslationX - margin - font.widthOfTextAtSize("Endenergieverbrauch Wärme", 10),
y: height - 191,
size: 10
})
@@ -263,6 +385,35 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
})
}
const vergleichswertWaermeText = `${Math.round(berechnungen?.vergleichsWertWaerme).toString()}kWh/(m²a)`
if (vergleichsWertWaermeTranslationPercentage > 0.5) {
page.drawText("Vergleichswert Wärme", {
x: vergleichsWertWaermeTranslationX - margin - font.widthOfTextAtSize("Vergleichswert Wärme", 10),
y: height - 275,
size: 10
})
page.drawText(vergleichswertWaermeText, {
x: vergleichsWertWaermeTranslationX - margin - bold.widthOfTextAtSize(vergleichswertWaermeText, 10),
y: height - 289,
size: 10,
font: bold
})
} else {
page.drawText("Vergleichswert Wärme", {
x: vergleichsWertWaermeTranslationX + pfeilWidth + margin,
y: height - 275,
size: 10
})
page.drawText(vergleichswertWaermeText, {
x: vergleichsWertWaermeTranslationX + pfeilWidth + margin,
y: height - 289,
size: 10,
font: bold
})
}
page.drawImage(pfeilNachUnten, {
x: stromVerbrauchTranslationX,
y: height - 354,
@@ -270,9 +421,18 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
height: 30
})
if (endenergieverbrauchTranslationPercentage > 0.5) {
page.drawImage(pfeilNachOben, {
x: vergleichsWertStromTranslationX,
y: height - 437,
width: pfeilWidth,
height: 30
})
const stromVerbrauchGesamtText = `${Math.round(berechnungen?.endEnergieVerbrauchStrom ?? 0).toString()}kWh/(m²a)`;
if (stromVerbrauchTranslationPercentage > 0.5) {
page.drawText("Endenergieverbrauch Strom", {
x: stromVerbrauchTranslationX - margin - font.widthOfTextAtSize("Primärenergieverbrauch", 10),
x: stromVerbrauchTranslationX - margin - font.widthOfTextAtSize("Endenergieverbrauch Strom", 10),
y: height - 335,
size: 10
})
@@ -296,40 +456,110 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
font: bold
})
}
const vergleichswertStromText = `${Math.round(berechnungen?.vergleichsWertStrom).toString()}kWh/(m²a)`
if (vergleichsWertWaermeTranslationPercentage > 0.5) {
page.drawText("Vergleichswert Strom", {
x: vergleichsWertStromTranslationX - margin - font.widthOfTextAtSize("Vergleichswert Strom", 10),
y: height - 420,
size: 10
})
page.drawText(vergleichswertStromText, {
x: vergleichsWertStromTranslationX - margin - bold.widthOfTextAtSize(vergleichswertStromText, 10),
y: height - 434,
size: 10,
font: bold
})
} else {
page.drawText("Vergleichswert Strom", {
x: vergleichsWertStromTranslationX + pfeilWidth + margin,
y: height - 420,
size: 10
})
page.drawText(vergleichswertStromText, {
x: vergleichsWertStromTranslationX + pfeilWidth + margin,
y: height - 434,
size: 10,
font: bold
})
}
}
addEnergieverbrauchSkalaPfeile(pages[2])
if (ausweis.warmwasser_enthalten) {
addCheckMark(pages[2], 41, height - 269)
pages[2].drawText("x", {
x: 42,
y: height - 301,
size: 10,
font: bold
})
}
if (ausweis.kuehlung_enthalten) {
addCheckMark(pages[2], 41, height - 281)
pages[2].drawText("x", {
x: 42,
y: height - 313,
size: 10,
font: bold
})
}
if (ausweis.stromverbrauch_enthaelt_heizung) {
addCheckMark(pages[2], 41, height - 456)
pages[2].drawText("x", {
x: 42,
y: height - 464,
size: 10,
font: bold
})
}
if (ausweis.stromverbrauch_enthaelt_warmwasser) {
addCheckMark(pages[2], 131, height - 456)
pages[2].drawText("x", {
x: 132,
y: height - 464,
size: 10,
font: bold
})
}
if (ausweis.stromverbrauch_enthaelt_lueftung) {
addCheckMark(pages[2], 218, height - 456)
pages[2].drawText("x", {
x: 219,
y: height - 464,
size: 10,
font: bold
})
}
if (ausweis.stromverbrauch_enthaelt_beleuchtung) {
addCheckMark(pages[2], 281, height - 456)
pages[2].drawText("x", {
x: 282,
y: height - 464,
size: 10,
font: bold
})
}
if (ausweis.stromverbrauch_enthaelt_kuehlung) {
addCheckMark(pages[2], 422, height - 456)
pages[2].drawText("x", {
x: 423,
y: height - 464,
size: 10,
font: bold
})
}
if (ausweis.stromverbrauch_enthaelt_sonstige) {
addCheckMark(pages[2], 492, height - 456)
pages[2].drawText("x", {
x: 493,
y: height - 464,
size: 10,
font: bold
})
}
addText(pages[2], berechnungen?.primaerEnergieVerbrauchGesamt.toString() || "", 475, height - 637, 10, font)
@@ -423,22 +653,7 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
const addVerbrauch = addVerbrauchGenerator();
if (!ausweis.warmwasser_enthalten) {
// Mit Warmwasserzuschlag
addVerbrauch(
moment(ausweis.startdatum).format("MM.YYYY"),
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
ausweis.brennstoff_1 || "",
berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
Math.round(berechnungen?.energieVerbrauchGesamt_1 || 0).toString(),
"0",
berechnungen?.endEnergieVerbrauchKuehlungsZuschlag_1,
Math.round(berechnungen?.energieVerbrauchHeizung_1 || 0).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
berechnungen?.energieVerbrauchStrom
);
} else {
// Ohne Warmwasserzuschlag
// Primäre Heizquelle
addVerbrauch(
moment(ausweis.startdatum).format("MM.YYYY"),
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
@@ -446,12 +661,12 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
Math.round(berechnungen?.energieVerbrauchGesamt_1 || 0).toString(),
Math.round(berechnungen?.energieVerbrauchWarmwasser_1 || 0).toString(),
berechnungen?.endEnergieVerbrauchKuehlungsZuschlag_1,
berechnungen?.kuehlungsZuschlag_1,
Math.round(berechnungen?.energieVerbrauchHeizung_1 || 0).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
berechnungen?.energieVerbrauchStrom
);
}
if (ausweis.zusaetzliche_heizquelle) {
addVerbrauch(
@@ -461,32 +676,13 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
berechnungen?.brennstoff_2.primaerenergiefaktor.toString(),
Math.round(berechnungen?.energieVerbrauchGesamt_2 || 0).toString(),
Math.round(berechnungen?.energieVerbrauchWarmwasser_2 || 0).toString(),
berechnungen?.endEnergieVerbrauchKuehlungsZuschlag_2,
berechnungen?.kuehlungsZuschlag_2,
Math.round(berechnungen?.energieVerbrauchHeizung_2 || 0).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
0
);
}
// TODO
if (!ausweis.warmwasser_enthalten) {
/**
* Dezentrale Warmwasserversorgung - Pauschale Erhöhung um 20kWh/m²
* @link https://www.bundesanzeiger.de/pub/publication/MRYM4nI84Sdlr0EIvvW?2
*/
addVerbrauch(
moment(ausweis.startdatum).format("MM.YYYY"),
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
"Warmwasserzuschlag",
berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
Math.round(berechnungen?.energieVerbrauchWarmwasser_1 || 0).toString(),
Math.round(berechnungen?.energieVerbrauchWarmwasser_1 || 0).toString(),
0,
"0"
);
}
if (aufnahme.leerstand && aufnahme.leerstand > 0) {
/**
* Leerstandszuschlag
@@ -498,10 +694,12 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
"Leerstandszuschlag",
berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
Math.round((berechnungen?.leerstandsZuschlagHeizung || 0) + (berechnungen?.leerstandsZuschlagWarmwasser || 0)).toString(),
Math.round((berechnungen?.leerstandsZuschlagHeizung || 0) + (berechnungen?.leerstandsZuschlagWarmwasser || 0) + (berechnungen?.leerstandsZuschlagKuehlung || 0)).toString(),
Math.round((berechnungen?.leerstandsZuschlagWarmwasser || 0)).toString(),
Math.round((berechnungen?.leerstandsZuschlagHeizung || 0)),
berechnungen?.durchschnittsKlimafaktor.toString()
Math.round((berechnungen?.leerstandsZuschlagKuehlung || 0)),
Math.round((berechnungen?.leerstandsZuschlagHeizung || 0)).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
Math.round((berechnungen?.leerstandsZuschlagStrom || 0))
);
} else {
addVerbrauch(
@@ -509,15 +707,17 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
"Leerstandszuschlag",
berechnungen?.brennstoff_1.primaerenergiefaktor.toString(),
Math.round((berechnungen?.leerstandsZuschlagHeizung || 0) + (berechnungen?.leerstandsZuschlagWarmwasser || 0)).toString(),
"0",
0,
berechnungen?.durchschnittsKlimafaktor.toString()
Math.round((berechnungen?.leerstandsZuschlagHeizung || 0) + (berechnungen?.leerstandsZuschlagWarmwasser || 0) + (berechnungen?.leerstandsZuschlagKuehlung || 0)).toString(),
Math.round((berechnungen?.leerstandsZuschlagWarmwasser || 0)).toString(),
Math.round((berechnungen?.leerstandsZuschlagKuehlung || 0)),
Math.round((berechnungen?.leerstandsZuschlagHeizung || 0)).toString(),
berechnungen?.durchschnittsKlimafaktor.toString(),
Math.round((berechnungen?.leerstandsZuschlagStrom || 0))
);
}
}
if (aufnahme.kuehlung) {
if (aufnahme.kuehlung === "1" && (ausweis.stromverbrauch_enthaelt_kuehlung === false || ausweis.stromverbrauch_enthaelt_kuehlung === null)) {
/**
* Kühlungszuschlag - Pauschale Erhöhung um 6kWh/m²
* Primärenergiefaktor Strom
@@ -527,16 +727,17 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
moment(ausweis.startdatum).format("MM.YYYY"),
moment(ausweis.startdatum).add(3, "years").format("MM.YYYY"),
"Kühlungszuschlag",
"1.8",
"",
"",
// TODO
// berechnungen?.primaerfaktorww.toString(),
Math.round(berechnungen?.kuehlungsZuschlag_1 || 0).toString(),
"0",
0,
""
"",
"",
Math.round(berechnungen?.kuehlungsZuschlag || 0)
);
}
/* -------------------------------- Seite 4 -------------------------------- */
const splitToSize = (text: string, size: number, font: PDFFont, fontSize: number) => {
@@ -612,9 +813,15 @@ export async function pdfVerbrauchsausweisGewerbe(ausweis: VerbrauchsausweisGewe
}
for (const page of pages) {
for (let i = 0; i < pages.length; i++) {
const page = pages[i];
if (vorschau) {
addAnsichtsausweisLabel(page, font)
}
addDatumGEG(page, font)
if (i !== pages.length - 1) {
addRegistriernummer(page, font, ausweis.registriernummer || "")
}
}

View File

@@ -1,25 +1,26 @@
import { AufnahmeClient, BenutzerClient, BildClient, ObjektClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import { getEmpfehlungen } from "#lib/XML/getEmpfehlungen.js";
import { Enums } from "#lib/server/prisma.js";
import * as fs from "fs"
import moment from "moment";
import { PDFDocument, PDFFont, PDFImage, PDFPage, StandardFonts } from "pdf-lib";
import { addCheckMark } from "./utils/checkbox.js";
import { addText } from "./utils/text.js";
import { addAnsichtsausweisLabel, addDatumGEG } from "./utils/helpers.js";
import { addAnsichtsausweisLabel, addDatumGEG, addRegistriernummer } from "./utils/helpers.js";
import { getS3File } from "#lib/s3.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016_Server } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016_Server.js";
/* -------------------------------- Pdf Tools ------------------------------- */
export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient) {
export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, vorschau = true) {
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("../../../public/pdf/templates/GEG24_Wohngebaeude_ohne_pfeile.pdf", import.meta.url), "base64");
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
const pages = pdf.getPages()
// const template = VerbrauchsausweisWohnen2016Template as Template;
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt);
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016_Server(ausweis, aufnahme, objekt);
const empfehlungen = getEmpfehlungen(ausweis, aufnahme, objekt)
const height = pages[0].getHeight()
@@ -27,7 +28,19 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
const font = await pdf.embedFont(StandardFonts.Helvetica)
const bold = await pdf.embedFont(StandardFonts.HelveticaBold)
pages[0].drawText(`ID: ${aufnahme.id || ""}`, {
for (let i = 0; i < pages.length; i++) {
const page = pages[i];
if (vorschau) {
addAnsichtsausweisLabel(page, font)
}
addDatumGEG(page, font)
if (i !== pages.length - 1) {
addRegistriernummer(page, font, ausweis.registriernummer || "")
}
}
pages[0].drawText(`ID: ${ausweis.id || ""}`, {
x: 211,
y: height - 112.5,
size: 10
@@ -39,9 +52,34 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
size: 10
})
const bild = bilder && bilder.find(image => image.kategorie === Enums.BilderKategorie.Gebaeude);
if (bild) {
const file = await getS3File("ibc-images", `${bild.id}.jpg`);
if (file) {
let image: PDFImage;
image = await pdf.embedJpg(file)
pages[0].drawImage(image, {
x: 460.5,
y: height - 289,
width: 111,
height: 138
})
}
}
pages[0].drawText(objekt.adresse || "", {
x: 211,
y: height - 194,
y: height - 188.5,
size: 10
})
const plzOrt = `${objekt.plz || ""} ${objekt.ort || ""}`
pages[0].drawText(plzOrt || "", {
x: 211,
y: height - 200,
size: 10
})
@@ -69,18 +107,36 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
size: 10
})
pages[0].drawText(aufnahme.nutzflaeche?.toString() || "", {
pages[0].drawText(Math.round(berechnungen?.energetischeNutzflaeche || 0).toString() || "", {
x: 211,
y: height - 285,
size: 10
})
// Nach 82 aus Wohnfläche ermittelt
if (aufnahme.nutzflaeche == 0) {
pages[0].drawText("x", {
x: 275,
y: height - 285,
size: 10,
font: bold
})
}
pages[0].drawText(`${ausweis.brennstoff_1}, ${ausweis.brennstoff_2 || ""}`, {
x: 211,
y: height - 298.5,
size: 10
})
if (ausweis.warmwasser_enthalten) {
pages[0].drawText(`${ausweis.brennstoff_1}, ${ausweis.brennstoff_2 || ""}`, {
x: 211,
y: height - 299,
size: 10
})
}
if (ausweis.warmwasser_enthalten) {
pages[0].drawText(`${ausweis.brennstoff_1}, ${ausweis.brennstoff_2 || ""}`, {
x: 211,
@@ -90,6 +146,7 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
}
const erneuerbareEnergienVerwendung = []
if (ausweis.alternative_heizung) {
@@ -114,69 +171,91 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
size: 8
})
if (ausweis.warmwasser_enthalten) {
pages[0].drawText(`${ausweis.brennstoff_1}, ${ausweis.brennstoff_2 || ""}`, {
x: 211,
y: height - 299,
size: 10
})
}
if (aufnahme.lueftung === Enums.Lueftungskonzept.Fensterlueftung) {
addCheckMark(pages[0], 213, height - 347)
pages[0].drawText("x", {
x: 214,
y: height - 355,
size: 10,
font: bold
})
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.Schachtlueftung) {
addCheckMark(pages[0], 213, height - 358)
pages[0].drawText("x", {
x: 214,
y: height - 366,
size: 10,
font: bold
})
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageMitWaermerueckgewinnung) {
addCheckMark(pages[0], 355, height - 347)
pages[0].drawText("x", {
x: 356,
y: height - 355,
size: 10,
font: bold
})
} else if (aufnahme.lueftung === Enums.Lueftungskonzept.LueftungsanlageOhneWaermerueckgewinnung) {
addCheckMark(pages[0], 355, height - 358)
pages[0].drawText("x", {
x: 356,
y: height - 366,
size: 10,
font: bold
})
}
// Kühlung
if (aufnahme.kuehlung) {
addCheckMark(pages[0], 213, height - 375.5)
} else {
addCheckMark(pages[0], 355, height - 386.5)
if (aufnahme.kuehlung === "1") {
pages[0].drawText("x", {
x: 213,
y: height - 383.5,
size: 10,
font: bold
})
}
if (ausweis.ausstellgrund === Enums.Ausstellgrund.Neubau) {
addCheckMark(pages[0], 213, height - 419)
pages[0].drawText("x", {
x: 214,
y: height - 427,
size: 10,
font: bold
})
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Vermietung || ausweis.ausstellgrund === Enums.Ausstellgrund.Verkauf) {
addCheckMark(pages[0], 213, height - 430)
pages[0].drawText("x", {
x: 214,
y: height - 438,
size: 10,
font: bold
})
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Modernisierung) {
addCheckMark(pages[0], 344.5, height - 419)
pages[0].drawText("x", {
x: 345.5,
y: height - 427,
size: 10,
font: bold
})
} else if (ausweis.ausstellgrund === Enums.Ausstellgrund.Sonstiges) {
addCheckMark(pages[0], 463, height - 419)
}
const bild = bilder && bilder.find(image => image.kategorie === Enums.BilderKategorie.Gebaeude);
if (bild) {
const file = await getS3File("ibc-images", `${bild.id}.jpg`);
if (file) {
let image: PDFImage;
image = await pdf.embedJpg(file)
pages[0].drawImage(image, {
x: 460.5,
y: height - 289,
width: 111,
height: 138
pages[0].drawText("x", {
x: 464,
y: height - 427,
size: 10,
font: bold
})
}
}
// Nach 82 aus Wohnfläche ermittelt
if (aufnahme.flaeche == 0) {
addCheckMark(pages[0], 274, height - 277)
}
// Checkmark Angabe energetische Qualität des Gebäudes.
addCheckMark(pages[0], 43, height - 560)
// Checkmark Angabe Verbrauchsausweis
pages[0].drawText("x", {
x: 44,
y: height - 568,
size: 10,
font: bold
})
// Datenerhebung durch Eigentümer
addCheckMark(pages[0], 298, height - 590)
pages[0].drawText("x", {
x: 299,
y: height - 598,
size: 10,
font: bold
})
// Ausstellungsdatum
pages[0].drawText(moment().format("DD.MM.YYYY"), {
@@ -195,9 +274,9 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
})
// Stempel und Unterschrift
if (ausweis.ausgestellt) {
if (!vorschau) {
const stempel = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/stempel-unterschrift.png", import.meta.url), "base64"));
const stempelHeight = 60
const stempelHeight = 65
pages[0].drawImage(stempel, {
x: 450,
@@ -209,11 +288,12 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
// Aussteller
const aussteller = await pdf.embedPng(fs.readFileSync(new URL("../../../public/pdf/images/aussteller.png", import.meta.url), "base64"));
pages[0].drawImage(aussteller, {
x: 40,
y: height - 770,
width: 100,
height: 50
x: 260,
y: height - 775,
width: 130,
height: 65
})
@@ -324,7 +404,7 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
}
}
addEnergieverbrauchSkalaPfeile(pages[2])
// CO2 Emissionen
pages[2].drawText(berechnungen?.co2EmissionenGesamt.toString() || "", {
@@ -334,6 +414,8 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
size: 10
})
addEnergieverbrauchSkalaPfeile(pages[2])
// Endenergieverbrauch
pages[2].drawText(berechnungen?.endEnergieVerbrauchGesamt.toString() || "", {
x: 455,
@@ -452,7 +534,7 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
);
}
if (!ausweis.warmwasser_enthalten) {
if (!ausweis.warmwasser_enthalten || ausweis.anteil_warmwasser_1 === 0) {
/**
* Dezentrale Warmwasserversorgung - Pauschale Erhöhung um 20kWh/m²
* @link https://www.bundesanzeiger.de/pub/publication/MRYM4nI84Sdlr0EIvvW?2
@@ -591,10 +673,5 @@ export async function pdfVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohne
addEmpfehlung(empfehlung.anlagenteil, empfehlung.description, true, empfehlung.amortisationszeit, empfehlung.kosten)
}
for (const page of pages) {
addAnsichtsausweisLabel(page, font)
addDatumGEG(page, font)
}
return pdf.save();
}

View File

@@ -22,3 +22,13 @@ export function addAnsichtsausweisLabel(page: PDFPage, font: PDFFont) {
opacity: 0.3,
});
}
export function addRegistriernummer(page: PDFPage, font: PDFFont, registriernummer: string) {
page.drawText(registriernummer, {
x: 435,
y: page.getHeight() - 113,
size: 10,
font,
});
}

View File

@@ -1,9 +1,10 @@
import { AufnahmeClient, BedarfsausweisWohnenClient, BenutzerClient, BildClient, getAusweisartFromId, ObjektClient, 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 { Enums, prisma } from "#lib/server/prisma.js";
import { Enums, prisma, Rechnung } 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.
@@ -31,15 +32,15 @@ export function getPrismaAusweisAdapter(id: string) {
* Gibt den richtigen Ansichtsausweis basierend auf der Ausweisart zurück.
* @param ausweis
*/
export async function getAnsichtsausweis(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, ausweisart = 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
}
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
return await pdfVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, bilder, user)
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)
return await pdfVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, bilder, user, vorschau)
}
return null
@@ -49,15 +50,15 @@ export async function getAnsichtsausweis(ausweis: VerbrauchsausweisWohnenClient
* Gibt das richtige Datenblatt basierend auf der Ausweisart zurück.
* @param ausweis
*/
export async function getDatenblatt(ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbeClient | BedarfsausweisWohnenClient, aufnahme: AufnahmeClient, objekt: ObjektClient, bilder: BildClient[], user: BenutzerClient, ausweisart = 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
}
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
return await pdfDatenblattVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, user, 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, user, bilder)
return await pdfDatenblattVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, rechnung, bilder)
}
return null

View File

@@ -1,4 +1,4 @@
import { Aufnahme, BedarfsausweisGewerbe, BedarfsausweisWohnen, Bild, GEGNachweisGewerbe, GEGNachweisWohnen, Objekt, prisma, Unterlage, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "./prisma.js";
import { Aufnahme, BedarfsausweisGewerbe, BedarfsausweisWohnen, Bild, GEGNachweisGewerbe, GEGNachweisWohnen, Objekt, prisma, Rechnung, Unterlage, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "./prisma.js";
export async function getVerbrauchsausweisWohnen(id: string): Promise<VerbrauchsausweisWohnen | null> {
return await prisma.verbrauchsausweisWohnen.findUnique({
@@ -8,6 +8,29 @@ export async function getVerbrauchsausweisWohnen(id: string): Promise<Verbrauchs
})
}
export async function getVerbrauchsausweisWohnenKomplett(id: string) {
return await prisma.verbrauchsausweisWohnen.findUnique({
where: {
id
},
include: {
aufnahme: {
include: {
bilder: true,
objekt: {
include: {
benutzer: true,
},
},
},
},
rechnung: true
},
})
}
export type VerbrauchsausweisWohnenKomplett = Awaited<ReturnType<typeof getVerbrauchsausweisWohnenKomplett>>;
export async function getVerbrauchsausweisGewerbe(id: string): Promise<VerbrauchsausweisGewerbe | null> {
return await prisma.verbrauchsausweisGewerbe.findUnique({
where: {
@@ -16,6 +39,27 @@ export async function getVerbrauchsausweisGewerbe(id: string): Promise<Verbrauch
})
}
export async function getVerbrauchsausweisGewerbeKomplett(id: string) {
return await prisma.verbrauchsausweisGewerbe.findUnique({
where: {
id
},
include: {
aufnahme: {
include: {
bilder: true,
objekt: {
include: {
benutzer: true,
},
},
},
},
rechnung: true
},
})
}
export async function getBedarfsausweisWohnen(id: string): Promise<BedarfsausweisWohnen | null> {
return await prisma.bedarfsausweisWohnen.findUnique({
where: {
@@ -24,6 +68,27 @@ export async function getBedarfsausweisWohnen(id: string): Promise<Bedarfsauswei
})
}
export async function getBedarfsausweisWohnenKomplett(id: string) {
return await prisma.bedarfsausweisWohnen.findUnique({
where: {
id
},
include: {
aufnahme: {
include: {
bilder: true,
objekt: {
include: {
benutzer: true,
},
},
},
},
rechnung: true
},
})
}
export async function getBedarfsausweisGewerbe(id: string): Promise<BedarfsausweisGewerbe | null> {
return await prisma.bedarfsausweisGewerbe.findUnique({
where: {
@@ -79,3 +144,11 @@ export async function getUnterlagen(aufnahme_id: string): Promise<Unterlage[]> {
}
})
}
export async function getRechnung(rechnung_id: string) {
return await prisma.rechnung.findUnique({
where: {
id: rechnung_id
}
})
}

348
src/lib/server/invoice.ts Normal file
View File

@@ -0,0 +1,348 @@
import { getAusweisartFromId } from "#components/Ausweis/types.js";
import moment from "moment";
import { createLexOfficeCustomer } from "./lexoffice.js";
import { Enums, prisma, Rechnung } from "./prisma.js";
import { LEX_OFFICE_API_KEY, PRICES } from "#lib/constants.js";
import { VerbrauchsausweisWohnenKomplett } from "./db.js";
export function createLineItem(name: string, preis: number, steuer: number) {
return {
type: "custom",
name: name,
description: "",
quantity: 1,
lineItemAmount: preis,
unitName: name,
unitPrice: {
currency: "EUR",
grossAmount: preis,
taxRatePercentage: steuer,
},
};
}
type LineItem = ReturnType<typeof createLineItem>;
export function addedServicesNeu(
data: any,
rechnung: Rechnung,
steuer: number
) {
if (rechnung.services.includes(Enums.Service.Qualitaetsdruck)) {
data["lineItems"].push(
createLineItem("Zusatzservice Postversand", 9, steuer)
);
}
if (rechnung.services.includes(Enums.Service.Aushang)) {
data["lineItems"].push(
createLineItem("Zusatzservice Aushang", 10, steuer)
);
}
if (rechnung.services.includes(Enums.Service.SameDay)) {
data["lineItems"].push(
createLineItem("Zusatzservice Same Day Service", 29, steuer)
);
}
if (rechnung.services.includes(Enums.Service.Telefonberatung)) {
data["lineItems"].push(
createLineItem("Zusatzservice Telefonische Beratung", 75, steuer)
);
}
return data;
}
/**
* Erstellt eine Rechnung in LexOffice und gibt die ID zurück.
* Die Preise basieren auf den in der Konstante `__PRICES__` definierten Preisen.
* @param Ausweis ausweis
* @param Rechnung $rechnung
* @return array
* @throws Error
*/
export async function createInvoice(
ausweis: VerbrauchsausweisWohnenKomplett,
rechnung: Rechnung
) {
if (!ausweis) {
throw new Error("Ausweis ist null");
}
if (!ausweis.benutzer_id) {
throw new Error("Benutzer ist nicht vorhanden");
}
const user = await prisma.benutzer.findUnique({
where: {
id: ausweis.benutzer_id,
},
});
if (!user) {
throw new Error("Nutzer existiert nicht!");
} else if (user.lex_office_id == null) {
// User has no valid lex_id
const lex_office_id = await createLexOfficeCustomer(user);
user.lex_office_id = lex_office_id;
await prisma.benutzer.update({
where: {
id: user.id,
},
data: {
lex_office_id: user.lex_office_id,
},
});
}
const ausweisart = getAusweisartFromId(ausweis.id);
let data = {
voucherDate: moment().format("YYYY-MM-DDTHH:mm:ss.SSSZ"),
taxConditions: {
taxType: "gross",
},
shippingConditions: {
shippingType: "none",
},
address: {
contactId: user.lex_office_id,
name: rechnung.empfaenger || "----",
street: rechnung.strasse,
city: rechnung.ort,
zip: rechnung.plz,
countryCode: "DE",
supplement: rechnung.zusatzzeile,
},
lineItems: [] as LineItem[],
totalPrice: {
currency: "EUR",
totalGrossAmount: rechnung.betrag,
},
title: "Rechnung",
introduction:
`Ihren Energieausweis (Ausweis ID ${ausweis.id}) stellen wir Ihnen hiermit in Rechnung`,
remark: "Vielen Dank für Ihren Einkauf.",
};
if (rechnung.status == Enums.Rechnungsstatus.paid) {
const types: Record<Enums.Bezahlmethoden, string> = {
[Enums.Bezahlmethoden.paypal]: "PayPal",
[Enums.Bezahlmethoden.creditcard]: "Kreditkarte",
[Enums.Bezahlmethoden.sofort]: "Sofortüberweisung",
[Enums.Bezahlmethoden.giropay]: "Giropay",
[Enums.Bezahlmethoden.rechnung]: "Rechnung",
};
const type = types[rechnung.bezahlmethode];
data[
"introduction"
] = `Vielen Dank für Ihren Einkauf (Ausweis ID ${ausweis.id}). Ihre Rechnung haben sie bereits mit ${type} bezahlt.`;
}
const tax_rate = 19;
if (rechnung.betrag == 15) {
// Korrektur alleinstehend
data["lineItems"].push(
createLineItem("Service Korrektur anfordern", rechnung.betrag, 19)
);
} else if (rechnung.betrag == 476) {
data["lineItems"].push(
createLineItem("GEG Berechnung Wohngebäude", rechnung.betrag, 19)
);
} else if (rechnung.betrag > 400 && rechnung.betrag != 476) {
data["lineItems"].push(
createLineItem("Bedarfsausweis Gewerbe", rechnung.betrag, 19)
);
} else if (ausweisart == Enums.Ausweisart.VerbrauchsausweisWohnen) {
if (ausweis.ausweistyp == Enums.AusweisTyp.Standard) {
data["lineItems"].push(
createLineItem(
`Verbrauchsausweis Online (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisWohnen.Standard,
19
)
);
} else if (ausweis.ausweistyp == Enums.AusweisTyp.Beratung) {
data["lineItems"].push(
createLineItem(
`Verbrauchsausweis Online (Vorprüfung negativ) (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisWohnen.Beratung,
19
)
);
} else if (ausweis.ausweistyp == Enums.AusweisTyp.Offline) {
data["lineItems"].push(
createLineItem(
`Verbrauchsausweis Offline (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisWohnen.Offline,
19
)
);
}
} else if (ausweisart == Enums.Ausweisart.BedarfsausweisWohnen) {
if (ausweis.ausweistyp == Enums.AusweisTyp.Standard) {
data["lineItems"].push(
createLineItem(
`Bedarfsausweis Online (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisWohnen.Standard,
19
)
);
} else if (ausweis.ausweistyp == Enums.AusweisTyp.Beratung) {
data["lineItems"].push(
createLineItem(
`Bedarfsausweis Online (Vorprüfung negativ) (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisWohnen.Beratung,
19
)
);
} else if (ausweis.ausweistyp == Enums.AusweisTyp.Offline) {
data["lineItems"].push(
createLineItem(
`Bedarfsausweis Offline (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisWohnen.Offline,
19
)
);
}
} else if (ausweisart == Enums.Ausweisart.VerbrauchsausweisGewerbe) {
if (ausweis.ausweistyp == Enums.AusweisTyp.Standard) {
data["lineItems"].push(
createLineItem(
`Verbrauchsausweis Nichtwohngebäude Online (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisGewerbe.Standard,
19
)
);
} else if (ausweis.ausweistyp == Enums.AusweisTyp.Beratung) {
data["lineItems"].push(
createLineItem(
`Verbrauchsausweis Nichtwohngebäude Online (Vorprüfung negativ) (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisGewerbe.Beratung,
19
)
);
} else if (ausweis.ausweistyp == Enums.AusweisTyp.Offline) {
data["lineItems"].push(
createLineItem(
`Verbrauchsausweis Nichtwohngebäude Offline (ID ${ausweis.id})`,
PRICES.VerbrauchsausweisGewerbe.Offline,
19
)
);
}
}
data = addedServicesNeu(data, rechnung, 19);
const response = await fetch(
"https://api.lexoffice.io/v1/invoices?finalize=true",
{
method: "POST",
headers: {
Accept: `application/json`,
Authorization: `Bearer ${LEX_OFFICE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
}
);
if (response.status == 400) {
throw new Error("Fehler beim Absenden der Request.");
}
const invoice = await response.json();
// Wir müssen den Ausweis nun wieder abfragen, um die erstellte Rechnungsnummer zu bekommen.
const response_id = invoice["id"];
const request = await fetch(
`https://api.lexoffice.io/v1/invoices/${response_id}`,
{
method: "GET",
headers: {
Accept: `application/json`,
Authorization: `Bearer ${LEX_OFFICE_API_KEY}`,
"Content-Type": "application/json",
},
}
);
const abfrage_response = await request.json();
return {
id: invoice["id"],
voucherNumber: abfrage_response["voucherNumber"],
};
}
export async function getLexOfficeVoucherNumber(rechnung: Rechnung) {
const request = await fetch(
`https://api.lexoffice.io/v1/invoices/${rechnung.lex_office_id}`,
{
method: "GET",
headers: {
Accept: `application/json`,
Authorization: `Bearer ${LEX_OFFICE_API_KEY}`,
"Content-Type": "application/json",
},
}
);
const response = await request.json();
return response["voucherNumber"]
}
/**
* Ládt das Reechnungs PDF von LexOffice runter.
*
* @export
* @async
* @param {Rechnung} rechnung
* @returns {ArrayBuffer}
* @throws Falls eine der requests fehlschlägt.
*/
export async function getLexOfficeRechnung(rechnung: Rechnung) {
const response = await fetch(`https://api.lexoffice.io/v1/invoices/${rechnung.lex_office_id}/document`, {
method: "GET",
headers: {
"Accept": `application/json`,
"Authorization": `Bearer ${LEX_OFFICE_API_KEY}`,
"Content-Type": `application/json`
}
})
const body = await response.json()
if(!("documentFileId" in body)){
throw new Error("documentFileId nicht in request.")
}
const file_id = body["documentFileId"];
const fileRequest = await fetch(`https://api.lexoffice.io/v1/files/${file_id}`, {
method: "GET",
headers: {
"Accept": `application/pdf`,
"Authorization": `Bearer ${LEX_OFFICE_API_KEY}`,
}
})
if (fileRequest.status !== 200) {
throw new Error("File request hat nicht funktioniert.")
}
const file = await fileRequest.arrayBuffer()
return file;
}

View File

@@ -0,0 +1,47 @@
import moment from "moment";
import { prisma } from "./prisma.js";
export async function getKlimafaktorenServer(plz: string, startdatum: Date, enddatum: Date) {
const start = moment(startdatum);
const end = moment(enddatum);
if (start.isSameOrAfter(end)) {
return []
}
const intervals = [];
let currentDate = start.clone();
while (currentDate.isSameOrBefore(end)) {
let copy = currentDate.clone();
intervals.push(copy);
currentDate.add(1, "year");
}
let klimafaktoren = await prisma.klimafaktoren.findMany({
where: {
plz,
month: intervals[0].month(),
OR: intervals.map((date) => {
return {
year: date.year(),
};
}),
},
});
if (!klimafaktoren) {
return []
}
// NOTE: Sollten wir hier lieber den Output padden und trotzdem die gefundenen zurückgeben?
if (klimafaktoren.length !== intervals.length) {
return []
}
return klimafaktoren.map((klimafaktor) => ({
month: klimafaktor.month,
year: klimafaktor.year,
klimafaktor: klimafaktor.klimafaktor,
}));
}

View File

@@ -1,10 +1,10 @@
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { LEX_OFFICE_API_KEY } from "#lib/constants.js";
import { Aufnahme, BedarfsausweisWohnen, Benutzer, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/client/prisma";
import { prisma } from "#lib/server/prisma";
import { Aufnahme, BedarfsausweisWohnen, Benutzer, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/client/prisma.js";
import { prisma } from "#lib/server/prisma.js";
import moment from "moment";
export function lexOfficeAnfrageSenden(ausweis: VerbrauchsausweisWohnen | BedarfsausweisWohnen | VerbrauchsausweisGewerbe, options: {
export async function lexOfficeAnfrageSenden(ausweis: VerbrauchsausweisWohnen | BedarfsausweisWohnen | VerbrauchsausweisGewerbe, options: {
bezeichnung: string,
positionstext: string,
preis: number,
@@ -103,149 +103,149 @@ export function lexOfficeAnfrageSenden(ausweis: VerbrauchsausweisWohnen | Bedarf
throw new Error(`Ein Fehler ist aufgetreten: ${pdfResult.message}`);
}
$pdf_id = $render_response["documentFileId"];
// $pdf_id = $render_response["documentFileId"];
db()->execute("UPDATE Angebotsanfragen SET
Adresse_Objekt = :Adresse_Objekt,
PLZ_Objekt = :PLZ_Objekt,
Ort_Objekt = :Ort_Objekt,
Dienstleistung = :Dienstleistung,
Empfaengerrechnung = :Empfaengerrechnung,
Zusatzzeilerechnung = :Zusatzzeilerechnung,
Adresse = :Adresse,
PLZ = :PLZ,
Ort = :Ort,
Anlass = :Anlass,
Baujahrheizung = :Baujahrheizung,
Baujahrgebaeude = :Baujahrgebaeude,
Baujahrklima = :Baujahrklima,
Gebaeudetyp = :Gebaeudetyp,
Nutzflaeche = :Nutzflaeche,
Sanierungsstatus = :Sanierungsstatus,
Nachricht = :Nachricht,
Datei = :Datei,
Rolle = :Rolle,
Email = :Email,
Angebotspreis = :Angebotspreis,
Rabatt = :Rabatt,
`Status` = 'Verschickt',
lex_office_id = :lex_office_id,
Textanschreiben = :Textanschreiben,
Positionstext = :Positionstext
WHERE Auftragsnummer = :Auftragsnummer", [
"Adresse_Objekt": $_POST["gebaeude_strasse"],
"PLZ_Objekt": $_POST["gebaeude_plz"],
"Ort_Objekt": $_POST["gebaeude_ort"],
"Dienstleistung": $_POST["dienstleistung"],
"Empfaengerrechnung": $_POST["rechnung_empfaenger"],
"Zusatzzeilerechnung": $_POST["rechnung_zusatzzeile"],
"Adresse": $_POST["rechnung_strasse"],
"PLZ": $_POST["rechnung_plz"],
"Ort": $_POST["rechnung_ort"],
"Anlass": $_POST["anlass"],
"Baujahrheizung": $_POST["baujahr_heizung"],
"Baujahrgebaeude": $_POST["baujahr_gebaeude"],
"Baujahrklima": $_POST["baujahr_klimaanlage"],
"Gebaeudetyp": $_POST["gebaeudetyp"],
"Nutzflaeche": $_POST["nutzflaeche"],
"Sanierungsstatus": $_POST["sanierungsstatus"],
"Nachricht": $_POST["nachricht"],
"Datei": $dateien,
"Rolle": $_POST["rolle"],
"Email": $_POST["email"],
"Angebotspreis": $_POST["Angebotspreis"],
"Rabatt": $_POST["Rabatt"],
"lex_office_id": $lex_office_id,
"Textanschreiben": $_POST["Textanschreiben"],
"Positionstext": $_POST["Positionstext"],
"Auftragsnummer": $_POST["Auftragsnummer"]
]);
// db()->execute("UPDATE Angebotsanfragen SET
// Adresse_Objekt = :Adresse_Objekt,
// PLZ_Objekt = :PLZ_Objekt,
// Ort_Objekt = :Ort_Objekt,
// Dienstleistung = :Dienstleistung,
// Empfaengerrechnung = :Empfaengerrechnung,
// Zusatzzeilerechnung = :Zusatzzeilerechnung,
// Adresse = :Adresse,
// PLZ = :PLZ,
// Ort = :Ort,
// Anlass = :Anlass,
// Baujahrheizung = :Baujahrheizung,
// Baujahrgebaeude = :Baujahrgebaeude,
// Baujahrklima = :Baujahrklima,
// Gebaeudetyp = :Gebaeudetyp,
// Nutzflaeche = :Nutzflaeche,
// Sanierungsstatus = :Sanierungsstatus,
// Nachricht = :Nachricht,
// Datei = :Datei,
// Rolle = :Rolle,
// Email = :Email,
// Angebotspreis = :Angebotspreis,
// Rabatt = :Rabatt,
// `Status` = 'Verschickt',
// lex_office_id = :lex_office_id,
// Textanschreiben = :Textanschreiben,
// Positionstext = :Positionstext
// WHERE Auftragsnummer = :Auftragsnummer", [
// "Adresse_Objekt": $_POST["gebaeude_strasse"],
// "PLZ_Objekt": $_POST["gebaeude_plz"],
// "Ort_Objekt": $_POST["gebaeude_ort"],
// "Dienstleistung": $_POST["dienstleistung"],
// "Empfaengerrechnung": $_POST["rechnung_empfaenger"],
// "Zusatzzeilerechnung": $_POST["rechnung_zusatzzeile"],
// "Adresse": $_POST["rechnung_strasse"],
// "PLZ": $_POST["rechnung_plz"],
// "Ort": $_POST["rechnung_ort"],
// "Anlass": $_POST["anlass"],
// "Baujahrheizung": $_POST["baujahr_heizung"],
// "Baujahrgebaeude": $_POST["baujahr_gebaeude"],
// "Baujahrklima": $_POST["baujahr_klimaanlage"],
// "Gebaeudetyp": $_POST["gebaeudetyp"],
// "Nutzflaeche": $_POST["nutzflaeche"],
// "Sanierungsstatus": $_POST["sanierungsstatus"],
// "Nachricht": $_POST["nachricht"],
// "Datei": $dateien,
// "Rolle": $_POST["rolle"],
// "Email": $_POST["email"],
// "Angebotspreis": $_POST["Angebotspreis"],
// "Rabatt": $_POST["Rabatt"],
// "lex_office_id": $lex_office_id,
// "Textanschreiben": $_POST["Textanschreiben"],
// "Positionstext": $_POST["Positionstext"],
// "Auftragsnummer": $_POST["Auftragsnummer"]
// ]);
// Die Auftragsnummer abfragen
// // Die Auftragsnummer abfragen
$curl_nummer = curl_init();
// $curl_nummer = curl_init();
curl_setopt_array($curl_nummer, [
CURLOPT_URL: "https://api.lexoffice.io/v1/quotations/$lex_office_id",
CURLOPT_RETURNTRANSFER: true,
CURLOPT_ENCODING: "",
CURLOPT_MAXREDIRS: 10,
CURLOPT_TIMEOUT: 30,
CURLOPT_HTTP_VERSION: CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST: "GET",
CURLOPT_HTTPHEADER: [
"Accept: application/json",
"Authorization: Bearer " . LEX_OFFICE_API_KEY
]
]);
// curl_setopt_array($curl_nummer, [
// CURLOPT_URL: "https://api.lexoffice.io/v1/quotations/$lex_office_id",
// CURLOPT_RETURNTRANSFER: true,
// CURLOPT_ENCODING: "",
// CURLOPT_MAXREDIRS: 10,
// CURLOPT_TIMEOUT: 30,
// CURLOPT_HTTP_VERSION: CURL_HTTP_VERSION_1_1,
// CURLOPT_CUSTOMREQUEST: "GET",
// CURLOPT_HTTPHEADER: [
// "Accept: application/json",
// "Authorization: Bearer " . LEX_OFFICE_API_KEY
// ]
// ]);
$nummer_response = curl_exec($curl_nummer);
$nummer_response = json_decode($nummer_response, true);
$err = curl_error($curl_nummer);
// $nummer_response = curl_exec($curl_nummer);
// $nummer_response = json_decode($nummer_response, true);
// $err = curl_error($curl_nummer);
curl_close($curl_nummer);
// curl_close($curl_nummer);
// Und die Mail verschicken
// // Und die Mail verschicken
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
// $mail = new PHPMailer\PHPMailer\PHPMailer(true);
$mail->IsSMTP();
$mail->Host = "smtp.ionos.de";
$mail->SMTPAuth = true;
$mail->Username = 'info@online-energieausweis.org';
$mail->Password = 'Katendeich5a2024!';
// $mail->IsSMTP();
// $mail->Host = "smtp.ionos.de";
// $mail->SMTPAuth = true;
// $mail->Username = 'info@online-energieausweis.org';
// $mail->Password = 'Katendeich5a2024!';
$mail->CharSet = 'UTF-8';
$mail->Encoding = 'base64';
$mail->setFrom("info@online-energieausweis.org", "IB Cornelsen",0);
$mail->addAddress($_POST["email"], $_POST["vorname"] . " " . $_POST["name"]);
$mail->addCC("jens.cornelsen@ib-cornelsen.de", "Jens Cornelsen");
$mail->isHTML(true);
$mail->Subject = "{$nummer_response["voucherNumber"]} - {$_POST["Angebotsbezeichnung"]}";
// $mail->CharSet = 'UTF-8';
// $mail->Encoding = 'base64';
// $mail->setFrom("info@online-energieausweis.org", "IB Cornelsen",0);
// $mail->addAddress($_POST["email"], $_POST["vorname"] . " " . $_POST["name"]);
// $mail->addCC("jens.cornelsen@ib-cornelsen.de", "Jens Cornelsen");
// $mail->isHTML(true);
// $mail->Subject = "{$nummer_response["voucherNumber"]} - {$_POST["Angebotsbezeichnung"]}";
// carriage return type (RFC)
$eol = "<br>";
$anrede = "Sehr geehrte" . ($_POST["anrede"] == "Herr" ? "r " : " ") . $_POST["anrede"];
// // carriage return type (RFC)
// $eol = "<br>";
// $anrede = "Sehr geehrte" . ($_POST["anrede"] == "Herr" ? "r " : " ") . $_POST["anrede"];
$message = "$anrede {$_POST["name"]},{$eol}{$eol}";
$message .= "vielen Dank für Ihre Anfrage. Im Anhang finden Sie das ausgearbeitete Angebot als PDF-Dokument.{$eol}{$eol}";
$message .= "Mit freundlichen Grüßen,$eol";
$message .= "Jens Cornelsen$eol";
$message .= "--{$eol}IB Cornelsen{$eol}Katendeich 5A{$eol}21035 Hamburg{$eol}{$eol}www.ib-cornelsen.de{$eol}{$eol}Fon 040 209339858{$eol}Fax 040 209339859";
$mail->Body = $message;
// $message = "$anrede {$_POST["name"]},{$eol}{$eol}";
// $message .= "vielen Dank für Ihre Anfrage. Im Anhang finden Sie das ausgearbeitete Angebot als PDF-Dokument.{$eol}{$eol}";
// $message .= "Mit freundlichen Grüßen,$eol";
// $message .= "Jens Cornelsen$eol";
// $message .= "--{$eol}IB Cornelsen{$eol}Katendeich 5A{$eol}21035 Hamburg{$eol}{$eol}www.ib-cornelsen.de{$eol}{$eol}Fon 040 209339858{$eol}Fax 040 209339859";
// $mail->Body = $message;
$curl_pdf = curl_init();
// $curl_pdf = curl_init();
curl_setopt_array($curl_pdf, [
CURLOPT_URL: "https://api.lexoffice.io/v1/files/$pdf_id",
CURLOPT_RETURNTRANSFER: true,
CURLOPT_ENCODING: "",
CURLOPT_MAXREDIRS: 10,
CURLOPT_TIMEOUT: 30,
CURLOPT_HTTP_VERSION: CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST: "GET",
CURLOPT_HTTPHEADER: [
"Accept: application/pdf",
"Authorization: Bearer " . LEX_OFFICE_API_KEY
]
]);
// curl_setopt_array($curl_pdf, [
// CURLOPT_URL: "https://api.lexoffice.io/v1/files/$pdf_id",
// CURLOPT_RETURNTRANSFER: true,
// CURLOPT_ENCODING: "",
// CURLOPT_MAXREDIRS: 10,
// CURLOPT_TIMEOUT: 30,
// CURLOPT_HTTP_VERSION: CURL_HTTP_VERSION_1_1,
// CURLOPT_CUSTOMREQUEST: "GET",
// CURLOPT_HTTPHEADER: [
// "Accept: application/pdf",
// "Authorization: Bearer " . LEX_OFFICE_API_KEY
// ]
// ]);
$response = curl_exec($curl_pdf);
$err = curl_error($curl_pdf);
// $response = curl_exec($curl_pdf);
// $err = curl_error($curl_pdf);
$HOME = dirname($ROOT);
// $HOME = dirname($ROOT);
curl_close($curl_pdf);
$fp = fopen("$HOME/{$PERSISTENT_FOLDER}/angebote/$pdf_id.pdf", "w+");
fwrite($fp, $response);
fclose($fp);
// curl_close($curl_pdf);
// $fp = fopen("$HOME/{$PERSISTENT_FOLDER}/angebote/$pdf_id.pdf", "w+");
// fwrite($fp, $response);
// fclose($fp);
$mail->addAttachment("$HOME/{$PERSISTENT_FOLDER}/angebote/$pdf_id.pdf", "Angebot.pdf");
// $mail->addAttachment("$HOME/{$PERSISTENT_FOLDER}/angebote/$pdf_id.pdf", "Angebot.pdf");
$mail->send();
// $mail->send();
echo "Alles wurde abgesendet! Du kannst die Webseite nun verlassen.";
// echo "Alles wurde abgesendet! Du kannst die Webseite nun verlassen.";
}
export async function createLexOfficeCustomer(user: Benutzer) {

View File

@@ -1,255 +0,0 @@
import {
VerbrauchsausweisWohnenSchema,
AufnahmeSchema,
ObjektSchema,
BildSchema,
RechnungSchema,
EventSchema,
BenutzerSchema,
GebaeudePlaeneSchema,
AnteilshaberSchema,
BedarfsausweisWohnenSchema,
VerbrauchsausweisGewerbeSchema
} from "#lib/client/prisma";
import { z } from "zod";
export const RechnungValidator = RechnungSchema.omit({
aufnahme_id: true,
id: true,
benutzer_id: true
})
export const GebaeudePlaeneValidator = GebaeudePlaeneSchema.omit({
id: true,
objekt_id: true
})
export const AnteilshaberValidator = AnteilshaberSchema.omit({
benutzer_id: true,
id: true,
objekt_id: true
})
export const BildValidator = BildSchema.omit({
id: true,
objekt_id: true
})
export const AufnahmeValidator = AufnahmeSchema.omit({
id: true,
benutzer_id: true,
objekt_id: true,
}).merge(
z.object({
verbrauchsausweis_wohnen: VerbrauchsausweisWohnenSchema.omit({
id: true,
benutzer_id: true,
aufnahme_id: true,
}).nullable(),
bedarfsausweis_wohnen: VerbrauchsausweisWohnenSchema.omit({
id: true,
benutzer_id: true,
aufnahme_id: true,
}).nullable(),
verbrauchsausweis_gewerbe: VerbrauchsausweisWohnenSchema.omit({
id: true,
benutzer_id: true,
aufnahme_id: true,
}).nullable(),
rechnungen: z.array(
RechnungValidator
),
events: z.array(
EventSchema.omit({
benutzer_id: true,
id: true,
}).merge(
z.object({
benutzer: BenutzerSchema.pick({ uid: true }),
})
)
),
})
);
export const ObjektValidator = ObjektSchema.omit({
benutzer_id: true,
id: true
}).merge(z.object({
aufnahme: z.array(
AufnahmeValidator
).nullable().optional(),
bilder: z.array(
BildValidator
).nullable().optional(),
gebaeude_plaene: z.array(
GebaeudePlaeneValidator
).nullable().optional(),
Anteilshaber: z.array(
AnteilshaberValidator
).nullable().optional()
}))
/**
* Runtime überprüfung für den Verbrauchsausweis Wohnen
* Dieser Typ beinhaltet alle Daten bis auf die IDs aller Verlinkungen.
*/
export const VerbrauchsausweisWohnenValidator =
VerbrauchsausweisWohnenSchema.merge(
z.object({
benutzer: BenutzerSchema.omit({
id: true,
passwort: true
}),
aufnahme: AufnahmeSchema.omit({
benutzer_id: true,
objekt_id: true,
id: true,
}).merge(
z.object({
objekt: ObjektSchema.omit({
benutzer_id: true,
id: true,
}).merge(
z.object({
bilder: z.array(
BildSchema.omit({
id: true,
objekt_id: true,
})
)
})
),
rechnungen: RechnungSchema.omit({
aufnahme_id: true,
benutzer_id: true,
id: true,
}).array(),
events: z.array(
EventSchema.omit({
aufnahme_id: true,
id: true,
benutzer_id: true
}).merge(z.object({
benutzer: BenutzerSchema.pick({
uid: true
})
}))
)
})
)
})
).omit({
benutzer_id: true,
id: true,
aufnahme_id: true,
});
export const VerbrauchsausweisWohnenBerechnungValidator2024 = z.object({
endEnergieVerbrauchGesamt: z.number(),
primaerEnergieVerbrauchGesamt: z.number(),
energieEffizienzKlasse: z.string(),
co2EmissionenGesamt: z.number()
})
/**
* Runtime überprüfung für den Verbrauchsausweis Wohnen
* Dieser Typ beinhaltet alle Daten bis auf die IDs aller Verlinkungen.
*/
export const BedarfsausweisWohnenValidator =
BedarfsausweisWohnenSchema.merge(
z.object({
aufnahme: AufnahmeSchema.omit({
benutzer_id: true,
objekt_id: true,
id: true,
}).merge(
z.object({
objekt: ObjektSchema.omit({
benutzer_id: true,
id: true,
}).merge(
z.object({
bilder: z.array(
BildSchema.omit({
id: true,
objekt_id: true,
})
)
})
),
rechnungen: RechnungSchema.omit({
aufnahme_id: true,
benutzer_id: true,
id: true,
}).array(),
events: z.array(
EventSchema.omit({
aufnahme_id: true,
id: true,
benutzer_id: true
}).merge(z.object({
benutzer: BenutzerSchema.pick({
uid: true
})
}))
)
})
)
})
).omit({
benutzer_id: true,
id: true,
aufnahme_id: true,
});
/**
* Runtime überprüfung für den Verbrauchsausweis Wohnen
* Dieser Typ beinhaltet alle Daten bis auf die IDs aller Verlinkungen.
*/
export const VerbrauchsausweisGewerbeValidator =
VerbrauchsausweisGewerbeSchema.merge(
z.object({
aufnahme: AufnahmeSchema.omit({
benutzer_id: true,
objekt_id: true,
id: true,
}).merge(
z.object({
objekt: ObjektSchema.omit({
benutzer_id: true,
id: true,
}).merge(
z.object({
bilder: z.array(
BildSchema.omit({
id: true,
objekt_id: true,
})
)
})
),
rechnungen: RechnungSchema.omit({
aufnahme_id: true,
benutzer_id: true,
id: true,
}).array(),
events: z.array(
EventSchema.omit({
aufnahme_id: true,
id: true,
benutzer_id: true
}).merge(z.object({
benutzer: BenutzerSchema.pick({
uid: true
})
}))
)
})
)
})
).omit({
benutzer_id: true,
id: true,
aufnahme_id: true,
});

View File

@@ -36,6 +36,8 @@
export let unterlagen: Unterlage[] = [];
export let id: string | null;
export let partner_code: string;
export let loadFromDatabase: boolean = false;
// Wir holen die daten aus dem LocalStorage falls
@@ -143,6 +145,7 @@
bind:unterlagen
bind:blockLocalStorageSync
{ausweisart}
{partner_code}
showWeiter={false}
{form}
{skala}
@@ -166,19 +169,19 @@
<!-- C - Berechnungshilfe und Tabelle der Hüllflächen, U-Werte und Gebäudevolumen -->
<!-- <Bereich
<Bereich
bereich="C"
title="Berechnungshilfe und Tabelle der Hüllflächen, U-Werte und Gebäudevolumen"
><GebaeudeVolumen bind:ausweis /></Bereich
> -->
>
<!-- D - Eingabe der Fensterflächen und Konstruktion von Dach, Wänden und Boden -->
<!-- <Bereich
<Bereich
bereich="D"
title="Eingabe der Fensterflächen und Konstruktion von Dach, Wänden und Boden"
><Fensterflaechen bind:ausweis /></Bereich
> -->
>
<!-- E - Angabe zu Lüftung und Kühlung -->
@@ -187,7 +190,7 @@
>
<!-- F Angaben zur Heizungsanlage -->
<!-- <Bereich bereich="F" title="Angaben zur Heizunganlage"
<!-- <Bereich bereich="D" title="Angaben zur Heizunganlage"
><SanierungszustandHeizungsanlage
bind:images={bilder}
bind:objekt
@@ -195,7 +198,7 @@
bind:ausweis
{ausweisart}
/></Bereich
> -->
>
<Bereich bereich="D" title="Gebäudepläne & Unterlagen">
<div
@@ -277,6 +280,7 @@
bind:unterlagen
bind:blockLocalStorageSync
{ausweisart}
{partner_code}
showWeiter={true}
{form}
{skala}

View File

@@ -1,18 +1,24 @@
<script lang="ts">
import { AufnahmeKomplettClient, BenutzerClient } from "#components/Ausweis/types.js";
import AusweisPruefenNotification from "#components/AusweisPruefenNotification.svelte";
import Carousel from "#components/Carousel.svelte";
import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte";
import DashboardNachweis from "#components/Dashboard/DashboardNachweis.svelte";
import NotificationProvider from "#components/NotificationProvider/NotificationProvider.svelte";
import { Objekt } from "#lib/client/prisma.js";
import NotificationWrapper from "#components/Notifications/NotificationWrapper.svelte";
import { Aufnahme, BedarfsausweisWohnen, Bild, Objekt, Rechnung, Unterlage, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/client/prisma.js";
import mime from "mime"
import { ChevronLeft, ChevronRight, FileText } from "radix-svelte-icons";
import { CaretRight, ChevronLeft, ChevronRight, FileText } from "radix-svelte-icons";
import CaretLeft from "radix-svelte-icons/src/lib/icons/CaretLeft.svelte";
export let user: BenutzerClient;
export let aufnahme: AufnahmeKomplettClient;
export let objekt: Objekt;
export let ausweis: (VerbrauchsausweisWohnen | VerbrauchsausweisGewerbe | BedarfsausweisWohnen) & {
rechnung: Rechnung,
aufnahme: Aufnahme & {
bilder: Bild[],
unterlagen: Unterlage[],
objekt: Objekt
}
};
export let benutzer: BenutzerClient;
export let page: number;
export let totalPageCount: number;
let dropdownOpen = false;
@@ -22,31 +28,35 @@
}
</script>
<h1>{objekt.adresse}, {objekt.plz} {objekt.ort}</h1>
<hr>
<div class="relative mb-6 hidden">
<div class="justify-between items-center flex flex-row">
<div class="text-2xl rounded-lg gap-2 bg-grey-200 text-center">
ID: {ausweis.id}
</div>
<div class="text-2xl">{ausweis.aufnahme.objekt.adresse}, {ausweis.aufnahme.objekt.plz} {ausweis.aufnahme.objekt.ort}</div>
<div class="relative">
<button class="button flex flex-row rounded-lg gap-2 bg-secondary text-white text-center" on:click={toggleDropdown}>
Ausweis erstellen +
</button>
{#if dropdownOpen}
<div class="absolut mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5" on:click|stopPropagation on:keydown|stopPropagation on:keyup|stopPropagation>
<div class="py-1" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
<a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?aufnahme={aufnahme.id}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis Wohnen Erstellen</a>
<a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe?aufnahme={aufnahme.id}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis Gewerbe Erstellen</a>
<a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude?aufnahme={aufnahme.id}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Bedarfsausweis Erstellen</a>
<div class="absolute top-15 left-0 mt-2 w-50 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-[9999]" on:click|stopPropagation on:keydown|stopPropagation on:keyup|stopPropagation>
<div class="py-1 w-full" role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
<a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude?aufnahme={ausweis.aufnahme.id}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis<br>Wohnen Erstellen</a>
<a href="/energieausweis-erstellen/verbrauchsausweis-gewerbe?aufnahme={ausweis.aufnahme.id}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Verbrauchsausweis<br>Gewerbe Erstellen</a>
<a href="/energieausweis-erstellen/bedarfsausweis-wohngebaeude?aufnahme={ausweis.aufnahme.id}" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 w-full text-left" role="menuitem">Bedarfsausweis<br>Wohnen Erstellen</a>
</div>
</div>
{/if}
</div>
</div>
<hr>
<div class="my-4 grid grid-cols-1 md:grid-cols-1 lg:grid-cols-1 gap-2">
<div class="relative bg-gray-100 rounded-md flex justify-center items-center">
{#if aufnahme.bilder.length > 0}
<Carousel perPage={3}>
{#each aufnahme.bilder as bild, i (i)}
{#if ausweis.aufnahme.bilder.length > 0}
<Carousel perPage={4}>
{#each ausweis.aufnahme.bilder as bild, i (i)}
<img src="/bilder/{bild.id}.jpg" alt={bild.kategorie} class="max-h-[15vh] h-full w-full object-contain">
{/each}
<span slot="left-control" class="p-2.5 bg-opacity-50 bg-white block rounded-full"><ChevronLeft size={24}></ChevronLeft></span>
@@ -54,10 +64,10 @@
</Carousel>
{/if}
</div>
{#if aufnahme.unterlagen.length > 0}
{#if ausweis.aufnahme.unterlagen.length > 0}
<h3 class="font-semibold">Unterlagen</h3>
<div class="grid grid-flow-col gap-4">
{#each aufnahme.unterlagen as unterlage}
{#each ausweis.aufnahme.unterlagen as unterlage}
<a href="/unterlagen/{unterlage.id}.{mime.getExtension(unterlage.mime)}" target="_blank" class="text-black flex flex-row items-center gap-2 bg-base-200 p-2 rounded-lg"><FileText size={32}></FileText> {unterlage.name}</a>
{/each}
</div>
@@ -65,7 +75,34 @@
</div>
<div class="my-4 grid grid-cols-[1fr] md:grid-cols-[7fr,16fr,5fr] lg:grid-cols-[7fr,16fr,5fr] min-h-[600px]">
<DashboardAusweis {benutzer} {ausweis} aufnahme={ausweis.aufnahme} objekt={ausweis.aufnahme.objekt} rechnung={ausweis.rechnung}></DashboardAusweis>
</div>
<div class="flex items-center justify-between">
{#if page > 1}
<a class="p-2 rounded-lg hover:bg-gray-200 cursor-pointer" href="/dashboard/objekte/{page - 1}">
<CaretLeft size={30}></CaretLeft>
</a>
{:else}
<div></div>
{/if}
<div class="text-lg">Ausweis {page} / {totalPageCount}</div>
{#if totalPageCount > page}
<a class="p-2 rounded-lg hover:bg-gray-200 cursor-pointer" href="/dashboard/objekte/{page + 1}">
<CaretRight size={30}></CaretRight>
</a>
{:else}
<div></div>
{/if}
</div>
<div class="fixed bottom-8 right-8 flex flex-col gap-4">
<NotificationWrapper></NotificationWrapper>
</div>
<style>
/* TODO: Das kann auch als Tailwind Klasse gemacht werden */
.button {
padding: 0.5rem 1rem;
font-size: 1rem;
@@ -73,28 +110,3 @@
cursor: pointer;
}
</style>
<div class="my-4 grid grid-cols-1 md:grid-cols-1 lg:grid-cols-1">
{#each aufnahme.verbrauchsausweise_wohnen as ausweis}
<DashboardAusweis {benutzer} {ausweis} {aufnahme} {objekt} rechnung={ausweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.bedarfsausweise_wohnen as ausweis}
<DashboardAusweis {benutzer} {ausweis} {aufnahme} {objekt} rechnung={ausweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.verbrauchsausweise_gewerbe as ausweis}
<DashboardAusweis {benutzer} {ausweis} {aufnahme} {objekt} rechnung={ausweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.geg_nachweise_wohnen as nachweis}
<DashboardAusweis {benutzer} ausweis={nachweis} {aufnahme} {objekt} rechnung={nachweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.geg_nachweise_gewerbe as nachweis}
<DashboardAusweis {benutzer} ausweis={nachweis} {aufnahme} {objekt} rechnung={nachweis.rechnung}></DashboardAusweis>
{/each}
{#each aufnahme.bedarfsausweise_gewerbe as nachweis}
<DashboardAusweis {benutzer} ausweis={nachweis} {aufnahme} {objekt} rechnung={nachweis.rechnung}></DashboardAusweis>
{/each}
</div>
<div class="fixed bottom-8 right-8 flex flex-col gap-4">
<NotificationProvider component={AusweisPruefenNotification}></NotificationProvider>
</div>

View File

@@ -1,83 +0,0 @@
<script lang="ts">
import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import DashboardAusweis from "#components/Dashboard/DashboardAusweis.svelte";
import DashboardAusweisSkeleton from "#components/Dashboard/DashboardAusweisSkeleton.svelte";
import { verbrauchsausweisWohnenCalculateFormProgress } from "#lib/VerbrauchsausweisWohnen/calculateFormProgress";
import { onMount } from "svelte";
export let user: BenutzerClient;
let ausweise: VerbrauchsausweisWohnenClient[] | null = null;
let ausweisUeberpruefung: ReturnType<typeof verbrauchsausweisWohnenCalculateFormProgress>[] = [];
let errorCount = 0;
onMount(async () => {
ausweise = await client.v1.verbrauchsausweisWohnen.getMany.query({
limit: 10
});
console.log(ausweise);
if (!ausweise) return;
ausweisUeberpruefung = ausweise.map(ausweis => verbrauchsausweisWohnenCalculateFormProgress(ausweis));
errorCount = ausweisUeberpruefung.reduce((acc, { errors }) => acc + errors.length, 0);
})
</script>
{#if errorCount > 0}
<h1 class="text-4xl font-medium my-8">Wichtiges</h1>
<div class="flex flex-row gap-4 overflow-x-auto">
{#each ausweisUeberpruefung as { errors }}
{#if errors.length > 0}
<div class="card w-96 card-bordered bg-base-200 border-base-300">
<div class="card-body">
<div class="badge font-semibold" class:badge-warning={errors[0].severity == "warning"} class:badge-error={errors[0].severity == "error"}>{errors[0].severity == "error" ? "Achtung!" : "Wichtig!"}</div>
<h2 class="card-title">{errors[0].title}</h2>
<p>{errors[0].description}</p>
{#if errors[0].resolvehref}
<div class="card-actions justify-end">
<a class="btn btn-primary" href={errors[0].resolvehref}>Beheben</a>
</div>
{/if}
</div>
</div>
{/if}
{/each}
</div>
{/if}
<h1 class="text-4xl font-medium my-8">Ihre Ausweise</h1>
<div class="grid xl:grid-cols-2 grid-cols-1 gap-4">
{#if ausweise === null}
<DashboardAusweisSkeleton></DashboardAusweisSkeleton>
{:else}
{#if ausweise.length == 0}
<div class="">
<h1 class="text-2xl">Es konnten keine Ausweise gefunden werden.</h1>
<p>Erstellen sie einen Verbrauchsausweis für ihr Wohngebäude <a href="/energieausweis-erstellen/verbrauchsausweis-wohngebaeude">hier</a></p>
</div>
{:else}
{#each ausweise as ausweis, i}
<DashboardAusweis progress={ausweisUeberpruefung[i]?.progress || 0} {ausweis}></DashboardAusweis>
{/each}
{/if}
{/if}
</div>
<div class="flex items-center justify-center mt-12">
<div class="join">
<button class="join-item btn btn-ghost shadow-none">1</button>
<button class="join-item btn btn-ghost shadow-none">2</button>
<button class="join-item btn btn-ghost shadow-none">3</button>
<button class="join-item btn btn-ghost shadow-none">4</button>
</div>
</div>

View File

@@ -71,36 +71,6 @@
<Person size={22} />
Profil
</Tab>
<Tab>
<Reader width={22} height={22} />
Ausweise
</Tab>
<Tab>
<EnvelopeClosed width={22} height={22} />
Kontakt
</Tab>
<li>
<details>
<summary class="tab w-full outline-0 hover:outline-0">
<Cube width={22} height={22} />
Services</summary
>
<ul>
<li>
<Tab>
<EnvelopeClosed width={22} height={22} />
Kontakt
</Tab>
</li>
<li>
<Tab>
<EnvelopeClosed width={22} height={22} />
Kontakt
</Tab>
</li>
</ul>
</details>
</li>
</TabList>
<div
class="border border-base-300 w-full h-full rounded-lg bg-base-200 p-8"

View File

@@ -2,7 +2,6 @@
import "../../style/formular.css";
import {
BenutzerClient,
ObjektClient,
ObjektKomplettClient,
} from "#components/Ausweis/types.js";
import DashboardObjekt from "#components/Dashboard/DashboardObjekt.svelte";
@@ -14,10 +13,8 @@
import Cookies from "js-cookie";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import Pagination from "#components/Pagination.svelte";
import AusweisePruefenFilter from "#components/Dashboard/AusweisePruefenFilter.svelte";
import { filterAusweise } from "#lib/filters.js";
import { z, ZodTypeAny } from "zod";
import { Enums } from "#lib/client/prisma.js";
import { Enums, Objekt } from "#lib/client/prisma.js";
export let user: BenutzerClient;
export let objekte: ObjektKomplettClient[];
@@ -26,7 +23,7 @@
let objektOverlayHidden = true;
let objekt: Omit<ObjektClient, "uid"> = {
let objekt: Objekt = {
adresse: "",
erstellungsdatum: new Date(),
latitude: 0,
@@ -91,8 +88,6 @@
objekte = objekte
}
let filters: { name: keyof z.infer<typeof filterAusweise>, type: ZodTypeAny, value: any }[] = []
export let id: string = "";
</script>
@@ -100,15 +95,10 @@
<hr />
{#if user.rolle === Enums.BenutzerRolle.ADMIN}
<!-- <div class="flex flex-col mb-4">
<AusweisePruefenFilter bind:filters={filters}></AusweisePruefenFilter>
</div> -->
<form action="" class="flex flex-row gap-2 my-2">
<input type="text" bind:value={id} name="id" placeholder="ID">
<button class="button text-sm">Suchen</button>
</form>
{/if}
<!-- <div class="relative mb-6">
<button class="button" on:click={() => {

View File

@@ -27,7 +27,7 @@
<span>{user.vorname} {user.name}</span>
<span class="text-xs">{user.email}</span>
</div>
<a href="/dashboard/admin/impersonate?uid={user.uid}" class="button text-sm">Einloggen</a>
<a href="/dashboard/admin/impersonate?id={user.id}" class="button text-sm">Einloggen</a>
</div>
{/each}
</div>

View File

@@ -30,8 +30,8 @@
import InputLabel from "#components/labels/InputLabel.svelte";
import PlzSuche from "#components/PlzSuche.svelte";
import { getMaximumDevitationInPercent } from "#client/lib/helpers.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016 } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016.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";
export let user: Partial<BenutzerClient>;
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbe | BedarfsausweisWohnen;
@@ -211,7 +211,7 @@
versand_plz: versand_plz,
versand_ort: versand_ort,
telefon: telefon,
nachweis_id: result.nachweis_id,
nachweis_id: result.nachweis_id
},
{
headers: {
@@ -291,7 +291,7 @@
let result: Awaited<ReturnType<typeof ausweisSpeichern>> | Awaited<ReturnType<typeof nachweisSpeichern>> | null = null;
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen || ausweisart === Enums.Ausweisart.GEGNachweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe) {
result = await nachweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
result = await nachweisSpeichern(ausweis as unknown as GEGNachweisWohnen, objekt, aufnahme, bilder, unterlagen, ausweisart)
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
}
@@ -394,33 +394,6 @@
}
}
/**
* TODO
* Ausschlusskriterien: Neubau, Modernisierung
Baujahr vor 1978, unsaniert und bis 4 Wohneinheiten /
Heizung jünger als 3 Jahre / Verbrauchsjahre unvollständig / Verbrauchsjahre nicht aktuell genug /
Klimafaktoren unvollständig /
Leerstand größer 30% /
Fehlende oder unvollständige Bilder (pro Abschnitt mindestens ein Bild) /
Fehlende Angaben zum Sanierungsstand (Bei F mindestens 2 Haken), (Bei G mindestens 1 Haken)
*/
let bestellenNichtMoeglich = false;
if (
((ausweis.ausstellgrund === "Neubau" ||
ausweis.ausstellgrund === "Modernisierung") &&
aufnahme.baujahr_gebaeude[0] < 1978 &&
aufnahme.saniert === false &&
aufnahme.einheiten &&
aufnahme.einheiten > 4) ||
new Date().getFullYear() - aufnahme.baujahr_heizung[0] < 3 ||
!ausweis.verbrauch_1 ||
!ausweis.verbrauch_2 ||
!ausweis.verbrauch_3 ||
(aufnahme.leerstand && aufnahme.leerstand > 30)
) {
bestellenNichtMoeglich = true;
}
const gegAnfrage =
ausweisart === Enums.Ausweisart.GEGNachweisWohnen ||
ausweisart === Enums.Ausweisart.BedarfsausweisGewerbe ||
@@ -924,7 +897,7 @@ grid-cols-3 sm:grid-cols-5 justify-around justify-items-center items-center"
<h3>Bitte untenstehende Punkte bestätigen. Bitte gehen Sie gegebenenfalls zurück zum Formular und überprüfen bzw. korrigieren Ihre Eingaben.</h3>
{#if ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe}
{@const request = ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen ? endEnergieVerbrauchVerbrauchsausweis_2016(ausweis, aufnahme, objekt) : endEnergieVerbrauchVerbrauchsausweisGewerbe_2016(ausweis, aufnahme, objekt)}
{@const request = ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen ? endEnergieVerbrauchVerbrauchsausweis_2016_Client(ausweis, aufnahme, objekt) : endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client(ausweis, aufnahme, objekt)}
{#await request}
@@ -1041,7 +1014,8 @@ grid-cols-3 sm:grid-cols-5 justify-around justify-items-center items-center"
{#if ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen}
<!-- Verbrauchsausweis Wohnen [altes System: $ausweis->anteil_warmwasser_1 < 6 OR $ausweis->anteil_warmwasser_1 > 40] -->
{#if (ausweis.anteil_warmwasser_1 < 6) || (ausweis.anteil_warmwasser_1 > 40)}
{#if (ausweis.anteil_warmwasser_1 !== null)}
{#if ((ausweis.anteil_warmwasser_1 < 6) && (ausweis.anteil_warmwasser_1 != 0)) || (ausweis.anteil_warmwasser_1 > 40)}
<div class="pruefpunkt">
<input type="checkbox" name="pruefpunkt_anteil_warmwasser" bind:checked={ausweis.pruefpunkt_anteil_warmwasser} required/>
<div class="text-left">
@@ -1050,6 +1024,7 @@ grid-cols-3 sm:grid-cols-5 justify-around justify-items-center items-center"
</div>
{/if}
{/if}
{/if}
{#if ausweisart === Enums.Ausweisart.BedarfsausweisWohnen}
<!-- Zusätzlich beim Bedarfsausweis [altes System: $ausweis->wohnflaeche < $ausweis->energetische_nutzfläche] -->
{#if ausweis.flaeche < ausweis.nutzflaeche}

View File

@@ -49,6 +49,7 @@
export let bilder: BildClient[];
export let id: string | null;
export let partner_code: string;
export let loadFromDatabase: boolean = false;
const ausweisart = Enums.Ausweisart.VerbrauchsausweisGewerbe
@@ -128,6 +129,7 @@
ausweisart={Enums.Ausweisart.VerbrauchsausweisGewerbe}
showWeiter={false}
{form}
{partner_code}
{skala}
>
</ButtonWeiterHilfe>
@@ -244,6 +246,7 @@
ausweisart={Enums.Ausweisart.VerbrauchsausweisGewerbe}
showWeiter={true}
{form}
{partner_code}
{skala}
>
</ButtonWeiterHilfe>

View File

@@ -230,7 +230,3 @@
</li>
</ul>
</div>

View File

@@ -160,6 +160,7 @@ let skala: HTMLDivElement;
bind:aufnahme
ausweisart={Enums.Ausweisart.VerbrauchsausweisWohnen}
showWeiter={false}
{partner_code}
{form}
{skala}
>

View File

@@ -1,84 +1,91 @@
---
import AusweisLayout from "#layouts/AusweisLayoutDaten_partner.astro";
import AusweisLayout from "#layouts/AusweisLayoutDaten.astro";
import BedarfsausweisWohnenModule from "#modules/BedarfsausweisWohnen/BedarfsausweisWohnenModule.svelte";
import { AufnahmeClient, ObjektClient, BildClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { createCaller } from "src/astro-typesafe-api-caller";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import { Enums } from "#lib/server/prisma";
import { Aufnahme, BedarfsausweisWohnen, Bild, Enums, Objekt } from "#lib/server/prisma";
import { getAufnahme, getObjekt, getBilder, getBedarfsausweisWohnen } from "#lib/server/db";
import { getCurrentUser } from "#lib/server/user";
const id = Astro.url.searchParams.get("uid") || "";
const id = Astro.url.searchParams.get("id");
const aufnahme_id = Astro.url.searchParams.get("aufnahme")
const ausweistyp = Astro.url.searchParams.get("ausweistyp") || Enums.AusweisTyp.Standard;
let ausweis: VerbrauchsausweisWohnenClient = {} as VerbrauchsausweisWohnenClient;
let aufnahme: AufnahmeClient = {} as AufnahmeClient;
let objekt: ObjektClient = {} as ObjektClient;
let bilder: BildClient[] = []
let ausweistyp = Astro.url.searchParams.get("ausweistyp") as Enums.AusweisTyp || Enums.AusweisTyp.Standard;
const partner_code = Astro.params.partner as string;
const valid = validateAccessTokenServer(Astro);
let ausweis: BedarfsausweisWohnen = {} as BedarfsausweisWohnen;
let aufnahme: Aufnahme = {} as Aufnahme;
let objekt: Objekt = {} as Objekt;
let bilder: Bild[] = []
const caller = createCaller(Astro);
const user = await getCurrentUser(Astro)
if (id) {
if (!valid) {
if (!user) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
try {
ausweis = await caller["bedarfsausweis-wohnen"]._id.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
id
}
});
ausweis = await getBedarfsausweisWohnen(id) as BedarfsausweisWohnen
ausweistyp = ausweis.ausweistyp;
aufnahme = await caller.aufnahme._id.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
id: ausweis.aufnahme_id
}
})
objekt = await caller.objekt._id.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
id: ausweis.objekt_id
}
})
bilder = await caller.aufnahme._id.bilder.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
id: ausweis.aufnahme_id
}
})
if (!ausweis) {
if (!ausweis || (ausweis.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
// Der Ausweis scheint nicht zu existieren.
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
// Wir leiten auf die generische Ausweisseite ohne ID weiter.
return Astro.redirect(
"/energieausweis-erstellen/bedarfsausweis-wohngebaeude"
);
}
} catch(e) {
aufnahme = await getAufnahme(ausweis.aufnahme_id) as Aufnahme
if (!aufnahme) {
// Die Aufnahme existiert nicht, das sollte eigentlich nicht passieren aber so können wir nicht fortfahren.
return Astro.redirect(
"/energieausweis-erstellen/bedarfsausweis-wohngebaeude"
);
}
objekt = await getObjekt(aufnahme.objekt_id) as Objekt
if (!objekt) {
// Das Objekt existiert nicht, das sollte eigentlich nicht passieren aber so können wir nicht fortfahren.
return Astro.redirect(
"/energieausweis-erstellen/bedarfsausweis-wohngebaeude"
);
}
bilder = await getBilder(aufnahme.id);
} else if (aufnahme_id) {
if (!user) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
aufnahme = await getAufnahme(ausweis.aufnahme_id) as Aufnahme
if (!aufnahme) {
// Die Aufnahme existiert wohl nicht.
return Astro.redirect(
"/energieausweis-erstellen/bedarfsausweis-wohngebaeude"
);
}
objekt = await getObjekt(aufnahme.objekt_id) as Objekt
if (!objekt) {
// Das Objekt existiert nicht.
return Astro.redirect(
"/energieausweis-erstellen/bedarfsausweis-wohngebaeude"
);
}
}
console.log(ausweistyp);
---
<AusweisLayout title="Bedarfsausweis erstellen | IBCornelsen" tabHover3="glow">
<BedarfsausweisWohnenModule client:only {ausweis} {objekt} {aufnahme} {bilder} {ausweistyp} {id}></BedarfsausweisWohnenModule>
<AusweisLayout title="Bedarfsausweis erstellen | IBCornelsen">
<BedarfsausweisWohnenModule client:only {ausweis} {objekt} {aufnahme} {bilder} {ausweistyp} {id} {user} loadFromDatabase={id !== null} {partner_code}></BedarfsausweisWohnenModule>
</AusweisLayout>

View File

@@ -1,79 +1,80 @@
---
import AusweisLayout from "#layouts/AusweisLayoutDaten_partner.astro";
import { AufnahmeClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types";
import { createCaller } from "src/astro-typesafe-api-caller";
import { inferOutput } from "astro-typesafe-api/client";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import AusweisLayout from "#layouts/AusweisLayoutDaten.astro";
import { AufnahmeClient, ObjektClient, BildClient, VerbrauchsausweisGewerbeClient } from "#components/Ausweis/types";
import VerbrauchsausweisGewerbeModule from "#modules/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbeModule.svelte";
import { Enums } from "#lib/server/prisma";
import { Aufnahme, Enums, Objekt, VerbrauchsausweisGewerbe } from "#lib/server/prisma";
import { getAufnahme, getObjekt, getBilder, getVerbrauchsausweisGewerbe } from "#lib/server/db";
import { getCurrentUser } from "#lib/server/user";
const uid = Astro.url.searchParams.get("uid");
const ausweistyp = Astro.url.searchParams.get("ausweistyp") || Enums.AusweisTyp.Standard;
const id = Astro.url.searchParams.get("id");
const aufnahme_id = Astro.url.searchParams.get("aufnahme")
let ausweistyp = Astro.url.searchParams.get("ausweistyp") as Enums.AusweisTyp || Enums.AusweisTyp.Standard;
const partner_code = Astro.params.partner as string;
let ausweis: VerbrauchsausweisGewerbeClient = {} as VerbrauchsausweisGewerbeClient;
let aufnahme: AufnahmeClient = {} as AufnahmeClient;
let objekt: ObjektClient = {} as ObjektClient;
let bilder: UploadedGebaeudeBild[] = []
let bilder: BildClient[] = []
const valid = validateAccessTokenServer(Astro);
const user = await getCurrentUser(Astro)
const caller = createCaller(Astro);
if (uid) {
if (!valid) {
if (id) {
if (!user) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
try {
let { uid_aufnahme, uid_objekt, uid_benutzer, ...result } = await caller["verbrauchsausweis-gewerbe"]._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid
}
});
ausweis = await getVerbrauchsausweisGewerbe(id) as VerbrauchsausweisGewerbe
ausweistyp = ausweis.ausweistyp;
ausweis = result
aufnahme = await caller.aufnahme._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: uid_aufnahme
}
})
objekt = await caller.objekt._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: uid_objekt
}
})
bilder = await caller.aufnahme._uid.bilder.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: uid_aufnahme
}
})
if (!ausweis) {
if (!ausweis || (ausweis.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
// Der Ausweis scheint nicht zu existieren.
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
// Wir leiten auf die generische Ausweisseite ohne ID weiter.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-gewerbe"
);
}
} catch(e) {
aufnahme = await getAufnahme(ausweis.aufnahme_id) as Aufnahme
if (!aufnahme) {
// Die Aufnahme existiert nicht, das sollte eigentlich nicht passieren aber so können wir nicht fortfahren.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-gewerbe"
);
}
objekt = await getObjekt(aufnahme.objekt_id) as Objekt
if (!objekt) {
// Das Objekt existiert nicht, das sollte eigentlich nicht passieren aber so können wir nicht fortfahren.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-gewerbe"
);
}
bilder = await getBilder(aufnahme.id);
} else if (aufnahme_id) {
if (!user) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
aufnahme = await getAufnahme(ausweis.aufnahme_id) as Aufnahme
if (!aufnahme) {
// Die Aufnahme existiert wohl nicht.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-gewerbe"
);
}
objekt = await getObjekt(aufnahme.objekt_id) as Objekt
if (!objekt) {
// Das Objekt existiert nicht.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-gewerbe"
);
@@ -81,6 +82,6 @@ if (uid) {
}
---
<AusweisLayout title="Verbrauchsausweis Gewerbe erstellen | IBCornelsen" tabHover2="glow">
<VerbrauchsausweisGewerbeModule client:only {ausweis} {objekt} {aufnahme} {bilder} {ausweistyp}/>
<AusweisLayout title="Verbrauchsausweis Gewerbe erstellen | IBCornelsen">
<VerbrauchsausweisGewerbeModule client:only {ausweis} {objekt} {aufnahme} {bilder} {ausweistyp} {user} {id} {partner_code} loadFromDatabase={id !== null}/>
</AusweisLayout>

View File

@@ -1,77 +1,79 @@
---
import AusweisLayout from "#layouts/AusweisLayoutDaten_partner.astro";
import VerbrauchsausweisWohnenModule from "#modules/VerbrauchsausweisWohnen/VerbrauchsausweisWohnenModule.svelte";
import { AufnahmeClient, ObjektClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { createCaller } from "src/astro-typesafe-api-caller";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants";
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
import { Enums } from "#lib/server/prisma";
import { Aufnahme, Bild, Enums, Objekt, VerbrauchsausweisWohnen } from "#lib/server/prisma";
import { getVerbrauchsausweisWohnen, getAufnahme, getObjekt, getBilder } from "#lib/server/db";
import { getCurrentUser } from "#lib/server/user";
const uid = Astro.url.searchParams.get("uid");
const ausweistyp = Astro.url.searchParams.get("ausweistyp") || Enums.AusweisTyp.Standard;
const id = Astro.url.searchParams.get("id");
const aufnahme_id = Astro.url.searchParams.get("aufnahme")
let ausweistyp = Astro.url.searchParams.get("ausweistyp") as Enums.AusweisTyp || Enums.AusweisTyp.Standard;
const partner_code = Astro.params.partner as string;
let ausweis: VerbrauchsausweisWohnen = {} as VerbrauchsausweisWohnen;
let aufnahme: Aufnahme = {} as Aufnahme;
let objekt: Objekt = {} as Objekt;
let bilder: Bild[] = []
let ausweis: VerbrauchsausweisWohnenClient = {} as VerbrauchsausweisWohnenClient;
let aufnahme: AufnahmeClient = {} as AufnahmeClient;
let objekt: ObjektClient = {} as ObjektClient;
let bilder: UploadedGebaeudeBild[] = []
const user = await getCurrentUser(Astro)
const valid = validateAccessTokenServer(Astro);
const caller = createCaller(Astro);
if (uid) {
if (!valid) {
if (id) {
if (!user) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
try {
ausweis = await caller["verbrauchsausweis-wohnen"]._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid
}
});
ausweis = await getVerbrauchsausweisWohnen(id) as VerbrauchsausweisWohnen
ausweistyp = ausweis.ausweistyp;
aufnahme = await caller.aufnahme._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: ausweis.uid_aufnahme
}
})
objekt = await caller.objekt._uid.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: ausweis.uid_objekt
}
})
bilder = await caller.aufnahme._uid.bilder.GET.fetch(null, {
headers: {
authorization: `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
},
params: {
uid: ausweis.uid_aufnahme
}
})
if (!ausweis) {
if (!ausweis || (ausweis.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
// Der Ausweis scheint nicht zu existieren.
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
// Wir leiten auf die generische Ausweisseite ohne ID weiter.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude"
);
}
} catch(e) {
aufnahme = await getAufnahme(ausweis.aufnahme_id) as Aufnahme
if (!aufnahme) {
// Die Aufnahme existiert nicht, das sollte eigentlich nicht passieren aber so können wir nicht fortfahren.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude"
);
}
objekt = await getObjekt(aufnahme.objekt_id) as Objekt
if (!objekt) {
// Das Objekt existiert nicht, das sollte eigentlich nicht passieren aber so können wir nicht fortfahren.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude"
);
}
bilder = await getBilder(aufnahme.id);
} else if (aufnahme_id) {
if (!user) {
return Astro.redirect(
`/auth/login?redirect=${Astro.url.toString()}`
);
}
aufnahme = await getAufnahme(ausweis.aufnahme_id) as Aufnahme
if (!aufnahme) {
// Die Aufnahme existiert wohl nicht.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude"
);
}
objekt = await getObjekt(aufnahme.objekt_id) as Objekt
if (!objekt) {
// Das Objekt existiert nicht.
return Astro.redirect(
"/energieausweis-erstellen/verbrauchsausweis-wohngebaeude"
);
@@ -81,5 +83,5 @@ if (uid) {
---
<AusweisLayout title="Verbrauchsausweis erstellen" tabHover1="glow">
<VerbrauchsausweisWohnenModule client:only {ausweis} {objekt} {aufnahme} {bilder} {ausweistyp} />
<VerbrauchsausweisWohnenModule client:only {ausweis} {objekt} {aufnahme} {bilder} {id} {ausweistyp} {user} {partner_code} loadFromDatabase={id !== null} />
</AusweisLayout>

View File

@@ -8,9 +8,11 @@ import {
Enums,
Objekt,
prisma,
Rechnung,
VerbrauchsausweisGewerbe,
VerbrauchsausweisWohnen,
} from "#lib/server/prisma.js";
import { join } from "path"
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "astro:content";
import { transport } from "#lib/mail.js";
@@ -18,14 +20,24 @@ import { BASE_URI } from "#lib/constants.js";
import { getAnsichtsausweis, getDatenblatt } from "#lib/server/ausweis.js";
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { s3Client } from "#lib/s3.js";
import { createInvoice, getLexOfficeRechnung, getLexOfficeVoucherNumber } from "#lib/server/invoice.js";
import { tryCatch } from "#lib/tryCatch.js";
import SFTPClient from 'ssh2-sftp-client';
import {
getBedarfsausweisWohnenKomplett,
getVerbrauchsausweisGewerbeKomplett,
getVerbrauchsausweisWohnenKomplett,
} from "#lib/server/db.js";
import { PDFDocument } from "pdf-lib";
export const GET = defineApiRoute({
input: z.object({
id_ausweis: z.string(),
post: z.boolean().describe("Ob der Ausweis auch per Post ausgestellt werden soll.").optional().default(false)
}),
output: z.void(),
middleware: adminMiddleware,
async fetch({ id_ausweis }, context, user) {
async fetch({ id_ausweis, post }, context) {
const ausweisart = getAusweisartFromId(id_ausweis);
let ausweis:
@@ -37,66 +49,19 @@ export const GET = defineApiRoute({
aufnahme: Aufnahme & {
bilder: Bild[];
objekt: Objekt & {
benutzer: Benutzer;
};
benutzer: Benutzer | null;
};
},
rechnung: Rechnung
})
| null = null;
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
id: id_ausweis,
},
include: {
aufnahme: {
include: {
bilder: true,
objekt: {
include: {
benutzer: true,
},
},
},
},
},
});
ausweis = await getVerbrauchsausweisWohnenKomplett(id_ausweis);
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
ausweis = await prisma.verbrauchsausweisGewerbe.findUnique({
where: {
id: id_ausweis,
},
include: {
aufnahme: {
include: {
bilder: true,
objekt: {
include: {
benutzer: true,
},
},
},
},
},
});
ausweis = await getVerbrauchsausweisGewerbeKomplett(id_ausweis);
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
ausweis = await prisma.bedarfsausweisWohnen.findUnique({
where: {
id: id_ausweis,
},
include: {
aufnahme: {
include: {
bilder: true,
objekt: {
include: {
benutzer: true,
},
},
},
},
},
});
ausweis = await getBedarfsausweisWohnenKomplett(id_ausweis);
}
if (!ausweis) {
@@ -108,13 +73,18 @@ export const GET = defineApiRoute({
const rechnung = await prisma.rechnung.findFirst({
where: {
verbrauchsausweis_wohnen: {
id: id_ausweis,
},
OR: [
{ bedarfsausweis_wohnen: { id: id_ausweis } },
{ verbrauchsausweis_wohnen: { id: id_ausweis } },
{ verbrauchsausweis_gewerbe: { id: id_ausweis } }
]
},
orderBy: {
erstellt_am: "desc",
},
include: {
benutzer: true
}
});
if (!rechnung) {
@@ -125,72 +95,164 @@ export const GET = defineApiRoute({
});
}
// TODO
// SECTION: Rechnung erstellen (LexOffice)
// Wir wollen die Rechnung an lex office versenden, und uns die ID von da holen.
// Falls die Rechnung bereits existiert ist das nicht nötig.
// if (!$rechnung->lex_office_id) {
// [$lex_office_id, $renr] = createInvoice($ausweis, $rechnung);
// sleep(1); // TODO: Nach der Umstellung von LexOffice auf etwas anderes MUSS das hier unbedingt entfernt werden!
let voucherNumber: string = "";
if (!rechnung.lex_office_id) {
const [result, error] = await tryCatch(
createInvoice(ausweis, rechnung)
);
// if (!$lex_office_id || !$renr) {
// die("Bei der Erstellung der Rechnung ist etwas schiefgelaufen - Möglicherweise ist etwas mit LexOffice?");
// }
if (error) {
throw new APIError({
code: "BAD_REQUEST",
message:
"Die Rechnung konnte bei LexOffice nicht angelegt werden..",
cause: error
});
}
// $rechnung->lex_office_id = $lex_office_id;
// $rechnung->rechnungsnummer = $renr;
// $rechnung->save();
// }
const { id, voucherNumber: lexOfficeVoucherNumber } = result;
// TODO
// if ($ausweis->erledigt != 2) {$ausweis->erstellungsdatum = date("Y-m-d H:i:s");}
// $ausweis->erledigt = 2;
// $ausweis->save();
voucherNumber = lexOfficeVoucherNumber;
await prisma.rechnung.update({
where: {
id: rechnung.id,
},
data: {
lex_office_id: id,
},
});
} else {
voucherNumber = await getLexOfficeVoucherNumber(rechnung)
}
const pdfAusweis = await getAnsichtsausweis(
ausweis,
ausweis.aufnahme,
ausweis.aufnahme.objekt,
ausweis.aufnahme.bilder,
ausweis.aufnahme.objekt.benutzer
ausweis.aufnahme.objekt.benutzer,
false
);
const pdfDatenblatt = await getDatenblatt(
ausweis,
ausweis.aufnahme,
ausweis.aufnahme.objekt,
ausweis.aufnahme.bilder,
ausweis.aufnahme.objekt.benutzer
ausweis.aufnahme.objekt.benutzer,
ausweis.rechnung
);
if (pdfAusweis) {
const command = new PutObjectCommand({
// TODO: Das ist immer noch scheiße, LexOffice ist doof
// Hier müssen wir warten, damit wir sichergehen können, dass die Rechnung bei LexOffice existiert.
setTimeout(async () => {
const [pdfRechnung, pdfRechnungError] = await tryCatch(getLexOfficeRechnung(rechnung));
if (pdfRechnungError) {
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Rechnungs PDF konnte nicht generiert werden."
})
}
if (!pdfAusweis) {
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Ausweis PDF konnte nicht generiert werden."
})
}
if (!pdfDatenblatt) {
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Datenblatt PDF konnte nicht generiert werden."
})
}
const ausweisCommand = new PutObjectCommand({
Bucket: "ibc-pdfs",
Key: `ID_${ausweis.id}_Energieausweis.pdf`,
Body: pdfAusweis,
ACL: "private",
});
const response = await s3Client.send(command);
}
await s3Client.send(ausweisCommand);
if (pdfDatenblatt) {
const command = new PutObjectCommand({
const datenblattCommand = new PutObjectCommand({
Bucket: "ibc-pdfs",
Key: `ID_${ausweis.id}_Energieausweis.pdf`,
Key: `ID_${ausweis.id}_Datenblatt.pdf`,
Body: pdfDatenblatt,
ACL: "private",
});
const response = await s3Client.send(command);
await s3Client.send(datenblattCommand);
const rechnungsCommand = new PutObjectCommand({
Bucket: "ibc-pdfs",
Key: `ID_${ausweis.id}_Rechnung.pdf`,
Body: pdfDatenblatt,
ACL: "private",
});
await s3Client.send(rechnungsCommand);
// Falls Postversand angefragt wurde müssen wir die Dateien auf den Postserver hochladen
if (post) {
const dateiNameDruck = `1011000000000-AW_ID_${ausweis.id}.pdf`;
const outputPdf = await PDFDocument.create();
async function appendPdf(buffer: Uint8Array<ArrayBufferLike>) {
const doc = await PDFDocument.load(buffer);
const copiedPages = await outputPdf.copyPages(doc, doc.getPageIndices());
for (const page of copiedPages) {
outputPdf.addPage(page);
}
}
let text: string;
await appendPdf(pdfDatenblatt);
await appendPdf(pdfAusweis);
const pdfBytes = await outputPdf.save();
const pdfCommand = new PutObjectCommand({
Bucket: "ibc-pdfs",
Key: dateiNameDruck,
Body: pdfBytes,
ACL: "private",
});
await s3Client.send(pdfCommand);
const sftp = new SFTPClient();
try {
await sftp.connect({
host: 'api.ppost.de',
username: 'jens.cornelsen@ib-cornelsen.de',
password: 'ANTQesWYjd',
});
const cwd = await sftp.cwd();
await sftp.put(Buffer.from(pdfBytes), join(cwd, "upload/api", dateiNameDruck));
} catch (err) {
console.error('SFTP Upload failed:', err);
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Login zum Postversand Server war nicht erfolgreich."
});
} finally {
sftp.end();
}
}
let html: string;
if (rechnung.status === Enums.Rechnungsstatus.paid) {
text = `
<p>Sehr geehrte*r ${user.vorname} ${user.name},</p>
html = `
<p>Sehr geehrte*r ${rechnung.empfaenger},</p>
<p>im Anhang finden Sie Ihren geprüften Energieusweis inkl. Rechnung als PDF-Datei. Den Rechnungsbetrag haben Sie bereits bezahlt. Vielen Dank.</p>
<p>im Anhang finden Sie Ihren geprüften Energieusweis inkl. Rechnung als PDF-Datei. ${post ? "Zusätzlich haben wir Ihren Ausweis per Post verschickt" : ""} Den Rechnungsbetrag haben Sie bereits bezahlt. Vielen Dank.</p>
<p>
Mit freundlichen Grüßen,
@@ -214,10 +276,10 @@ fon 040 · 209339850
fax 040 · 209339859
</p>`;
} else {
text = `
<p>Sehr geehrte*r ${user.vorname} ${user.name},</p>
html = `
<p>Sehr geehrte*r ${rechnung.empfaenger},</p>
<p>im Anhang finden Sie Ihren geprüften Energieusweis inkl. Rechnung als PDF-Datei. Nachfolgend finden Sie unsere Bankverbindung. Bitte geben Sie als Verwendungszweck die Rechnungsnummer an (siehe unten). Vielen Dank.</p>
<p>im Anhang finden Sie Ihren geprüften Energieusweis inkl. Rechnung als PDF-Datei. ${post ? "Zusätzlich haben wir Ihren Ausweis per Post verschickt" : ""} Nachfolgend finden Sie unsere Bankverbindung. Bitte geben Sie als Verwendungszweck die Rechnungsnummer an (siehe unten). Vielen Dank.</p>
<br>
<table>
@@ -226,22 +288,10 @@ fax 040 · 209339859
<tr><td>IBAN</td><td>:<td>\t DE81 2004 0000 0348 6008 00</td>
<tr><td>BIC</td><td>:</td><td>\t COBADEFFXXX</td>
<tr><td>Betrag</td><td>:</td><td>\t <b>${rechnung.betrag}€</b></td>
<tr><td>Verwendungszweck</td><td>:</td><td>\t <b>${rechnung.id}</b></td>
<tr><td>Verwendungszweck</td><td>:</td><td>\t <b>${voucherNumber}</b></td>
</table>
<br>
<p>
Alternativ können Sie auch direkt online zahlen indem Sie auf den entsprechenden Link klicken:
</p>
<br>
<table>
<tr><td>Per Einzuglastschrift zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.id}&p=SEPA'>jetzt per ELV bezahlen</a></td></tr>
<tr><td>Per Sofortüberweisung zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.id}&p=Sofort'>jetzt per Sofortüberweisung bezahlen</a></td></tr>
<tr><td>Über PayPal zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.id}&p=PayPal'>jetzt per Paypal bezahlen</a></td></tr>
<tr><td>Per Giropay zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.id}&p=Giropay'>jetzt per Giropay bezahlen</a></td></tr>
<tr><td>Per Visa oder MasterCard zahlen</td> <td>:</td> <td><a href='${BASE_URI}/energieausweis-erstellen/kaufabschluss-fortsetzen?uid=${ausweis.id}&p=Kreditkarte'>jetzt per Kreditkarte bezahlen</a></td></tr>
</table>
<br>
<p>
@@ -269,9 +319,59 @@ fax 040 · 209339859
await transport.sendMail({
from: `"IBCornelsen" <info@online-energieausweis.org>`,
to: user.email,
to: rechnung.email || rechnung.benutzer.email,
bcc: "info@online-energieausweis.org",
subject: `Ihr Originalausweis vom Ingenieurbüro Cornelsen (ID: ${ausweis.id})`,
text,
html,
attachments: [{
filename: `ID_${ausweis.id}_Energieausweis.pdf`,
encoding: "binary",
content: Buffer.from(pdfAusweis),
contentType: "application/pdf",
contentDisposition: "attachment",
}, {
filename: `ID_${ausweis.id}_Datenblatt.pdf`,
encoding: "binary",
content: Buffer.from(pdfDatenblatt),
contentType: "application/pdf",
contentDisposition: "attachment",
}, {
filename: `ID_${ausweis.id}_Rechnung.pdf`,
encoding: "binary",
content: Buffer.from(pdfRechnung),
contentType: "application/pdf",
contentDisposition: "attachment",
}]
});
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
await prisma.verbrauchsausweisWohnen.update({
where: {
id: ausweis.id,
},
data: {
ausgestellt: true,
},
});
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
await prisma.verbrauchsausweisGewerbe.update({
where: {
id: ausweis.id,
},
data: {
ausgestellt: true,
},
});
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
await prisma.bedarfsausweisWohnen.update({
where: {
id: ausweis.id,
},
data: {
ausgestellt: true,
},
});
}
}, 3000)
},
});

View File

@@ -7,10 +7,7 @@ import {
authorizationHeaders,
} from "#lib/middleware/authorization.js";
import {
BedarfsausweisWohnen,
Enums,
VerbrauchsausweisGewerbe,
VerbrauchsausweisWohnen,
} from "#lib/server/prisma.js";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
@@ -21,14 +18,14 @@ import { getPrismaAusweisAdapter } from "#lib/server/ausweis.js";
export const GET = defineApiRoute({
input: z.object({
uid: UUidWithPrefix,
id: UUidWithPrefix,
}),
headers: authorizationHeaders,
middleware: adminMiddleware,
async fetch({ uid }, context, user) {
const ausweisart = getAusweisartFromId(uid);
async fetch({ id }, context, user) {
const ausweisart = getAusweisartFromId(id);
const adapter = getPrismaAusweisAdapter(
uid
id
) as typeof prisma.verbrauchsausweisWohnen;
if (!adapter) {
@@ -40,7 +37,7 @@ export const GET = defineApiRoute({
const ausweis = await adapter.findUnique({
where: {
uid,
id,
},
include: {
aufnahme: {
@@ -125,32 +122,27 @@ export const GET = defineApiRoute({
? "Energiebedarfsausweis"
: "Energieverbrauchsausweis";
const body = `<Datenregistratur xmlns="http://energieausweis.dibt.de/WebServiceEnergie/DibtEnergieAusweisService">
<doc>
<root>
<Authentifizierung>
<Aussteller_ID_DIBT>${Aussteller_ID_DIBT}</Aussteller_ID_DIBT>
<Aussteller_PWD_DIBT>${Aussteller_PWD_DIBT}</Aussteller_PWD_DIBT>
</Authentifizierung>
<EnEV-Nachweis>
<Ausstellungsdatum>${Ausstellungsdatum}</Ausstellungsdatum>
<Bundesland>${postleitzahl.bundesland}</Bundesland>
<Postleitzahl>${postleitzahl.plz}</Postleitzahl>
<Gesetzesgrundlage>${Gesetzesgrundlage}</Gesetzesgrundlage>
</EnEV-Nachweis>
<Energieausweis-Daten>
<Gebaeudeart>${gebaeudeart}</Gebaeudeart>
<Art>${art}</Art>
<Neubau>${
ausweis.ausstellgrund ===
Enums.Ausstellgrund.Neubau
? "1"
: "0"
}</Neubau>
</Energieausweis-Daten>
</root>
</doc>
</Datenregistratur>`;
const requestPayload = {
doc: {
root: {
Authentifizierung: {
Aussteller_ID_DIBT: Aussteller_ID_DIBT,
Aussteller_PWD_DIBT: Aussteller_PWD_DIBT,
},
'EnEV-Nachweis': {
Ausstellungsdatum: Ausstellungsdatum,
Bundesland: postleitzahl.bundesland,
Postleitzahl: postleitzahl.plz,
Gesetzesgrundlage: Gesetzesgrundlage,
},
'Energieausweis-Daten': {
Gebaeudeart: gebaeudeart,
Art: art,
Neubau: ausweis.ausstellgrund === Enums.Ausstellgrund.Neubau ? "1" : "0",
},
},
},
}
return await new Promise(async (resolve, reject) => {
soap.createClient(
@@ -165,7 +157,7 @@ export const GET = defineApiRoute({
}
client.Datenregistratur(
body,
requestPayload,
async function (
err: any,
result: {
@@ -193,7 +185,7 @@ export const GET = defineApiRoute({
adapter as typeof prisma.verbrauchsausweisWohnen
).update({
where: {
uid,
id,
},
data: {
registriernummer:
@@ -202,9 +194,7 @@ export const GET = defineApiRoute({
.Registriernummer,
kontrolldatei_angefragt: result
.DatenregistraturResult
.WEB_Service_Antwort.Datendatei
? true
: false,
.WEB_Service_Antwort.Datendatei == 0 ? false : true,
},
});

View File

@@ -3,16 +3,17 @@ import { adminMiddleware } from "#lib/middleware/authorization.js";
import { mollieClient } from "#lib/mollie.js";
import { getPrismaAusweisAdapter } from "#lib/server/ausweis.js";
import { Prisma, prisma } from "#lib/server/prisma.js";
import { RefundStatus } from "@mollie/api-client";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "zod";
export const PUT = defineApiRoute({
input: z.object({
uid_ausweis: UUidWithPrefix
ausweis_id: UUidWithPrefix
}),
middleware: adminMiddleware,
async fetch(input, context, transfer) {
const adapter = getPrismaAusweisAdapter(input.uid_ausweis) as Prisma.VerbrauchsausweisWohnenDelegate;
const adapter = getPrismaAusweisAdapter(input.ausweis_id) as Prisma.VerbrauchsausweisWohnenDelegate;
if (!adapter) {
throw new APIError({
@@ -23,7 +24,7 @@ export const PUT = defineApiRoute({
const ausweis = await adapter.findUnique({
where: {
uid: input.uid_ausweis
id: input.ausweis_id
}
})
@@ -36,7 +37,7 @@ export const PUT = defineApiRoute({
const response = await adapter.findUnique({
where: {
uid: input.uid_ausweis
id: input.ausweis_id
},
select: {
rechnung: true
@@ -46,7 +47,7 @@ export const PUT = defineApiRoute({
if (!response || !response.rechnung) {
await adapter.update({
where: {
uid: input.uid_ausweis
id: input.ausweis_id
},
data: {
storniert: true
@@ -63,7 +64,7 @@ export const PUT = defineApiRoute({
await adapter.update({
where: {
uid: input.uid_ausweis
id: input.ausweis_id
},
data: {
storniert: true,
@@ -94,10 +95,17 @@ export const PUT = defineApiRoute({
value: rechnung.betrag.toFixed(2)
},
metadata: {
rechnung_uid: rechnung.uid
rechnung_id: rechnung.id
},
testmode: true
})
if (refund.status === RefundStatus.failed) {
throw new APIError({
code: "INTERNAL_SERVER_ERROR",
message: "Rückerstattung konnte nicht durchgeführt werden, Mollie hat die Rückerstattung abgelehnt."
})
}
}
},
})

View File

@@ -20,12 +20,11 @@ export const PATCH = defineApiRoute({
const aufnahme = await prisma.aufnahme.findUnique({
where: {
id,
benutzer_id: user.id
id
}
});
if (!aufnahme) {
if (!aufnahme || (aufnahme.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Aufnahme mit dieser UID existiert nicht oder gehört nicht dem aktuellen Benutzer."

View File

@@ -7,6 +7,7 @@ import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { TokenType } from "#lib/auth/types.js";
import { UUidWithPrefix } from "#components/Ausweis/types.js";
export const GET = defineApiRoute({
meta: {
description:
@@ -30,7 +31,7 @@ export const GET = defineApiRoute({
// Falls der Nutzer nicht existiert, wird eine Fehlermeldung zurückgegeben.
const user = await prisma.benutzer.findUnique({
where: {
email: input.email,
email: input.email.toLowerCase(),
},
});

View File

@@ -1,9 +1,9 @@
import { GEGNachweisWohnenClient, OptionalNullable, UUidWithPrefix, ZodOverlap } from "#components/Ausweis/types.js";
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import { generatePrefixedId } from "#lib/db.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma } from "#lib/server/prisma.js";
import { Enums, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { BedarfsausweisGewerbeSchema } from "src/generated/zod/bedarfsausweisgewerbe.js";
import { z } from "zod";
@@ -19,7 +19,8 @@ export const PATCH = defineApiRoute({
rechnung_id: true,
storniert: true,
updated_at: true,
zurueckgestellt: true
zurueckgestellt: true,
ausweisart: true
}),
output: z.void(),
headers: {
@@ -30,13 +31,10 @@ export const PATCH = defineApiRoute({
const objekt = await prisma.bedarfsausweisGewerbe.findUnique({
where: {
id: ctx.params.id,
benutzer: {
id: user.id
}
}
})
if (!objekt) {
if (!objekt || (objekt.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Nachweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."

View File

@@ -25,7 +25,8 @@ export const PUT = defineApiRoute({
rechnung_id: true,
storniert: true,
updated_at: true,
zurueckgestellt: true
zurueckgestellt: true,
ausweisart: true
}),
aufnahme_id: UUidWithPrefix
}),

View File

@@ -1,9 +1,9 @@
import { BedarfsausweisWohnenClient, OptionalNullable, UUidWithPrefix, VerbrauchsausweisWohnenClient, ZodOverlap } from "#components/Ausweis/types.js";
import { BedarfsausweisWohnenClient, OptionalNullable, UUidWithPrefix, ZodOverlap } from "#components/Ausweis/types.js";
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import { generatePrefixedId } from "#lib/db.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { BedarfsausweisWohnen, prisma } from "#lib/server/prisma.js";
import { Enums, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { BedarfsausweisWohnenSchema } from "src/generated/zod/bedarfsausweiswohnen.js";
import { z } from "zod";
@@ -19,7 +19,8 @@ export const PATCH = defineApiRoute({
zurueckgestellt: true,
created_at: true,
updated_at: true,
storniert: true
storniert: true,
ausweisart: true
}),
output: z.void(),
headers: {
@@ -29,14 +30,11 @@ export const PATCH = defineApiRoute({
async fetch(input, ctx, user) {
const objekt = await prisma.bedarfsausweisWohnen.findUnique({
where: {
id: ctx.params.id,
benutzer: {
id: user.id
}
id: ctx.params.id
}
})
if (!objekt) {
if (!objekt || (objekt.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Ausweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."

View File

@@ -29,6 +29,7 @@ export const PUT = defineApiRoute({
created_at: true,
updated_at: true,
storniert: true,
ausweisart: true
}),
aufnahme_id: UUidWithPrefix,
}),
@@ -51,7 +52,7 @@ export const PUT = defineApiRoute({
}
const id = generatePrefixedId(
6,
9,
VALID_UUID_PREFIXES.BedarfsausweisWohnen
);

View File

@@ -1,9 +1,9 @@
import { GEGNachweisWohnenClient, OptionalNullable, UUidWithPrefix, ZodOverlap } from "#components/Ausweis/types.js";
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import { generatePrefixedId } from "#lib/db.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma } from "#lib/server/prisma.js";
import { Enums, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { GEGNachweisGewerbeSchema } from "src/generated/zod/gegnachweisgewerbe.js";
import { z } from "zod";
@@ -19,7 +19,8 @@ export const PATCH = defineApiRoute({
rechnung_id: true,
storniert: true,
updated_at: true,
zurueckgestellt: true
zurueckgestellt: true,
ausweisart: true
}),
output: z.void(),
headers: {
@@ -29,14 +30,11 @@ export const PATCH = defineApiRoute({
async fetch(input, ctx, user) {
const objekt = await prisma.gEGNachweisGewerbe.findUnique({
where: {
id: ctx.params.id,
benutzer: {
id: user.id
}
id: ctx.params.id
}
})
if (!objekt) {
if (!objekt || (objekt.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Nachweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."

View File

@@ -25,7 +25,8 @@ export const PUT = defineApiRoute({
rechnung_id: true,
storniert: true,
updated_at: true,
zurueckgestellt: true
zurueckgestellt: true,
ausweisart: true
}),
aufnahme_id: UUidWithPrefix
}),

View File

@@ -3,7 +3,7 @@ import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import { generatePrefixedId } from "#lib/db.js";
import { exclude } from "#lib/exclude.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma } from "#lib/server/prisma.js";
import { Enums, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { GEGNachweisWohnenSchema } from "src/generated/zod/gegnachweiswohnen.js";
import { z } from "zod";
@@ -19,7 +19,8 @@ export const PATCH = defineApiRoute({
rechnung_id: true,
storniert: true,
updated_at: true,
zurueckgestellt: true
zurueckgestellt: true,
ausweisart: true
}),
output: z.void(),
headers: {
@@ -29,14 +30,11 @@ export const PATCH = defineApiRoute({
async fetch(input, ctx, user) {
const objekt = await prisma.gEGNachweisWohnen.findUnique({
where: {
id: ctx.params.id,
benutzer: {
id: user.id
}
id: ctx.params.id
}
})
if (!objekt) {
if (!objekt || (objekt.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Nachweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."

View File

@@ -25,7 +25,8 @@ export const PUT = defineApiRoute({
rechnung_id: true,
storniert: true,
updated_at: true,
zurueckgestellt: true
zurueckgestellt: true,
ausweisart: true
}),
aufnahme_id: UUidWithPrefix
}),

View File

@@ -20,14 +20,11 @@ export const PATCH = defineApiRoute({
async fetch(input, ctx, user) {
const objekt = await prisma.objekt.findUnique({
where: {
id: ctx.params.id,
benutzer: {
id: user.id
}
id: ctx.params.id
}
})
if (!objekt) {
if (!objekt || (objekt.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Objekt konnte nicht gefunden werden."

View File

@@ -1,5 +1,5 @@
import { z } from "zod";
import { prisma } from "#lib/server/prisma";
import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
export const GET = defineApiRoute({

View File

@@ -52,9 +52,6 @@ export const PUT = defineApiRoute({
})
}
console.log(nachweis);
if (!nachweis || nachweis.benutzer_id !== user.id) {
throw new APIError({
code: "BAD_REQUEST",

View File

@@ -65,6 +65,9 @@ export const PUT = defineApiRoute({
const ausweis = await adapter.findUnique({
where: {
id: ausweis_id
},
include: {
rechnung: true
}
})
@@ -75,6 +78,13 @@ export const PUT = defineApiRoute({
});
}
if (ausweis.rechnung) {
throw new APIError({
code: "BAD_REQUEST",
message: "Eine Rechnung für diesen Ausweis existiert bereits.",
});
}
if (ausweis.benutzer_id !== user.id) {
throw new APIError({
code: "UNAUTHORIZED",
@@ -101,6 +111,19 @@ export const PUT = defineApiRoute({
betrag,
bezahlmethode: bezahlmethode,
status: Enums.Rechnungsstatus.open,
abweichende_versand_adresse: input.abweichende_versand_adresse,
email: input.email,
empfaenger: input.empfaenger,
ort: input.ort,
plz: input.plz,
strasse: input.strasse,
telefon: input.telefon,
versand_ort: input.versand_ort,
versand_empfaenger: input.versand_empfaenger,
versand_plz: input.versand_plz,
versand_strasse: input.versand_strasse,
versand_zusatzzeile: input.versand_zusatzzeile,
zusatzzeile: input.zusatzzeile,
verbrauchsausweis_wohnen: {
connect: {
id: ausweis_id
@@ -118,6 +141,19 @@ export const PUT = defineApiRoute({
betrag,
bezahlmethode: bezahlmethode,
status: Enums.Rechnungsstatus.open,
abweichende_versand_adresse: input.abweichende_versand_adresse,
email: input.email,
empfaenger: input.empfaenger,
ort: input.ort,
plz: input.plz,
strasse: input.strasse,
telefon: input.telefon,
versand_ort: input.versand_ort,
versand_empfaenger: input.versand_empfaenger,
versand_plz: input.versand_plz,
versand_strasse: input.versand_strasse,
versand_zusatzzeile: input.versand_zusatzzeile,
zusatzzeile: input.zusatzzeile,
verbrauchsausweis_gewerbe: {
connect: {
id: ausweis_id
@@ -135,6 +171,19 @@ export const PUT = defineApiRoute({
betrag,
bezahlmethode: bezahlmethode,
status: Enums.Rechnungsstatus.open,
abweichende_versand_adresse: input.abweichende_versand_adresse,
email: input.email,
empfaenger: input.empfaenger,
ort: input.ort,
plz: input.plz,
strasse: input.strasse,
telefon: input.telefon,
versand_ort: input.versand_ort,
versand_empfaenger: input.versand_empfaenger,
versand_plz: input.versand_plz,
versand_strasse: input.versand_strasse,
versand_zusatzzeile: input.versand_zusatzzeile,
zusatzzeile: input.zusatzzeile,
bedarfsausweis_wohnen: {
connect: {
id: ausweis_id
@@ -178,7 +227,7 @@ export const PUT = defineApiRoute({
method: input.bezahlmethode as PaymentMethod,
description: "Verbrauchsausweis Wohnen 2016",
redirectUrl: `https://online-energieausweis.org/payment/success?a=${ausweis.id}&r=${rechnung.id}`,
webhookUrl: `https://online-energieausweis.org/api/webhooks/mollie?uid=${rechnung.id}`,
webhookUrl: `https://online-energieausweis.org/api/webhooks/mollie`,
cancelUrl: `https://online-energieausweis.org/kundendaten?a=${ausweis.id}&r=${rechnung.id}`
});

View File

@@ -3,6 +3,7 @@ import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import { generatePrefixedId } from "#lib/db.js";
import { adminMiddleware, authorizationMiddleware } from "#lib/middleware/authorization.js";
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 { APIError, defineApiRoute } from "astro-typesafe-api/server";
@@ -117,6 +118,17 @@ export const PUT = defineApiRoute({
}
})
const lex_office_id = await createLexOfficeCustomer(user);
await prisma.benutzer.update({
where: {
id: user.id
},
data: {
lex_office_id
}
})
await sendRegisterMail(user)
return { id }

View File

@@ -14,7 +14,8 @@ export const PATCH = defineApiRoute({
benutzer_id: true,
aufnahme_id: true,
updated_at: true,
created_at: true
created_at: true,
ausweisart: true
}).merge(z.object({
startdatum: z.coerce.date().nullable(),
})),
@@ -26,14 +27,11 @@ export const PATCH = defineApiRoute({
async fetch(input, ctx, user) {
const objekt = await prisma.verbrauchsausweisGewerbe.findUnique({
where: {
id: ctx.params.id,
benutzer: {
id: user.id
}
id: ctx.params.id
}
})
if (!objekt) {
if (!objekt || (objekt.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Ausweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."

View File

@@ -21,7 +21,8 @@ export const PUT = defineApiRoute({
aufnahme_id: true,
rechnung_id: true,
updated_at: true,
created_at: true
created_at: true,
ausweisart: true
}).merge(z.object({
startdatum: z.coerce.date().nullable()
})),

View File

@@ -15,7 +15,8 @@ export const PATCH = defineApiRoute({
aufnahme_id: true,
rechnung_id: true,
created_at: true,
updated_at: true
updated_at: true,
ausweisart: true
}).merge(z.object({
startdatum: z.coerce.date().nullable()
})),
@@ -27,14 +28,11 @@ export const PATCH = defineApiRoute({
async fetch(input, ctx, user) {
const objekt = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
id: ctx.params.id,
benutzer: {
id: user.id
}
id: ctx.params.id
}
})
if (!objekt) {
if (!objekt || (objekt.benutzer_id !== user.id && user.rolle !== Enums.BenutzerRolle.ADMIN)) {
throw new APIError({
code: "NOT_FOUND",
message: "Ausweis konnte nicht gefunden werden oder gehört einem anderen Benutzer."

View File

@@ -1,4 +1,5 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import { generatePrefixedId } from "#lib/db.js";
import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { prisma } from "#lib/server/prisma.js";
@@ -26,7 +27,8 @@ export const PUT = defineApiRoute({
aufnahme_id: true,
rechnung_id: true,
created_at: true,
updated_at: true
updated_at: true,
ausweisart: true
}),
aufnahme_id: UUidWithPrefix
}),
@@ -51,7 +53,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(9, "VW");
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.VerbrauchsausweisWohnen);
const createdAusweis = await prisma.verbrauchsausweisWohnen.create({
data: {

View File

@@ -19,7 +19,7 @@ export const POST = defineApiRoute({
// Wir holen uns die Transaktion von Mollie.
const payment = await mollieClient.payments.get(id);
const metadata = payment.metadata as { rechnung_uid: string }
const metadata = payment.metadata as { rechnung_id: string }
if (!payment) {
throw new APIError({
@@ -28,7 +28,7 @@ export const POST = defineApiRoute({
});
}
if (!metadata.rechnung_uid) {
if (!metadata.rechnung_id) {
throw new APIError({
code: "BAD_REQUEST",
message: "Rechnung UID nicht gefunden.",
@@ -38,7 +38,7 @@ export const POST = defineApiRoute({
// Wir holen uns die Rechnung aus unserer Datenbank.
const rechnung = await prisma.rechnung.findUnique({
where: {
uid: metadata.rechnung_uid,
id: metadata.rechnung_id,
},
});
@@ -57,6 +57,7 @@ export const POST = defineApiRoute({
data: {
status: payment.status as Enums.Rechnungsstatus,
transaktions_referenz: payment.id,
bezahlt_am: new Date()
},
});
},

View File

@@ -20,7 +20,7 @@ export const GET: APIRoute = async (Astro) => {
const file = await getS3File("ibc-images", `${image.id}.jpg`);
if (!file) {
const file = await getS3File("ibc-images", `${image.name}.jpg`)
const file = await getS3File("ibc-images", image.name)
if (!file) {
return new Response(null, { status: 404 })

View File

@@ -10,7 +10,6 @@ import ImpersonateUserModule from "#modules/ImpersonateUserModule.svelte";
const caller = createCaller(Astro)
const params = Astro.params;
const page = Number(params.page)
const user = await caller.user.self.GET.fetch(undefined, {
headers: {

View File

@@ -22,15 +22,15 @@ if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
return Astro.redirect("/dashboard")
}
const uid = Astro.url.searchParams.get("uid")
const id = Astro.url.searchParams.get("id")
if (!uid) {
if (!id) {
return Astro.redirect("/404")
}
const searchedUser = await prisma.benutzer.findUnique({
where: {
uid
id
}
})
@@ -40,12 +40,12 @@ if (!searchedUser) {
const refreshTokenExpiry = moment().add(30, "days");
const accessToken = encodeToken({
uid: searchedUser.uid,
id: searchedUser.id,
typ: TokenType.Access,
exp: moment().add(30, "minutes").valueOf(),
});
const refreshToken = encodeToken({
uid: searchedUser.uid,
id: searchedUser.id,
typ: TokenType.Refresh,
exp: refreshTokenExpiry.valueOf(),
});
@@ -60,7 +60,6 @@ Astro.cookies.set(API_ACCESS_TOKEN_COOKIE_NAME, accessToken, {
path: "/",
expires: moment().add(30, "minutes").toDate()
})
Astro.cookies.set("uid", searchedUser.uid)
return Astro.redirect("/dashboard")
---

View File

@@ -39,31 +39,49 @@ const aufnahme = await prisma.aufnahme.findUnique({
bilder: true,
unterlagen: true,
bedarfsausweise_wohnen: {
orderBy: {
updated_at: "desc"
},
include: {
rechnung: true
}
},
verbrauchsausweise_gewerbe: {
orderBy: {
updated_at: "desc"
},
include: {
rechnung: true
}
},
verbrauchsausweise_wohnen: {
orderBy: {
updated_at: "desc"
},
include: {
rechnung: true
}
},
bedarfsausweise_gewerbe: {
orderBy: {
updated_at: "desc"
},
include: {
rechnung: true
}
},
geg_nachweise_gewerbe: {
orderBy: {
updated_at: "desc"
},
include: {
rechnung: true
}
},
geg_nachweise_wohnen: {
orderBy: {
updated_at: "desc"
},
include: {
rechnung: true
}

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