Datenbank und ID Generierung

This commit is contained in:
Moritz Utcke
2025-04-07 15:33:30 -04:00
parent 32d8e2383e
commit 2abb143cfe
66 changed files with 906 additions and 6309 deletions

4
.gitignore vendored
View File

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

View File

@@ -1,4 +1,4 @@
.PHONY: dev online-energieausweis all prod backup run-database build-database install-dependencies wait-for-database prod database prisma-studio
.PHONY: dev online-energieausweis all prod backup run-database build-database install-dependencies wait-for-database prod database prisma-studio backup-database-cronjob
DB_CONTAINER_NAME := database
DB_NAME := main
@@ -57,10 +57,15 @@ all:
mkdir -p ~/logs
bun run dev 2>&1 | tee ~/logs/`date '+%d-%m-%Y_%H:%M:%S'`.log
prod: install-dependencies prisma-studio
prod: install-dependencies prisma-studio backup-database-cronjob
bun run build
mkdir -p ~/logs
mkdir -p ~/persistent/online-energieausweis
- pm2 delete online-energieausweis
NODE_ENV="production" pm2 start --name "online-energieausweis" --update-env --log ~/logs/`date '+%d-%m-%Y_%H:%M:%S'`.log --time bun -- run ./server.ts
pm2 save
backup-database-cronjob:
- pm2 delete daily-db-backup
pm2 start backup-database.bash --name "daily-db-backup" --cron "0 0 * * *"

17
backup-database.bash Normal file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
FILE_NAME=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_dumpall -c -U main | brotli --best > $FILE_NAME
# Das wird benötigt für AWS Ionos Kompatibilität.
export AWS_REQUEST_CHECKSUM_CALCULATION=when_required
export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required
# IMPORTANT: Dieser Befehl benötigt das `ionos` Profil, sonst wird er nicht funktionieren.
# Das Profil kann mit `aws configure --profile ionos` erstellt werden.
# Den Key dafür findet man auf https://dcd.ionos.com/latest/?lang=en#/key-management
aws s3 cp $FILE_NAME s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-1.ionoscloud.com --storage-class STANDARD
# Wir entfernen das Backup
rm $FILE_NAME

View File

@@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "VerbrauchsausweisGewerbe" ALTER COLUMN "stromverbrauch_enthaelt_sonstige" SET DATA TYPE VARCHAR(255);

View File

@@ -1,2 +0,0 @@
-- AlterTable
ALTER TABLE "Rechnung" ADD COLUMN "lex_office_id" TEXT;

View File

@@ -1,2 +0,0 @@
-- DropIndex
DROP INDEX "Rechnung_transaktions_referenz_key";

View File

@@ -39,7 +39,7 @@ CREATE TYPE "Service" AS ENUM ('Telefonberatung', 'Aushang', 'Qualitaetsdruck',
-- CreateTable
CREATE TABLE "Anteilshaber" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"rolle" VARCHAR,
"privilegien" BIGINT,
"benutzer_id" TEXT NOT NULL,
@@ -50,7 +50,7 @@ CREATE TABLE "Anteilshaber" (
-- CreateTable
CREATE TABLE "ApiRequests" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"date" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"ip" VARCHAR(50) NOT NULL,
"method" VARCHAR(10) NOT NULL,
@@ -66,7 +66,7 @@ CREATE TABLE "ApiRequests" (
-- CreateTable
CREATE TABLE "Aufnahme" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"benutzer_id" TEXT,
"gebaeudetyp" VARCHAR,
"gebaeudeteil" VARCHAR,
@@ -124,7 +124,7 @@ CREATE TABLE "Aufnahme" (
-- CreateTable
CREATE TABLE "BedarfsausweisGewerbe" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"ausstellgrund" "Ausstellgrund",
"keller_beheizt" BOOLEAN,
"storniert" BOOLEAN DEFAULT false,
@@ -154,7 +154,8 @@ CREATE TABLE "BedarfsausweisGewerbe" (
-- CreateTable
CREATE TABLE "BedarfsausweisWohnen" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"alte_ausweis_id" INTEGER,
"benutzer_id" TEXT,
"ausstellgrund" "Ausstellgrund",
"registriernummer" VARCHAR,
@@ -245,7 +246,8 @@ CREATE TABLE "BedarfsausweisWohnen" (
-- CreateTable
CREATE TABLE "benutzer" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"alte_id" INTEGER,
"name" VARCHAR(100),
"vorname" VARCHAR(50),
"email" VARCHAR(255) NOT NULL,
@@ -266,7 +268,7 @@ CREATE TABLE "benutzer" (
-- CreateTable
CREATE TABLE "Bild" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"kategorie" "BilderKategorie" NOT NULL,
"name" TEXT NOT NULL,
"aufnahme_id" TEXT,
@@ -276,7 +278,7 @@ CREATE TABLE "Bild" (
-- CreateTable
CREATE TABLE "Event" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"date" TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"title" VARCHAR(255) NOT NULL,
"description" TEXT,
@@ -288,7 +290,7 @@ CREATE TABLE "Event" (
-- CreateTable
CREATE TABLE "GEGEinpreisung" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"empfaenger" VARCHAR,
"strasse" VARCHAR,
"plz" VARCHAR,
@@ -310,7 +312,7 @@ CREATE TABLE "GEGEinpreisung" (
-- CreateTable
CREATE TABLE "GEGNachweisGewerbe" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"ausstellgrund" "Ausstellgrund",
"keller_beheizt" BOOLEAN,
"storniert" BOOLEAN DEFAULT false,
@@ -330,7 +332,7 @@ CREATE TABLE "GEGNachweisGewerbe" (
-- CreateTable
CREATE TABLE "GEGNachweisWohnen" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"ausstellgrund" "Ausstellgrund",
"keller_beheizt" BOOLEAN,
"storniert" BOOLEAN DEFAULT false,
@@ -361,7 +363,7 @@ CREATE TABLE "Klimafaktoren" (
-- CreateTable
CREATE TABLE "Objekt" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"latitude" DOUBLE PRECISION,
"longitude" DOUBLE PRECISION,
"plz" VARCHAR(5),
@@ -388,7 +390,8 @@ CREATE TABLE "Postleitzahlen" (
-- CreateTable
CREATE TABLE "Rechnung" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"alte_id" INTEGER,
"empfaenger" VARCHAR,
"strasse" VARCHAR,
"plz" VARCHAR,
@@ -411,6 +414,7 @@ CREATE TABLE "Rechnung" (
"storniert_am" TIMESTAMP(3),
"transaktions_referenz" VARCHAR,
"partner_code" TEXT,
"lex_office_id" TEXT,
"benutzer_id" TEXT NOT NULL,
CONSTRAINT "Rechnung_pkey" PRIMARY KEY ("id")
@@ -429,7 +433,7 @@ CREATE TABLE "RefreshTokens" (
-- CreateTable
CREATE TABLE "Tickets" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3),
"deleted_at" TIMESTAMP(3),
@@ -447,7 +451,7 @@ CREATE TABLE "Tickets" (
-- CreateTable
CREATE TABLE "Unterlage" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"name" TEXT,
"kategorie" TEXT,
"mime" TEXT NOT NULL,
@@ -458,7 +462,8 @@ CREATE TABLE "Unterlage" (
-- CreateTable
CREATE TABLE "VerbrauchsausweisGewerbe" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"alte_ausweis_id" INTEGER,
"ausstellgrund" "Ausstellgrund",
"registriernummer" VARCHAR,
"zusaetzliche_heizquelle" BOOLEAN,
@@ -484,7 +489,7 @@ CREATE TABLE "VerbrauchsausweisGewerbe" (
"stromverbrauch_enthaelt_lueftung" BOOLEAN,
"stromverbrauch_enthaelt_beleuchtung" BOOLEAN,
"stromverbrauch_enthaelt_kuehlung" BOOLEAN,
"stromverbrauch_enthaelt_sonstige" VARCHAR(50),
"stromverbrauch_enthaelt_sonstige" VARCHAR(255),
"kuehlung_enthalten" BOOLEAN,
"anteil_kuehlung_1" DOUBLE PRECISION,
"anteil_kuehlung_2" DOUBLE PRECISION,
@@ -530,7 +535,8 @@ CREATE TABLE "VerbrauchsausweisGewerbe" (
-- CreateTable
CREATE TABLE "VerbrauchsausweisWohnen" (
"id" VARCHAR(10) NOT NULL,
"id" VARCHAR(11) NOT NULL,
"alte_ausweis_id" INTEGER,
"ausstellgrund" "Ausstellgrund",
"registriernummer" VARCHAR,
"zusaetzliche_heizquelle" BOOLEAN,
@@ -705,9 +711,6 @@ CREATE UNIQUE INDEX "Objekt_id_key" ON "Objekt"("id");
-- CreateIndex
CREATE UNIQUE INDEX "Rechnung_id_key" ON "Rechnung"("id");
-- CreateIndex
CREATE UNIQUE INDEX "Rechnung_transaktions_referenz_key" ON "Rechnung"("transaktions_referenz");
-- CreateIndex
CREATE UNIQUE INDEX "RefreshTokens_token_key" ON "RefreshTokens"("token");

View File

@@ -0,0 +1,14 @@
/*
Warnings:
- Added the required column `updated_at` to the `Rechnung` table without a default value. This is not possible if the table is not empty.
- Added the required column `updated_at` to the `benutzer` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "Rechnung" ADD COLUMN "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "updated_at" TIMESTAMP(3) NOT NULL;
-- AlterTable
ALTER TABLE "benutzer" ADD COLUMN "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "updated_at" TIMESTAMP(3) NOT NULL;

View File

@@ -0,0 +1,9 @@
/*
Warnings:
- Added the required column `updated_at` to the `Bild` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "Bild" ADD COLUMN "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "updated_at" TIMESTAMP(3) NOT NULL;

View File

@@ -1,5 +1,5 @@
model Anteilshaber {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
rolle String? @db.VarChar
privilegien BigInt?

View File

@@ -1,6 +1,6 @@
model ApiRequests {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
date DateTime @default(now()) @db.Timestamp(6)
ip String @db.VarChar(50)
method String @db.VarChar(10)

View File

@@ -13,7 +13,7 @@ enum Lueftungskonzept {
}
model Aufnahme {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
benutzer_id String?
benutzer Benutzer? @relation(fields: [benutzer_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
/// @zod.describe("Art des Gebäudes und seiner primären Nutzungsart")

View File

@@ -1,5 +1,5 @@
model BedarfsausweisGewerbe {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
/// @zod.describe("Ausstellgrund wie z.B. Vermietung oder Verkauf")
ausstellgrund Ausstellgrund?

View File

@@ -1,6 +1,7 @@
model BedarfsausweisWohnen {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
alte_ausweis_id Int?
benutzer_id String?
ausstellgrund Ausstellgrund?
registriernummer String? @db.VarChar

View File

@@ -5,7 +5,8 @@ enum BenutzerRolle {
}
model Benutzer {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
alte_id Int?
name String? @db.VarChar(100)
vorname String? @db.VarChar(50)
email String @unique(map: "benutzer_email_idx") @db.VarChar(255)
@@ -40,6 +41,8 @@ model Benutzer {
geg_nachweise_wohnen GEGNachweisWohnen[]
bedarfsausweise_gewerbe BedarfsausweisGewerbe[]
created_at DateTime @default(now())
updated_at DateTime @updatedAt
ErstellteTickets Tickets[] @relation("ErstellteTickets")

View File

@@ -8,10 +8,13 @@ enum BilderKategorie {
}
model Bild {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
kategorie BilderKategorie
name String
created_at DateTime @default(now())
updated_at DateTime @updatedAt
aufnahme_id String?
aufnahme Aufnahme? @relation(fields: [aufnahme_id], references: [id], onDelete: NoAction, onUpdate: NoAction)
}

View File

@@ -3,7 +3,7 @@
// Hier werden beispielsweise Events wie "Nachricht Verschickt" gespeichert.
// Diese Events werden dann in der Admin-Oberfläche angezeigt.
model Event {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
date DateTime @default(now()) @db.Timestamp(6)
title String @db.VarChar(255)

View File

@@ -6,7 +6,7 @@ enum Einpreisungsstatus {
}
model GEGEinpreisung {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
empfaenger String? @db.VarChar
strasse String? @db.VarChar

View File

@@ -1,5 +1,5 @@
model GEGNachweisGewerbe {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
/// @zod.describe("Ausstellgrund wie z.B. Vermietung oder Verkauf")
ausstellgrund Ausstellgrund?

View File

@@ -1,5 +1,5 @@
model GEGNachweisWohnen {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
/// @zod.describe("Ausstellgrund wie z.B. Vermietung oder Verkauf")
ausstellgrund Ausstellgrund?

View File

@@ -1,5 +1,5 @@
model Objekt {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
latitude Float?
longitude Float?

View File

@@ -27,7 +27,8 @@ enum AusweisTyp {
}
model Rechnung {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
alte_id Int?
empfaenger String? @db.VarChar
strasse String? @db.VarChar
@@ -55,6 +56,9 @@ model Rechnung {
partner_code String?
lex_office_id String?
created_at DateTime @default(now())
updated_at DateTime @updatedAt
benutzer_id String
benutzer Benutzer @relation(fields: [benutzer_id], references: [id], onDelete: NoAction, onUpdate: NoAction)

View File

@@ -8,7 +8,7 @@ enum TicketStatus {
}
model Tickets {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
created_at DateTime @default(now())
updated_at DateTime? @updatedAt
deleted_at DateTime?

View File

@@ -5,7 +5,7 @@ enum UnterlagenKategorie {
}
model Unterlage {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
name String?
kategorie String?
mime String

View File

@@ -1,6 +1,7 @@
model VerbrauchsausweisGewerbe {
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
alte_ausweis_id Int?
ausstellgrund Ausstellgrund?
registriernummer String? @db.VarChar
zusaetzliche_heizquelle Boolean?

View File

@@ -1,7 +1,8 @@
model VerbrauchsausweisWohnen {
/// @zod.describe("ID des Ausweises")
id String @id @unique @db.VarChar(10)
id String @id @unique @db.VarChar(11)
alte_ausweis_id Int?
/// @zod.describe("Ausstellgrund wie z.B. Vermietung oder Verkauf")
ausstellgrund Ausstellgrund?
/// @zod.describe("Die Registriernummer des Ausweises")

View File

@@ -12,12 +12,11 @@ export const createCaller = createCallerFactory({
"admin/post-ausstellen": await import("../src/pages/api/admin/post-ausstellen.ts"),
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"),
"bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/index.ts"),
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"),
"auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"),
"bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/index.ts"),
"bedarfsausweis-wohnen/[id]": await import("../src/pages/api/bedarfsausweis-wohnen/[id].ts"),
@@ -28,16 +27,16 @@ export const createCaller = createCallerFactory({
"geg-nachweis-wohnen/[id]": await import("../src/pages/api/geg-nachweis-wohnen/[id].ts"),
"geg-nachweis-wohnen": await import("../src/pages/api/geg-nachweis-wohnen/index.ts"),
"objekt": await import("../src/pages/api/objekt/index.ts"),
"ticket": await import("../src/pages/api/ticket/index.ts"),
"user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
"rechnung/[id]": await import("../src/pages/api/rechnung/[id].ts"),
"rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"),
"rechnung": await import("../src/pages/api/rechnung/index.ts"),
"ticket": await import("../src/pages/api/ticket/index.ts"),
"user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
"aufnahme/[id]/bilder": await import("../src/pages/api/aufnahme/[id]/bilder.ts"),
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),

View File

@@ -45,7 +45,7 @@ export const AufnahmeSchema = z.object({
isolier_verglasung: z.boolean().describe("Falls die Fenster des Gebäudes isolier Verglasung haben, sollte dieser Wert auf true stehen").nullish(),
tueren_undicht: z.boolean().describe("Falls die Türen des Gebäudes undicht sind, sollte dieser Wert auf true stehen").nullish(),
tueren_dicht: z.boolean().describe("Falls die Türen des Gebäudes dicht sind, sollte dieser Wert auf true stehen").nullish(),
dachgeschoss_gedaemmt: z.boolean().describe("Falls das Dachgeschoss des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen").nullish(),
dachgeschoss_gedaemmt: z.boolean().describe("Falls das Dachgeschoss des Gebäudes ged<EFBFBD><EFBFBD>mmt ist, sollte dieser Wert auf true stehen").nullish(),
keller_decke_gedaemmt: z.boolean().describe("Falls die Kellerdecke des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen").nullish(),
keller_wand_gedaemmt: z.boolean().describe("Falls die Kellerwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen").nullish(),
aussenwand_gedaemmt: z.boolean().describe("Falls die Außenwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen").nullish(),

View File

@@ -3,6 +3,7 @@ import { Ausstellgrund, AusweisTyp } from "@prisma/client"
export const BedarfsausweisWohnenSchema = z.object({
id: z.string(),
alte_ausweis_id: z.number().int().nullish(),
benutzer_id: z.string().nullish(),
ausstellgrund: z.nativeEnum(Ausstellgrund).nullish(),
registriernummer: z.string().nullish(),

View File

@@ -3,6 +3,7 @@ import { BenutzerRolle } from "@prisma/client"
export const BenutzerSchema = z.object({
id: z.string(),
alte_id: z.number().int().nullish(),
name: z.string().nullish(),
vorname: z.string().nullish(),
email: z.string(),
@@ -17,4 +18,6 @@ export const BenutzerSchema = z.object({
firma: z.string().nullish(),
lex_office_id: z.string().nullish(),
verified: z.boolean(),
created_at: z.date(),
updated_at: z.date(),
})

View File

@@ -5,5 +5,7 @@ export const BildSchema = z.object({
id: z.string(),
kategorie: z.nativeEnum(BilderKategorie),
name: z.string(),
created_at: z.date(),
updated_at: z.date(),
aufnahme_id: z.string().nullish(),
})

View File

@@ -3,6 +3,7 @@ import { Bezahlmethoden, Rechnungsstatus, Service } from "@prisma/client"
export const RechnungSchema = z.object({
id: z.string(),
alte_id: z.number().int().nullish(),
empfaenger: z.string().nullish(),
strasse: z.string().nullish(),
plz: z.string().nullish(),
@@ -26,5 +27,7 @@ export const RechnungSchema = z.object({
transaktions_referenz: z.string().nullish(),
partner_code: z.string().nullish(),
lex_office_id: z.string().nullish(),
created_at: z.date(),
updated_at: z.date(),
benutzer_id: z.string(),
})

View File

@@ -3,6 +3,7 @@ import { Ausstellgrund, AusweisTyp } from "@prisma/client"
export const VerbrauchsausweisGewerbeSchema = z.object({
id: z.string(),
alte_ausweis_id: z.number().int().nullish(),
ausstellgrund: z.nativeEnum(Ausstellgrund).nullish(),
registriernummer: z.string().nullish(),
zusaetzliche_heizquelle: z.boolean().nullish(),

View File

@@ -3,6 +3,7 @@ import { Ausstellgrund, AusweisTyp } from "@prisma/client"
export const VerbrauchsausweisWohnenSchema = z.object({
id: z.string().describe("ID des Ausweises"),
alte_ausweis_id: z.number().int().nullish(),
ausstellgrund: z.nativeEnum(Ausstellgrund).describe("Ausstellgrund wie z.B. Vermietung oder Verkauf").nullish(),
registriernummer: z.string().describe("Die Registriernummer des Ausweises").nullish(),
zusaetzliche_heizquelle: z.boolean().describe("Falls eine sekundäre Heizquelle existiert, sollte dieser Wert auf true stehen").nullish(),

View File

@@ -140,7 +140,7 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
}
let durchschnittsKlimafaktor =
(klimafaktoren[0].klimafaktor + klimafaktoren[1].klimafaktor + klimafaktoren[2].klimafaktor) / 3 || 1;
((klimafaktoren[0].klimafaktor + klimafaktoren[1].klimafaktor + klimafaktoren[2].klimafaktor) / 3) || 1;
let energieVerbrauchHeizungBereinigt_1 =
energieVerbrauchHeizung_1 * durchschnittsKlimafaktor;

View File

@@ -39,7 +39,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.Aufnahme)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.Aufnahme)
const aufnahme = await prisma.aufnahme.create({
data: {

View File

@@ -119,7 +119,7 @@ export const DELETE = defineApiRoute({
}
})
const event_id = generatePrefixedId(6, VALID_UUID_PREFIXES.Ticket)
const event_id = generatePrefixedId(9, VALID_UUID_PREFIXES.Ticket)
// Wir erstellen ein Event, dass der Nachweis storniert wurde
// Dann können wir das in der Historie anzeigen

View File

@@ -46,7 +46,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.BedarfsausweisGewerbe)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.BedarfsausweisGewerbe)
const nachweis = await prisma.bedarfsausweisGewerbe.create({
data: {

View File

@@ -122,7 +122,7 @@ export const DELETE = defineApiRoute({
}
})
const event_id = generatePrefixedId(6, VALID_UUID_PREFIXES.Ticket)
const event_id = generatePrefixedId(9, VALID_UUID_PREFIXES.Ticket)
// Wir erstellen ein Event, dass der Ausweis storniert wurde
// Dann können wir das in der Historie anzeigen

View File

@@ -37,7 +37,7 @@ export const PUT = defineApiRoute({
);
const buffer = Buffer.from(dataWithoutPrefix, "base64");
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.Bild)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.Bild)
const bild = await prisma.bild.create({
data: {

View File

@@ -120,7 +120,7 @@ export const DELETE = defineApiRoute({
})
const event_id = generatePrefixedId(6, VALID_UUID_PREFIXES.Ticket)
const event_id = generatePrefixedId(9, VALID_UUID_PREFIXES.Ticket)
// Wir erstellen ein Event, dass der Nachweis storniert wurde
// Dann können wir das in der Historie anzeigen
await prisma.event.create({

View File

@@ -50,7 +50,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.GEGNachweisGewerbe)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.GEGNachweisGewerbe)
const nachweis = await prisma.gEGNachweisGewerbe.create({
data: {

View File

@@ -125,7 +125,7 @@ export const DELETE = defineApiRoute({
// Dann können wir das in der Historie anzeigen
await prisma.event.create({
data: {
id: generatePrefixedId(6, VALID_UUID_PREFIXES.Event),
id: generatePrefixedId(9, VALID_UUID_PREFIXES.Event),
title: "Nachweis storniert",
description: ((user.rolle === "ADMIN") && (nachweis.benutzer_id !== user.id)) ? "Nachweis wurde von einem Administrator storniert." : "Nachweis wurde vom Besitzer storniert.",
benutzer: {

View File

@@ -50,7 +50,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.GEGNachweisWohnen)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.GEGNachweisWohnen)
const nachweis = await prisma.gEGNachweisWohnen.create({
data: {

View File

@@ -17,7 +17,7 @@ export const PUT = defineApiRoute({
}),
middleware: authorizationMiddleware,
async fetch(input, context, user) {
const id = generatePrefixedId(6, "OB")
const id = generatePrefixedId(9, "OB")
console.log(id);

View File

@@ -62,7 +62,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.GEGEinpreisung)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.GEGEinpreisung)
if (ausweisart === Enums.Ausweisart.GEGNachweisWohnen) {
einpreisung = await prisma.gEGEinpreisung.create({

View File

@@ -37,6 +37,8 @@ export const PUT = defineApiRoute({
betrag: true,
storniert_am: true,
transaktions_referenz: true,
created_at: true,
updated_at: true
})
),
output: z.object({
@@ -87,7 +89,7 @@ export const PUT = defineApiRoute({
betrag += servicePriceList[service]
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.Rechnung);
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.Rechnung);
// Wir erstellen eine neue Rechnung in unserer Datenbank.
let rechnung: Rechnung | null = null;
@@ -176,7 +178,8 @@ 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: `http://online-energieausweis.org/api/webhooks/mollie?uid=${rechnung.id}`,
webhookUrl: `https://online-energieausweis.org/api/webhooks/mollie?uid=${rechnung.id}`,
cancelUrl: `https://online-energieausweis.org/kundendaten?a=${ausweis.id}&r=${rechnung.id}`
});
const checkoutUrl = payment.getCheckoutUrl();

View File

@@ -28,7 +28,7 @@ export const PUT = defineApiRoute({
id: UUidWithPrefix,
}),
async fetch(input, ctx) {
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.Ticket)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.Ticket)
const ticket = await prisma.tickets.create({
data: {

View File

@@ -29,7 +29,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.Unterlage)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.Unterlage)
await prisma.unterlage.create({
data: {

View File

@@ -13,7 +13,9 @@ export const POST = defineApiRoute({
input: BenutzerSchema.omit({
id: true,
lex_office_id: true,
rolle: true
rolle: true,
created_at: true,
updated_at: true
}),
middleware: authorizationMiddleware,
async fetch(input, context, user) {
@@ -103,7 +105,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.User);
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.User);
const user = await prisma.benutzer.create({
data: {

View File

@@ -120,7 +120,7 @@ export const DELETE = defineApiRoute({
// Dann können wir das in der Historie anzeigen
await prisma.event.create({
data: {
id: generatePrefixedId(6, VALID_UUID_PREFIXES.Event),
id: generatePrefixedId(9, VALID_UUID_PREFIXES.Event),
title: "Ausweis storniert",
description: ((user.rolle === "ADMIN") && (ausweis.benutzer_id !== user.id)) ? "Ausweis wurde von einem Administrator storniert." : "Ausweis wurde vom Besitzer storniert.",
benutzer: {

View File

@@ -48,7 +48,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.VerbrauchsausweisGewerbe)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.VerbrauchsausweisGewerbe)
const createdAusweis = await prisma.verbrauchsausweisGewerbe.create({
data: {

View File

@@ -121,7 +121,7 @@ export const DELETE = defineApiRoute({
// Dann können wir das in der Historie anzeigen
await prisma.event.create({
data: {
id: generatePrefixedId(6, VALID_UUID_PREFIXES.Event),
id: generatePrefixedId(9, VALID_UUID_PREFIXES.Event),
title: "Ausweis storniert",
description: ((user.rolle === "ADMIN") && (ausweis.benutzer_id !== user.id)) ? "Ausweis wurde von einem Administrator storniert." : "Ausweis wurde vom Besitzer storniert.",
benutzer: {

View File

@@ -51,7 +51,7 @@ export const PUT = defineApiRoute({
})
}
const id = generatePrefixedId(6, "VW");
const id = generatePrefixedId(9, "VW");
const createdAusweis = await prisma.verbrauchsausweisWohnen.create({
data: {

View File

@@ -4,6 +4,8 @@ import KundendatenModule from "#modules/KundendatenModule.svelte";
import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro";
import { Enums } from "#lib/client/prisma";
import { getCurrentUser } from "#lib/server/user";
import { getAusweisartFromId } from "#components/Ausweis/types";
import { getAufnahme, getBedarfsausweisWohnen, getBilder, getObjekt, getUnterlagen, getVerbrauchsausweisGewerbe, getVerbrauchsausweisWohnen } from "#lib/server/db";
// Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde.
@@ -11,12 +13,38 @@ const user = await getCurrentUser(Astro) || {}
// POST Body
const params = new URLSearchParams(await Astro.request.text());
const searchParams = Astro.url.searchParams;
let ausweis, aufnahme, objekt, ausweisart, bilder, unterlagen, partner_code;
if (!params.has("ausweis") || !params.has("aufnahme") || !params.has("objekt") || !params.has("bilder") || !params.has("ausweisart")) {
// Rechnung und Ausweis als GET parameter
if (searchParams.has("a") && searchParams.has("r")) {
const id = searchParams.get("id") as string
const ausweisart = getAusweisartFromId(id)
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
ausweis = await getVerbrauchsausweisWohnen(id)
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
ausweis = await getVerbrauchsausweisGewerbe(id)
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
ausweis = await getBedarfsausweisWohnen(id)
}
if (!ausweis || ausweis.benutzer_id !== user.id) {
// Ausweis gehört nicht diesem Benutzer oder existiert nicht
return Astro.redirect("/404")
}
let ausweis, aufnahme, objekt, ausweisart, bilder, unterlagen, partner_code;
aufnahme = await getAufnahme(ausweis.aufnahme_id)
objekt = await getObjekt(aufnahme?.objekt_id)
bilder = await getBilder(ausweis.aufnahme_id)
unterlagen = await getUnterlagen(ausweis.aufnahme_id)
} else {
// Nichts ist vorhanden
return Astro.redirect("/404")
}
} else {
try {
ausweis = JSON.parse(params.get("ausweis") || "")
aufnahme = JSON.parse(params.get("aufnahme") || "")
@@ -32,6 +60,7 @@ try {
} catch(e){
return Astro.redirect("/404")
}
}
---

BIN
src/testing/ausweise.csv.br Normal file

Binary file not shown.

View File

@@ -1,57 +1,92 @@
import moment from "moment";
import newUserIdMap from "./new-user-id-map.json" with { type: "json" };
import processed from "./new-ausweis-id-map.json" with { type: "json" };
import { Benutzer, Enums, prisma } from "#lib/server/prisma.js";
import { Enums, prisma } from "#lib/server/prisma.js";
import * as fs from "fs";
import { fileURLToPath } from "url";
import { hashPassword } from "#lib/password.js";
import Papa from "papaparse"
import Papa from "papaparse";
import { generatePrefixedId } from "#lib/db.js";
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import { tryCatch } from "#lib/tryCatch.js";
const saveUserMap = () => {
fs.writeFileSync(
fileURLToPath(new URL("./new-user-id-map.json", import.meta.url)),
JSON.stringify(newUserIdMap)
);
};
const path = fileURLToPath(new URL("./temp_ausweise.csv", import.meta.url));
const path = fileURLToPath(new URL("./ausweise.csv", import.meta.url));
if (!fs.existsSync(path)) {
throw new Error(`${path} existiert nicht.`)
throw new Error(`${path} existiert nicht.`);
}
let i = 0
const file = fs.createReadStream(path, "utf8");
Papa.parse(file, {
header: true,
async complete(results, file) {
for (const dataset of results.data as any) {
if (dataset.id in processed) {
i++
if (i % 50 === 0) {
console.log(`Processed ${i} of ${results.data.length}, ${Math.round(i / results.data.length * 100)}%`)
}
const existing_ausweis = await prisma.aufnahme.findFirst({
where: {
OR: [{
verbrauchsausweise_gewerbe: {
some: {
alte_ausweis_id: parseInt(dataset.id),
},
},
}, {
verbrauchsausweise_wohnen: {
some: {
alte_ausweis_id: parseInt(dataset.id),
},
},
}, {
bedarfsausweise_wohnen: {
some: {
alte_ausweis_id: parseInt(dataset.id),
},
},
}]
},
});
if (existing_ausweis) {
console.log(`Ausweis für ${dataset.id} existiert bereits, überspringen.`);
continue;
}
const user_id = dataset.user_id;
const email =
dataset.email ||
dataset.rechnung_email ||
dataset.versand_email;
let user: Benutzer | null = null;
if (!(user_id in newUserIdMap)) {
console.log(`Missing user ${user_id}`);
const email = dataset.email || dataset.rechnung_email || dataset.versand_email
if (email) {
user = await prisma.benutzer.findUnique({
let user = await prisma.benutzer.findFirst({
where: {
email
}
})
OR: [
{
alte_id: parseInt(user_id),
},
{
email,
},
],
},
});
if (!user) {
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.User)
console.log(`Missing user ${user_id}`);
if (email) {
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.User);
user = await prisma.benutzer.create({
data: {
id,
email,
passwort: hashPassword(Math.random().toString(36).slice(-8)),
passwort: hashPassword(
Math.random().toString(36).slice(-8)
),
adresse: dataset.strasse,
ort: dataset.ort,
plz: dataset.plz,
@@ -61,27 +96,16 @@ Papa.parse(file, {
telefon: dataset.telefonnummer,
},
});
}
newUserIdMap[user_id] = user.id;
saveUserMap();
}
} else {
user = await prisma.benutzer.findUnique({
where: {
id: newUserIdMap[user_id],
},
});
}
if (!user) {
saveProcessed();
console.log(`Benutzer für ausweis ${dataset.id} konnte nicht gefunden werden`)
console.log(
`Benutzer für ausweis ${dataset.id} konnte nicht gefunden werden`
);
continue;
}
}
const objekt_id = generatePrefixedId(6, VALID_UUID_PREFIXES.Objekt)
const objekt = await prisma.objekt.create({
const objekt_id = generatePrefixedId(9, VALID_UUID_PREFIXES.Objekt);
const [objekt, objekt_error] = await tryCatch(prisma.objekt.create({
data: {
id: objekt_id,
adresse: dataset.objekt_strasse,
@@ -94,9 +118,29 @@ Papa.parse(file, {
},
},
},
});
}))
const aufnahme_id = generatePrefixedId(6, VALID_UUID_PREFIXES.Objekt)
if (objekt_error) {
console.log(objekt_error);
console.log({
id: objekt_id,
adresse: dataset.objekt_strasse,
erstellungsdatum: moment(dataset.erstellungsdatum).toDate(),
ort: dataset.objekt_ort,
plz: dataset.objekt_plz,
benutzer: {
connect: {
id: user.id,
},
},
});
continue;
}
const aufnahme_id = generatePrefixedId(
6,
VALID_UUID_PREFIXES.Objekt
);
const aufnahme = await prisma.aufnahme.create({
data: {
@@ -108,9 +152,15 @@ Papa.parse(file, {
aussenwand_gedaemmt: dataset.aussenwand_gedaemmt == "1",
aussenwand_min_12cm_gedaemmt:
dataset.aussenwand_min_12cm_gedaemmt == "1",
baujahr_gebaeude: parseInt(dataset.baujahr_gebaeude) ? [parseInt(dataset.baujahr_gebaeude)] : [],
baujahr_heizung: parseInt(dataset.baujahr_anlage) ? [parseInt(dataset.baujahr_anlage)] : [],
baujahr_klima: parseInt(dataset.baujahr_klimaanlage) ? [parseInt(dataset.baujahr_klimaanlage)] : [],
baujahr_gebaeude: parseInt(dataset.baujahr_gebaeude)
? [parseInt(dataset.baujahr_gebaeude)]
: [],
baujahr_heizung: parseInt(dataset.baujahr_anlage)
? [parseInt(dataset.baujahr_anlage)]
: [],
baujahr_klima: parseInt(dataset.baujahr_klimaanlage)
? [parseInt(dataset.baujahr_klimaanlage)]
: [],
benutzer: {
connect: {
id: user.id,
@@ -144,7 +194,8 @@ Papa.parse(file, {
nutzflaeche: parseFloat(dataset.nutzflaeche),
gebaeudeteil: dataset.objekt_gebaeudeteil,
gebaeudetyp: dataset.objekt_typ,
heizungsrohre_gedaemmt: dataset.heizungsrohre_gedaemmt == "1",
heizungsrohre_gedaemmt:
dataset.heizungsrohre_gedaemmt == "1",
isolier_verglasung: dataset.isolier_verglasung == "1",
keller:
dataset.keller_beheizt == "Beheizt"
@@ -171,15 +222,18 @@ Papa.parse(file, {
? Enums.Lueftungskonzept
.LueftungsanlageOhneWaermerueckgewinnung
: Enums.Lueftungskonzept.Schachtlueftung,
niedertemperatur_kessel: dataset.niedertemperatur_kessel == "1",
niedertemperatur_kessel:
dataset.niedertemperatur_kessel == "1",
oberste_geschossdecke_gedaemmt:
dataset.oberste_geschossdecke_gedaemmt == "1",
oberste_geschossdecke_min_12cm_gedaemmt:
dataset.oberste_geschossdecke_min_12cm_gedaemmt == "1",
photovoltaik: dataset.photovoltaik == "1",
raum_temperatur_regler: dataset.raum_temperatur_regler == "1",
raum_temperatur_regler:
dataset.raum_temperatur_regler == "1",
saniert: dataset.objekt_saniert == "1",
solarsystem_warmwasser: dataset.solarsystem_warmwasser == "1",
solarsystem_warmwasser:
dataset.solarsystem_warmwasser == "1",
standard_kessel: dataset.standard_kessel == "1",
tueren_dicht: dataset.tueren_dicht == "1",
tueren_undicht: dataset.tueren_undicht == "1",
@@ -192,37 +246,47 @@ Papa.parse(file, {
});
/* -------------------------------- Bilder ------------------------------- */
try {
const images: Record<string, string[]> = JSON.parse(dataset.images);
for (const kategorie in images) {
for (const image of images[kategorie]) {
const categoryMap = {
"daemmung": Enums.BilderKategorie.Daemmung,
"fenster": Enums.BilderKategorie.Fenster,
"general": Enums.BilderKategorie.Gebaeude,
"heizung": Enums.BilderKategorie.Heizung
}
daemmung: Enums.BilderKategorie.Daemmung,
fenster: Enums.BilderKategorie.Fenster,
general: Enums.BilderKategorie.Gebaeude,
heizung: Enums.BilderKategorie.Heizung,
};
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.Bild)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.Bild);
const img = await prisma.bild.create({
data: {
id,
kategorie: categoryMap[kategorie as keyof typeof categoryMap],
kategorie:
categoryMap[
kategorie as keyof typeof categoryMap
],
aufnahme: {
connect: {
id: aufnahme.id
}
id: aufnahme.id,
},
name: image
},
name: image,
},
});
}
})
}
} catch(e) {
}
if (dataset.ausweisart === "VA") {
const ausweis = await prisma.verbrauchsausweisWohnen.create({
data: {
id: VALID_UUID_PREFIXES.VerbrauchsausweisWohnen + dataset.id,
id:
VALID_UUID_PREFIXES.VerbrauchsausweisWohnen +
dataset.id,
alte_ausweis_id: parseInt(dataset.id),
alternative_heizung: dataset.alheizung == "1",
alternative_kuehlung: dataset.alkuehlung == "1",
alternative_lueftung: dataset.allueftung == "1",
@@ -260,7 +324,13 @@ Papa.parse(file, {
},
kontrolldatei_angefragt: dataset.kontrolldatei == "1",
registriernummer: dataset.regnummer,
startdatum: moment().set("year", dataset.energieverbrauch_zeitraum_jahr).set("month", dataset.energieverbrauch_zeitraum_monat).toDate(),
startdatum: moment()
.set("year", dataset.energieverbrauch_zeitraum_jahr)
.set(
"month",
dataset.energieverbrauch_zeitraum_monat
)
.toDate(),
verbrauch_1: parseFloat(
dataset.energieverbrauch_1_heizquelle_1
),
@@ -281,22 +351,30 @@ Papa.parse(file, {
),
warmwasser_anteil_bekannt:
dataset.warmwasser_anteil_bekannt == "1",
warmwasser_enthalten: dataset.warmwasser_enthalten == "1",
warmwasser_enthalten:
dataset.warmwasser_enthalten == "1",
zurueckgestellt: dataset.zurueckGestellt == "1",
zusaetzliche_heizquelle:
dataset.zusaetzliche_heizquelle == "1",
ausstellungsdatum: moment(dataset.bestelldatum).isValid() ? moment(dataset.bestelldatum).toDate() : new Date(),
ausstellungsdatum: moment(
dataset.bestelldatum
).isValid()
? moment(dataset.bestelldatum).toDate()
: new Date(),
ausweistyp: Enums.AusweisTyp.Standard,
brennstoff_1: dataset.energietraeger_1,
brennstoff_2: dataset.energietraeger_2,
boxpruefung: dataset.boxpruefung == "1",
created_at: moment(dataset.erstellungsdatum).toDate(),
created_at: moment(dataset.erstellungsdatum).toDate()
},
});
} else if (dataset.ausweisart === "VANW") {
const ausweis = await prisma.verbrauchsausweisGewerbe.create({
data: {
id: VALID_UUID_PREFIXES.VerbrauchsausweisGewerbe + dataset.id,
id:
VALID_UUID_PREFIXES.VerbrauchsausweisGewerbe +
dataset.id,
alte_ausweis_id: parseInt(dataset.id),
alternative_heizung: dataset.alheizung == "1",
alternative_kuehlung: dataset.alkuehlung == "1",
alternative_lueftung: dataset.allueftung == "1",
@@ -327,6 +405,7 @@ Papa.parse(file, {
einheit_1: dataset.energietraeger_einheit_heizquelle_1,
einheit_2: dataset.energietraeger_einheit_heizquelle_2,
storniert: dataset.erledigt == "4",
keller_beheizt: dataset.keller_beheizt === "Beheizt",
benutzer: {
connect: {
id: user.id,
@@ -334,7 +413,13 @@ Papa.parse(file, {
},
kontrolldatei_angefragt: dataset.kontrolldatei == "1",
registriernummer: dataset.regnummer,
startdatum: moment().set("year", dataset.energieverbrauch_zeitraum_jahr).set("month", dataset.energieverbrauch_zeitraum_monat).toDate(),
startdatum: moment()
.set("year", dataset.energieverbrauch_zeitraum_jahr)
.set(
"month",
dataset.energieverbrauch_zeitraum_monat
)
.toDate(),
verbrauch_1: parseFloat(
dataset.energieverbrauch_1_heizquelle_1
),
@@ -353,25 +438,40 @@ Papa.parse(file, {
verbrauch_6: parseFloat(
dataset.energieverbrauch_3_heizquelle_2
),
anteil_kuehlung_1: parseFloat(dataset.anteil_kuehlung_1),
anteil_kuehlung_2: parseFloat(dataset.anteil_kuehlung_2),
anteil_kuehlung_1: parseFloat(
dataset.anteil_kuehlung_1
),
anteil_kuehlung_2: parseFloat(
dataset.anteil_kuehlung_2
),
brennstoff_1: dataset.energietraeger_1,
brennstoff_2: dataset.energietraeger_2,
strom_1: parseFloat(dataset.vanw_strom_1),
strom_2: parseFloat(dataset.vanw_strom_2),
strom_3: parseFloat(dataset.vanw_strom_3),
kuehlung_enthalten: dataset.wird_gekuehlt == "1" ? true : false,
stromverbrauch_enthaelt_beleuchtung: dataset.nwbeleuchtung == "1",
stromverbrauch_enthaelt_heizung: dataset.nwheizung == "1",
stromverbrauch_enthaelt_kuehlung: dataset.nwkuehlung == "1",
stromverbrauch_enthaelt_lueftung: dataset.nwlueftung == "1",
kuehlung_enthalten:
dataset.wird_gekuehlt == "1" ? true : false,
stromverbrauch_enthaelt_beleuchtung:
dataset.nwbeleuchtung == "1",
stromverbrauch_enthaelt_heizung:
dataset.nwheizung == "1",
stromverbrauch_enthaelt_kuehlung:
dataset.nwkuehlung == "1",
stromverbrauch_enthaelt_lueftung:
dataset.nwlueftung == "1",
stromverbrauch_enthaelt_sonstige: dataset.nwsonstiges,
stromverbrauch_enthaelt_warmwasser: dataset.nwwarmwasser == "1",
warmwasser_enthalten: dataset.warmwasser_enthalten == "1",
stromverbrauch_enthaelt_warmwasser:
dataset.nwwarmwasser == "1",
warmwasser_enthalten:
dataset.warmwasser_enthalten == "1",
zurueckgestellt: dataset.zurueckGestellt == "1",
zusaetzliche_heizquelle:
dataset.zusaetzliche_heizquelle == "1",
ausstellungsdatum: moment(dataset.bestelldatum).isValid() ? moment(dataset.bestelldatum).toDate() : new Date(),
ausstellungsdatum: moment(
dataset.bestelldatum
).isValid()
? moment(dataset.bestelldatum).toDate()
: new Date(),
ausweistyp: Enums.AusweisTyp.Standard,
boxpruefung: dataset.boxpruefung == "1",
created_at: moment(dataset.erstellungsdatum).toDate(),
@@ -380,7 +480,10 @@ Papa.parse(file, {
} else if (dataset.ausweisart === "BA") {
const ausweis = await prisma.bedarfsausweisWohnen.create({
data: {
id: VALID_UUID_PREFIXES.BedarfsausweisWohnen + dataset.id,
id:
VALID_UUID_PREFIXES.BedarfsausweisWohnen +
dataset.id,
alte_ausweis_id: parseInt(dataset.id),
alternative_heizung: dataset.alheizung == "1",
alternative_kuehlung: dataset.alkuehlung == "1",
alternative_lueftung: dataset.allueftung == "1",
@@ -411,14 +514,26 @@ Papa.parse(file, {
kontrolldatei_angefragt: dataset.kontrolldatei == "1",
registriernummer: dataset.regnummer,
zurueckgestellt: dataset.zurueckGestellt == "1",
anteil_zusatzheizung: parseFloat(dataset.anteil_zusatzheizung),
anteil_zusatzheizung: parseFloat(
dataset.anteil_zusatzheizung
),
anzahl_gauben: parseInt(dataset.anzahl_gauben),
anzahl_vollgeschosse: parseInt(dataset.anzahl_vollgeschosse),
anzahl_vollgeschosse: parseInt(
dataset.anzahl_vollgeschosse
),
aussenwand_bauart: dataset.aussenwand_bauart,
aussenwand_daemmung: parseFloat(dataset.aussenwand_daemmung),
aussenwand_flaeche: parseFloat(dataset.aussenwand_flaeche),
aussenwand_u_wert: parseFloat(dataset.aussenwand_u_wert),
aussenwandflaeche_unbeheizt: parseFloat(dataset.aussenwandflaeche_unbeheizt),
aussenwand_daemmung: parseFloat(
dataset.aussenwand_daemmung
),
aussenwand_flaeche: parseFloat(
dataset.aussenwand_flaeche
),
aussenwand_u_wert: parseFloat(
dataset.aussenwand_u_wert
),
aussenwandflaeche_unbeheizt: parseFloat(
dataset.aussenwandflaeche_unbeheizt
),
boden_bauart: dataset.boden_bauart,
boden_daemmung: parseFloat(dataset.boden_daemmung),
breite_gauben: parseFloat(dataset.breite_gauben),
@@ -427,7 +542,9 @@ Papa.parse(file, {
dach_u_wert: parseFloat(dataset.dach_u_wert),
// TODO Das machen wir zwar so aber das ist doch scheiße....
dachfenster_art: parseFloat(dataset.dachfenster_art),
dachfenster_flaeche: parseFloat(dataset.dachfenster_flaeche),
dachfenster_flaeche: parseFloat(
dataset.dachfenster_flaeche
),
dachflaeche: parseFloat(dataset.dachflaeche),
decke_bauart: dataset.decke_bauart,
decke_daemmung: parseFloat(dataset.decke_daemmung),
@@ -436,11 +553,21 @@ Papa.parse(file, {
fenster_art_1: parseFloat(dataset.fenster_art_1),
fenster_art_2: parseFloat(dataset.fenster_art_2),
deckenflaeche: parseFloat(dataset.deckenflaeche),
fenster_flaeche_1: parseFloat(dataset.fenster_flaeche_1),
fenster_flaeche_2: parseFloat(dataset.fenster_flaeche_2),
fensterflaeche_nw_no: parseFloat(dataset.fensterflaeche_nw_no),
fensterflaeche_so_sw: parseFloat(dataset.fensterflaeche_so_sw),
fussboden_flaeche: parseFloat(dataset.fussboden_flaeche),
fenster_flaeche_1: parseFloat(
dataset.fenster_flaeche_1
),
fenster_flaeche_2: parseFloat(
dataset.fenster_flaeche_2
),
fensterflaeche_nw_no: parseFloat(
dataset.fensterflaeche_nw_no
),
fensterflaeche_so_sw: parseFloat(
dataset.fensterflaeche_so_sw
),
fussboden_flaeche: parseFloat(
dataset.fussboden_flaeche
),
fussboden_u_wert: parseFloat(dataset.fussboden_u_wert),
geschosshoehe: parseFloat(dataset.geschosshoehe),
haustuer_art: parseFloat(dataset.haustuer_art),
@@ -454,30 +581,26 @@ Papa.parse(file, {
masse_d: parseFloat(dataset.masse_d),
masse_e: parseFloat(dataset.masse_e),
masse_f: parseFloat(dataset.masse_f),
kollektor_flaeche: parseFloat(dataset.kollektor_flaeche),
kollektor_flaeche: parseFloat(
dataset.kollektor_flaeche
),
volumen: parseFloat(dataset.volumen),
waerme_erzeugung_heizung: dataset.waerme_erzeugung_heizung,
waerme_erzeugung_heizung:
dataset.waerme_erzeugung_heizung,
warmwasser_erzeugung: dataset.warmwasser_erzeugung,
warmwasser_speicherung: dataset.warmwasser_speicherung,
warmwasser_verteilung: dataset.warmwasser_verteilung,
ausstellungsdatum: moment(dataset.bestelldatum).isValid() ? moment(dataset.bestelldatum).toDate() : new Date(),
ausstellungsdatum: moment(
dataset.bestelldatum
).isValid()
? moment(dataset.bestelldatum).toDate()
: new Date(),
ausweistyp: Enums.AusweisTyp.Standard,
boxpruefung: dataset.boxpruefung == "1",
created_at: moment(dataset.erstellungsdatum).toDate(),
},
});
}
processed[dataset.id as string] = true;
saveProcessed()
}
},
});
function saveProcessed() {
fs.writeFileSync(
fileURLToPath(new URL("./new-ausweis-id-map.json", import.meta.url)),
JSON.stringify(processed)
);
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,3 @@
import newUserIdMap from "./new-user-id-map.json" with { type: "json" };
import { Enums, prisma } from "#lib/server/prisma.js";
import Papa from "papaparse"
import * as fs from "fs";
@@ -6,13 +5,6 @@ import { fileURLToPath } from "url";
import { generatePrefixedId } from "#lib/db.js";
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
const saveUserMap = () => {
fs.writeFileSync(
fileURLToPath(new URL("./new-user-id-map.json", import.meta.url)),
JSON.stringify(newUserIdMap)
);
};
const path = fileURLToPath(new URL("./users.csv", import.meta.url));
if (!fs.existsSync(path)) {
@@ -25,24 +17,31 @@ Papa.parse(file, {
async complete(results, file) {
let i = 0;
for (const user of results.data as any) {
if (user.id in newUserIdMap) {
continue;
i++
if (i % 50 === 0) {
console.log(`Processed ${i} of ${results.data.length}, ${Math.round(i / results.data.length * 100)}%`)
}
if (await prisma.benutzer.findUnique({
const existing = await prisma.benutzer.findFirst({
where: {
OR: [{
alte_id: parseInt(user.id)
}, {
email: user.email
}]
}
})) {
continue;
})
if (existing) {
continue
}
try {
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.User)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.User)
await prisma.benutzer.create({
data: {
id,
alte_id: parseInt(user.id),
email: user.email,
passwort: user.password,
adresse: user.adresse,
@@ -60,28 +59,11 @@ Papa.parse(file, {
telefon: user.phone,
}
});
newUserIdMap[user.id] = id;
} catch (e) {
saveUserMap();
console.log(e);
console.log(user);
continue;
}
// Alle 50 werden gespeichert.
if (i % 50 == 0) {
console.log(`Saved ${i} - ${results.data.length - i} left`);
saveUserMap();
}
i++;
}
}
});
process.on("SIGINT", () => {
console.log("Shutting down.");
saveUserMap()
process.exit(0)
})

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,4 @@
import newRechnungenIdMap from "./new-rechnungen-id-map.json" with { type: "json" };
import newUserIdMap from "./new-user-id-map.json" with { type: "json" };
import { Enums, prisma } from "#lib/server/prisma.js";
import { Enums, Prisma, prisma } from "#lib/server/prisma.js";
import Papa from "papaparse"
import * as fs from "fs";
import { fileURLToPath } from "url";
@@ -8,13 +6,6 @@ import { generatePrefixedId } from "#lib/db.js";
import { VALID_UUID_PREFIXES } from "#lib/constants.js";
import moment from "moment";
const saveRechnungenMap = () => {
fs.writeFileSync(
fileURLToPath(new URL("./new-rechnungen-id-map.json", import.meta.url)),
JSON.stringify(newRechnungenIdMap)
);
};
const path = fileURLToPath(new URL("./rechnungen.csv", import.meta.url));
if (!fs.existsSync(path)) {
@@ -27,17 +18,34 @@ Papa.parse(file, {
async complete(results, file) {
let i = 0;
for (const rechnung of results.data as any) {
if (rechnung.id in newRechnungenIdMap) {
i++
if (i % 50 === 0) {
console.log(`Processed ${i} of ${results.data.length}, ${Math.round(i / results.data.length * 100)}%`)
}
const existing = await prisma.rechnung.findFirst({
where: {
alte_id: parseInt(rechnung.id)
}
})
if (existing) {
console.log(`Rechnung für ${rechnung.id} existiert bereits.`);
continue;
}
if (!(rechnung.user_id in newUserIdMap)) {
const user = await prisma.benutzer.findFirst({
where: {
alte_id: parseInt(rechnung.user_id)
}
})
if (!user) {
console.log(`User ${rechnung.user_id} not found.`);
continue;
}
try {
const id = generatePrefixedId(6, VALID_UUID_PREFIXES.Rechnung)
const id = generatePrefixedId(9, VALID_UUID_PREFIXES.Rechnung)
const services: Enums.Service[] = []
@@ -79,20 +87,21 @@ Papa.parse(file, {
"SUE-OK": Enums.Bezahlmethoden.sofort,
"": Enums.Bezahlmethoden.rechnung
}
await prisma.rechnung.create({
data: {
const data: Parameters<typeof prisma.rechnung.create>[0]["data"] = {
id,
alte_id: parseInt(rechnung.id),
betrag: parseFloat(rechnung.amount),
bezahlmethode: paymentTypeMap[rechnung.payment_type],
bezahlmethode: paymentTypeMap[rechnung.payment_type as keyof typeof paymentTypeMap],
// bedarfsausweis_gewerbe,
// bedarfsausweis_wohnen,
// benutzer,
// benutzer_id,
status: rechnung.status === "storniert" ? Enums.Rechnungsstatus.canceled : rechnung.status,
bezahlt_am: moment(rechnung.date_created).toDate(),
bezahlt_am: moment(rechnung.date_created).isValid() ? moment(rechnung.date_created).toDate() : new Date(),
email: rechnung.email,
empfaenger: `${rechnung.vorname} ${rechnung.name}`,
erstellt_am: moment(rechnung.date_created).toDate(),
erstellt_am: moment(rechnung.date_created).isValid() ? moment(rechnung.date_created).toDate() : new Date(),
// geg_nachweis_gewerbe,
// geg_nachweis_wohnen,
ort: rechnung.ort,
@@ -108,31 +117,59 @@ Papa.parse(file, {
versand_plz: rechnung.plz,
versand_strasse: rechnung.strasse,
lex_office_id: rechnung.lex_office_id,
benutzer_id: newUserIdMap[rechnung.user_id]
benutzer: {
connect: {
id: user.id
}
}
}
});
newRechnungenIdMap[rechnung.id] = id;
const verbrauchsausweisWohnen = await prisma.verbrauchsausweisWohnen.findFirst({
where: {
alte_ausweis_id: parseInt(rechnung.ausweis_id)
}
})
if (verbrauchsausweisWohnen) {
data["verbrauchsausweis_wohnen"] = {
connect: {
id: verbrauchsausweisWohnen.id
}
}
} else {
const verbrauchsausweisGewerbe = await prisma.verbrauchsausweisGewerbe.findFirst({
where: {
alte_ausweis_id: parseInt(rechnung.ausweis_id)
}
})
if (verbrauchsausweisGewerbe) {
data["verbrauchsausweis_gewerbe"] = {
connect: {
id: verbrauchsausweisGewerbe.id
}
}
} else {
const bedarfsausweisWohnen = await prisma.bedarfsausweisWohnen.findFirst({
where: {
alte_ausweis_id: parseInt(rechnung.ausweis_id)
}
})
if (bedarfsausweisWohnen) {
data["bedarfsausweis_wohnen"] = {
connect: {
id: bedarfsausweisWohnen.id
}
}
}
}
}
await prisma.rechnung.create({
data
});
} catch (e) {
saveRechnungenMap();
console.log(e);
continue;
}
// Alle 50 werden gespeichert.
if (i % 50 == 0) {
console.log(`Saved ${i} - ${results.data.length - i} left`);
saveRechnungenMap();
}
i++;
}
}
});
process.on("SIGINT", () => {
console.log("Shutting down.");
saveRechnungenMap()
process.exit(0)
})

Binary file not shown.

File diff suppressed because it is too large Load Diff

BIN
src/testing/users.csv.br Normal file

Binary file not shown.