staging nach main #558

Merged
Letsmoe merged 58 commits from staging into main 2025-08-02 18:05:25 +00:00
6 changed files with 13 additions and 429 deletions
Showing only changes of commit f9dc9ebd48 - Show all commits

View File

@@ -5,7 +5,6 @@ export const createCaller = createCallerFactory({
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
"unterlage": await import("../src/pages/api/unterlage.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"admin/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"),
"admin/bedarfsausweis-ausstellen": await import("../src/pages/api/admin/bedarfsausweis-ausstellen.ts"),
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
@@ -14,6 +13,7 @@ export const createCaller = createCallerFactory({
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"),
"auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
@@ -31,14 +31,15 @@ export const createCaller = createCallerFactory({
"rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"),
"rechnung": await import("../src/pages/api/rechnung/index.ts"),
"ticket": await import("../src/pages/api/ticket/index.ts"),
"user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
"objekt/[id]": await import("../src/pages/api/objekt/[id]/index.ts"),
"aufnahme/[id]/bilder": await import("../src/pages/api/aufnahme/[id]/bilder.ts"),
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),
"aufnahme/[id]/unterlagen": await import("../src/pages/api/aufnahme/[id]/unterlagen.ts"),
"objekt/[id]": await import("../src/pages/api/objekt/[id]/index.ts"),
})

View File

@@ -2,6 +2,7 @@
export let hidden: boolean = true;
export let closeable: boolean = true;
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';
import { Cross1 } from 'radix-svelte-icons';
$: if (globalThis.window) {
if (hidden) {
@@ -12,13 +13,11 @@
}
</script>
<div class="fixed top-0 left-0 w-[100vw] h-[100vh] flex items-center justify-center bg-[rgba(0,0,0,0.8)] z-50" class:hidden={hidden} on:click|self={() => {
hidden = closeable ? true : hidden;
}}>
<div class="fixed top-0 left-0 w-[100vw] h-[100vh] flex items-center justify-center bg-[rgba(0,0,0,0.8)] z-50" class:hidden={hidden}>
{#if closeable}
<button class="absolute top-4 left-4 text-white" on:click={() => {
<button class="absolute top-4 right-4 text-white bg-gray-50 bg-opacity-25 px-4 py-2 rounded-lg" type="button" on:click={() => {
hidden = true;
}}>Schließen</button>
}}><Cross1 size={20}></Cross1></button>
{/if}
<slot></slot>
</div>

View File

@@ -6,11 +6,10 @@
export let onLogin: (response: Awaited<ReturnType<typeof loginClient>>) => any;
export let email: string = "";
export let password: string = "";
export let route: "login" | "signup" = "login"
let route: "login" | "signup" = "login"
const navigate = (target: typeof route) => {
route = target
const navigate = (target: string) => {
route = target as typeof route;
}
const loginData = {

View File

@@ -1,384 +0,0 @@
<script lang="ts">
import ZipSearch from "../components/PlzSuche.svelte";
import Label from "../components/Label.svelte";
import type {
Bezahlmethoden,
} from "#lib/client/prisma";
import { Enums } from "#lib/client/prisma";
import PaymentOption from "#components/PaymentOption.svelte";
import CheckoutItem from "#components/CheckoutItem.svelte";
import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
import { PRICES } from "#lib/constants.js";
import { RechnungClient } from "#components/Ausweis/types.js";
import { api } from "astro-typesafe-api/client";
export let user: BenutzerClient;
export let ausweis:
| VerbrauchsausweisWohnenClient;
// TODO: überarbeiten und zu inferProcedureOutput machen
let rechnung: Partial<RechnungClient> = {
email: user.email,
empfaenger: user.vorname + " " + user.name,
strasse: user.adresse,
plz: user.plz,
ort: user.ort,
versand_empfaenger: user.vorname + " " + user.name,
versand_strasse: user.adresse,
versand_plz: user.plz,
versand_ort: user.ort,
telefon: user.telefon,
};
let services = [
{
name: "Qualitätsdruck per Post (zusätzlich zur PDF Version) für 9€ inkl. MwSt.",
id: Enums.Service.Qualitaetsdruck,
price: 9,
selected: false,
},
{
name: "Aushang (für öffentliche Gebäude gesetzlich vorgeschrieben) für 10€ inkl. MwSt.",
id: Enums.Service.Aushang,
price: 10,
selected: false,
},
{
name: "Same Day Service (Bestellung Werktags vor 12:00 Uhr - Ausstellung bis 18:00 Uhr am gleichen Tag) für 29€ inkl. MwSt.",
id: Enums.Service.SameDay,
price: 29,
selected: false,
},
{
name: "Telefonische Energieeffizienzberatung für 75€ inkl. MwSt.",
id: Enums.Service.Telefonberatung,
price: 75,
selected: false,
},
];
export let aktiveBezahlmethode: Bezahlmethoden =
Enums.Bezahlmethoden.paypal;
async function createPayment(e: SubmitEvent) {
e.preventDefault();
// TODO
const response = await api.rechnung.PUT.fetch({
...rechnung,
ausweisart: Enums.Ausweisart.VerbrauchsausweisWohnen,
ausweis_uid: ausweis.uid,
bezahlmethode: aktiveBezahlmethode,
services: services
.filter((service) => service.selected)
.map((service) => service.id),
});
if (aktiveBezahlmethode === Enums.Bezahlmethoden.rechnung) {
window.location.href = `/payment/success?r=${response.uid}&a=${ausweis.uid}`
} else {
window.location.href = response.checkout_url as string;
}
}
const priceTotal = services.reduce((acc, service) => {
if (service.selected) {
return acc + service.price;
}
return acc;
}, 0) + PRICES[Enums.Ausweisart.VerbrauchsausweisWohnen][0];
</script>
<form class="grid grid-cols-[2fr_1fr] gap-4 h-full" on:submit={createPayment}>
<div>
<h3 class="font-semibold">Ansprechpartner</h3>
<div class="rounded-lg border p-4 border-base-300 bg-base-100">
<div class="grid grid-cols-3 gap-4">
<!-- Anrede -->
<div>
<Label>Anrede *</Label>
<div>
<select name="anrede" bind:value={user.anrede}>
<option>bitte auswählen</option>
<option value="Herr">Herr</option>
<option value="Frau">Frau</option>
</select>
</div>
</div>
<!-- Vorname -->
<div>
<Label>Vorname *</Label>
<input
name="vorname"
type="text"
bind:value={user.vorname}
required
/>
</div>
<!-- Nachname -->
<div>
<Label>Nachname *</Label>
<input
name="name"
type="text"
bind:value={user.name}
required
/>
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<!-- Telefon -->
<div>
<Label>Telefon</Label>
<input
name="telefon"
bind:value={user.telefon}
type="text"
/>
</div>
<!-- Email -->
<div>
<Label>E-Mail *</Label>
<input
name="email"
type="email"
bind:value={user.email}
required
/>
</div>
</div>
</div>
<h3 class="mt-8 font-semibold">Rechnungsadresse</h3>
<div class="rounded-lg border p-4 border-base-300 bg-base-100">
<div class="grid grid-cols-2 gap-4">
<div>
<Label>Empfänger *</Label>
<input
name="rechnung_empfaenger"
type="text"
bind:value={rechnung.empfaenger}
required
data-rule-maxlength="100"
data-msg-maxlength="max. 100 Zeichen"
/>
</div>
<!-- Zusatzzeile -->
<div>
<Label>Zusatzzeile</Label>
<input
name="rechnung_zusatzzeile"
bind:value={rechnung.zusatzzeile}
type="text"
data-rule-maxlength="80"
data-msg-maxlength="max. 80 Zeichen"
/>
</div>
</div>
<div class="grid grid-cols-3 gap-4">
<!-- Strasse -->
<div>
<Label>Straße, Hausnummer *</Label>
<input
name="rechnung_strasse"
bind:value={rechnung.strasse}
type="text"
required
data-rule-maxlength="40"
data-msg-maxlength="max. 40 Zeichen"
/>
</div>
<!-- PLZ -->
<ZipSearch
name="rechnung_plz"
bind:zip={rechnung.plz}
bind:city={rechnung.ort}
/>
<!-- Ort -->
<div>
<Label>Ort *</Label>
<input
name="rechnung_ort"
readonly
type="text"
required
value={rechnung.ort}
/>
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<!-- Telefon -->
<div>
<Label>Telefon</Label>
<input
name="rechnung_telefon"
bind:value={rechnung.telefon}
type="text"
/>
</div>
<!-- Email -->
<div>
<Label>E-Mail</Label>
<input
name="rechnung_email"
bind:value={rechnung.email}
type="email"
/>
</div>
</div>
</div>
<h3 class="mt-8 font-semibold">Versandadresse</h3>
<div class="rounded-lg border p-4 border-base-300 bg-base-100">
<div class="flex flex-row gap-2 items-center">
<input
class="w-[15px] h-[15px]"
type="checkbox"
name="abweichende_versand_adresse"
bind:checked={rechnung.abweichende_versand_adresse}
/>
<Label>Abweichende Versandadresse</Label>
</div>
<div class="grid grid-cols-2 gap-4">
<!-- Empfänger -->
<div>
<Label>Empfänger *</Label>
<input
name="versand_empfaenger"
type="text"
readonly={!rechnung.abweichende_versand_adresse}
bind:value={rechnung.versand_empfaenger}
required
data-rule-maxlength="100"
data-msg-maxlength="max. 100 Zeichen"
/>
</div>
<!-- Zusatzzeile -->
<div>
<Label>Zusatzzeile</Label>
<input
name="versand_zusatzzeile"
type="text"
readonly={!rechnung.abweichende_versand_adresse}
bind:value={rechnung.versand_zusatzzeile}
data-rule-maxlength="80"
data-msg-maxlength="max. 80 Zeichen"
/>
</div>
</div>
<div class="grid grid-cols-3 gap-4">
<!-- Strasse -->
<div>
<Label>Straße, Hausnummer *</Label>
<input
name="versand_strasse"
type="text"
readonly={!rechnung.abweichende_versand_adresse}
bind:value={rechnung.versand_strasse}
required
data-rule-maxlength="40"
data-msg-maxlength="max. 40 Zeichen"
/>
</div>
<!-- PLZ -->
<ZipSearch
name="versand_plz"
readonly={!rechnung.abweichende_versand_adresse}
bind:zip={rechnung.versand_plz}
bind:city={rechnung.versand_ort}
/>
<!-- Ort -->
<div>
<Label>Ort *</Label>
<input
name="versand_ort"
type="text"
readonly
required
bind:value={rechnung.versand_ort}
/>
</div>
</div>
</div>
<h3 class="mt-8 font-semibold">Bezahlmethode</h3>
<div
class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-row gap-4 justify-between"
>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.paypal}
bind:aktiveBezahlmethode
name={"PayPal"}
icon={"/images/paypal.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.sofort}
bind:aktiveBezahlmethode
name={"Sofort"}
icon={"/images/sofort.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.giropay}
bind:aktiveBezahlmethode
name={"Giropay"}
icon={"/images/giropay.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.creditcard}
bind:aktiveBezahlmethode
name={"Kreditkarte"}
icon={"/images/mastercard.png"}
></PaymentOption>
<PaymentOption
bezahlmethode={Enums.Bezahlmethoden.rechnung}
bind:aktiveBezahlmethode
name={"Rechnung"}
icon={"/images/rechnung.png"}
></PaymentOption>
</div>
</div>
<div>
<h3 class="font-semibold">Zusammenfassung</h3>
<div class="rounded-lg border p-4 border-base-300 bg-base-100">
<CheckoutItem
image={"https://www.gih.de/wp-content/uploads/2015/11/EnergieausweisW-E.jpg"}
name={"Energieausweis"}
description={"Verbrauchsausweis Wohnen"}
price={45}
quantity={1}
removable={false}
maxQuantity={1}
/>
<div class="mt-auto">
<hr />
<div class="flex flex-row items-center justify-between">
<span class="opacity-75 text-sm">Netto</span>
<span class="font-semibold text-sm">{Math.round(priceTotal * 0.81 * 100) / 100}</span>
</div>
<div class="flex flex-row items-center justify-between">
<span class="opacity-75 text-sm">19% MwSt</span>
<span class="font-semibold text-sm">{Math.round(priceTotal * 0.19 * 100) / 100}}€</span>
</div>
<hr />
<div class="flex flex-row items-center justify-between">
<span class="opacity-75 text-sm">Gesamt</span>
<span class="font-semibold text-sm">{Math.round(priceTotal)}</span>
</div>
<p class="mt-8">Mit dem Klick auf "Bestellung Bestätigen" akzeptieren sie unsere <a href="/agb">AGB</a> und <a href="/impressum">Datenschutzbestimmungen</a>. Sie werden zu ihrem ausgewählten Bezahlprovider weitergeleitet, nach Bezahlung werden sie automatisch zu unserem Portal zurückgeleitet.</p>
<button class="btn btn-secondary w-full mt-4"
>Bestellung Bestätigen</button
>
</div>
</div>
</div>
</form>

View File

@@ -1215,7 +1215,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
<Overlay bind:hidden={loginOverlayHidden}>
<div class="bg-white w-full max-w-screen-sm py-8">
<EmbeddedAuthFlowModule onLogin={loginAction} email={email}></EmbeddedAuthFlowModule>
<EmbeddedAuthFlowModule onLogin={loginAction} email={email} route="signup"></EmbeddedAuthFlowModule>
</div>
</Overlay>

View File

@@ -1,31 +0,0 @@
---
import KaufabschlussModule from "#modules/KaufabschlussModule.svelte";
import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro";
import { Enums } from "#lib/client/prisma";
import { createCaller } from "src/astro-typesafe-api-caller";
// Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde.
const uid = Astro.url.searchParams.get("uid");
if (!uid) {
return Astro.redirect("/404");
}
const caller = createCaller(Astro);
const ausweis = await caller.v1.verbrauchsausweisWohnen.get({
uid
})
const user = await caller.v1.benutzer.self();
if (!ausweis || !user) {
return Astro.redirect("/404");
}
---
<AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen">
<KaufabschlussModule user={user} ausweis={ausweis} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} client:load></KaufabschlussModule>
</AusweisLayout>