Kaufabschluss Update

This commit is contained in:
Moritz Utcke
2024-02-17 16:34:12 +07:00
committed by Jens Cornelsen
parent 06b423a22e
commit cb7d78c867
9 changed files with 692 additions and 572 deletions

View File

@@ -244,7 +244,10 @@ describe("Verbrauchsausweis erstellen Schritt 1", () => {
// Der Ausweis sollte jetzt schon erstellt worden sein und wir sollten auf die kundendaten seite weitergeleitet worden sein. // Der Ausweis sollte jetzt schon erstellt worden sein und wir sollten auf die kundendaten seite weitergeleitet worden sein.
cy.url().should("contain", "/kundendaten"); cy.url().should("contain", "/kundendaten");
cy.wait(1000)
// Wir füllen jetzt die Kundendaten aus. // Wir füllen jetzt die Kundendaten aus.
cy.get("select[name='anrede']").select(Math.random() > 0.5 ? "Herr" : "Frau");
cy.get("input[name='vorname']").should("contain.value", vorname); cy.get("input[name='vorname']").should("contain.value", vorname);
cy.get("input[name='name']").should("contain.value", nachname); cy.get("input[name='name']").should("contain.value", nachname);
cy.get("input[name='email']").should("contain.value", email); cy.get("input[name='email']").should("contain.value", email);

View File

@@ -4,8 +4,8 @@
<div class="flex flex-col relative"> <div class="flex flex-col relative">
<div class="progress-section"> <div class="progress-section">
<div class="w-[85%] left-9 bg-gray-100 absolute h-3 rounded-lg"> <div class="w-full bg-gray-100 absolute h-3 rounded-lg">
<div class="bg-green-600 left-2 h-3 absolute" style={`width: ${progress}%;`}></div> <div class="bg-green-600 left-0 h-3 absolute" style={`width: ${progress}%;`}></div>
</div> </div>
<span>1</span> <span>1</span>
<span>2</span> <span>2</span>
@@ -14,14 +14,14 @@
<div class="flex flex-row justify-between"> <div class="flex flex-row justify-between">
<p>Gebäudedaten</p> <p>Gebäudedaten</p>
<p>Kundendaten</p> <p>Prüfung</p>
<p>Kaufabschluss</p> <p>Kaufabschluss</p>
</div> </div>
</div> </div>
<style> <style>
.progress-section { .progress-section {
@apply relative items-center flex flex-row justify-between px-8; @apply relative items-center flex flex-row justify-between px-0;
} }
.progress-section span { .progress-section span {

View File

@@ -0,0 +1,36 @@
<script lang="ts">
import { get_current_component } from "svelte/internal";
const component = get_current_component();
export let image: string;
export let name: string;
export let description: string;
export let price: number;
export let quantity: number;
export let removable: boolean = true;
export let maxQuantity: number = Infinity;
</script>
<div class="flex flex-row justify-between items-center">
<div class="flex flex-row gap-4">
<img src={image} class="w-24" alt="">
<div class="flex flex-col">
<h4 class="font-semibold">{name}</h4>
<span class="opacity-75">{description}</span>
<span class="font-semibold text-sm">{price * quantity}</span>
</div>
</div>
<div class="join">
<button class="btn btn-sm join-item" disabled={!removable && quantity == 1} on:click={() => {
quantity--
if ((quantity == 0) && removable) {
component.$destroy();
}
}}>-</button>
<button class="btn btn-sm join-item btn-ghost">{quantity}</button>
<button class="btn btn-sm join-item" disabled={quantity <= maxQuantity} on:click={() => quantity++}>+</button>
</div>
</div>

View File

@@ -1,204 +0,0 @@
<script lang="ts">
import { PRICES } from "#lib/constants";
import type { BedarfsausweisWohnen, Enums, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "@ibcornelsen/database/client";
export let ausweis: VerbrauchsausweisWohnen | VerbrauchsausweisGewerbe | BedarfsausweisWohnen;
const prices = PRICES[ausweis.ausweisart];
export let services: { name: string, price: number, selected: boolean, id: Enums.Service }[] = [];
let basePrice: number = prices[0];
$: price =
basePrice + services.reduce((acc, service) => (service.selected && acc + service.price) || acc, 0)
</script>
<div>
<div class="yellow-box flex flex-col gap-4">
<div class="flex flex-col gap-2 test-box">
<strong>A - Prüfung der Ausweisart</strong>
<div>
<span>Vermietung, Verkauf oder sonstiges</span>
<span>Baujahr Heizung nicht kleiner als Baujahr Gebäude</span><span
>Baujahr nach 1977 oder saniert oder mehr als 4 Wohneinheiten</span
><span>Heizung min. 3 Jahre alt</span><span
>Verbrauchsausweis zulässig</span
>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong>B - Prüfung der Adresse, Wohnfläche, Keller und Dach</strong
>
<div>
<span>PLZ gültig</span><span>Klimafaktorern</span><span
>Wohnfläche passt zu Wohneinheiten</span
>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong>C - Prüfung der Verbrauchsangaben</strong>
<div>
<span>Verbrauchsmenge schlüssig</span><span
>Verbrauchsabweichung im Rahmen</span
><span>Endenergieverbrauch schlüssig</span>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong
>D - Prüfung Warmwasser und alternative Energieversorgung</strong
>
<div>
<span>Warmwasseranteil schlüssig</span>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong
>E - Prüfung von Gebäudetyp, Lüftung, Kühlung und Leerstand</strong
>
<div>
<span>Leerstand nicht größer als 30%</span>
</div>
</div>
<div class="flex flex-col gap-2 test-box">
<strong
>F - Prüfung des Sanierungsstandes und der Gebäudebilder</strong
>
<div>
<span>Mindestens ein Bild pro Abschnitt vorhanden</span><span
>Angaben zum Sanierungsstand vorhanden</span
><span
>Bei Baujahr vor 1978 Dach oder Geschossdecke min. 12 cm gedämmt</span
>
</div>
</div>
</div>
<hr />
<div class="yellow-box flex flex-col gap-4">
<table>
<tr>
<td><strong>Produkt:</strong></td>
<td
><div class="bg-white p-2 border border-gray-300">
Verbrauchsausweis
</div></td
>
</tr>
<tr>
<td><strong>Beschreibung:</strong></td>
<td>
<div class="bg-white p-2 border border-gray-300">
Registrierung beim DiBt<br />
Prüfung durch Diplom Ingenieur<br />
Energieausweis Vorschau als PDF<br />
</div>
</td>
</tr>
<tr>
<td>Netto-Preis</td>
<td
><div class="bg-white p-2 border border-gray-300">
{(price * 0.81).toFixed(2) + "€"}
</div></td
>
</tr>
<tr>
<td>19% gesetzl. MwSt.</td>
<td
><div class="bg-white p-2 border border-gray-300">
{(price * 0.19).toFixed(2) + "€"}
</div></td
>
</tr>
<tr>
<td>Preis inkl. MwSt.</td>
<td
><div class="bg-white p-2 border border-gray-300">
<strong>{price + "€"}</strong>
</div>
</td>
</tr>
</table>
</div>
<hr />
<div class="yellow-box flex flex-col gap-4">
<strong
>Hiermit bestelle ich folgende Version des Energieausweises:<br
/></strong
>
<table>
<tr>
<td
>Verbrauchsausweis online für {prices[0]} € inkl. MwSt. als PDF
per E-Mail</td
>
<td
><input
type="radio"
bind:group={basePrice}
value={prices[0]}
name="Preis"
checked
/>
</td>
</tr>
<tr>
<td
>Verbrauchsausweis online inkl. Beratung für {prices[1]}
€ inkl. MwSt. als PDF per E-Mail</td
>
<td
><input
type="radio"
bind:group={basePrice}
value={prices[1]}
name="Preis"
/>
</td>
</tr><tr>
<td
>Verbrauchsausweis offline für {prices[2]} € inkl. MwSt. als
PDF per E-Mail (Sie schicken uns 3 Verbrauchsabrechnungen)</td
>
<td
><input
type="radio"
bind:group={basePrice}
value={prices[2]}
name="Preis"
/></td
>
</tr>
</table>
</div>
<hr />
<div class="yellow-box flex flex-col gap-4">
<table>
<strong>Zusatzleistungen:<br /></strong>
{#each services as service}
<tr>
<td
>{service.name}</td
>
<td
><input
type="checkbox"
class="IGZusatzleistung"
bind:checked={service.selected}
/>
</td>
</tr>
{/each}
</table>
</div>
</div>
<style>
.test-box div {
@apply flex flex-col gap-1.5;
}
</style>

View File

@@ -86,7 +86,7 @@ const schema = JSON.stringify({
<Header /> <Header />
<main class="grid gap-6 p-6 grid-cols-[2fr,8fr] max-w-[1920px] w-full bg-base-100"> <main class="grid gap-6 p-6 grid-cols-[2fr,8fr] max-w-[1920px] w-full bg-base-100">
<SidebarLeft></SidebarLeft> <SidebarLeft></SidebarLeft>
<article class="bg-base-200 rounded-lg border border-base-300"> <article class="bg-base-200 rounded-lg border border-base-300 h-min">
<slot /> <slot />
</article> </article>
</main> </main>

View File

@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import { BenutzerClient, GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types"; import { BenutzerClient, GebaeudeClient, UploadedGebaeudeBild, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
import { addNotification, updateNotification } from "@ibcornelsen/ui"; import { addNotification, updateNotification } from "@ibcornelsen/ui";
import { validateAccessTokenClient } from "#client/lib/validateAccessToken"; import { validateAccessTokenClient } from "../../client/lib/validateAccessToken";
import { client } from "src/trpc"; import { client } from "src/trpc";
import EmbeddedAuthFlowModule from "#modules/EmbeddedAuthFlowModule.svelte"; import EmbeddedAuthFlowModule from "#modules/EmbeddedAuthFlowModule.svelte";
import Overlay from "#components/Overlay.svelte"; import Overlay from "#components/Overlay.svelte";

View File

@@ -0,0 +1,370 @@
<script lang="ts">
import HelpLabel from "#components/HelpLabel.svelte";
import ZipSearch from "../components/PlzSuche.svelte";
import Label from "../components/Label.svelte";
import type {
BedarfsausweisWohnen,
Benutzer,
Bezahlmethoden,
VerbrauchsausweisGewerbe,
VerbrauchsausweisWohnen,
} from "@ibcornelsen/database/client";
import { Enums } from "@ibcornelsen/database/client";
import PaymentOption from "#components/PaymentOption.svelte";
import { client } from "src/trpc";
import type { inferProcedureInput } from "@trpc/server";
import type { AppRouter } from "@ibcornelsen/api";
import CheckoutItem from "#components/CheckoutItem.svelte";
export let user: Benutzer;
export let ausweis:
| VerbrauchsausweisWohnen
| BedarfsausweisWohnen
| VerbrauchsausweisGewerbe;
let rechnung: inferProcedureInput<
AppRouter["v1"]["rechnungen"]["erstellen"]
> = {};
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 selectedPaymentType: Bezahlmethoden =
Enums.Bezahlmethoden.PAYPAL;
let agbAkzeptiert: boolean;
let datenschutzAkzeptiert: boolean;
async function createPayment(e: SubmitEvent) {
e.preventDefault();
const response = await client.v1.rechnungen.erstellen.mutate({
...rechnung,
ausweisart: ausweis.ausweisart,
uid: ausweis.uid,
bezahlmethode: selectedPaymentType,
services: services
.filter((service) => service.selected)
.map((service) => service.id),
});
window.location.href = response.checkout_url;
}
</script>
<div class="grid grid-cols-[2fr_1fr] gap-4 h-full">
<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
paymentType={Enums.Bezahlmethoden.paypal}
bind:selectedPaymentType
name={"PayPal"}
icon={"/images/paypal.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.sofort}
bind:selectedPaymentType
name={"Sofort"}
icon={"/images/sofort.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.giropay}
bind:selectedPaymentType
name={"Giropay"}
icon={"/images/giropay.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.creditcard}
bind:selectedPaymentType
name={"Kreditkarte"}
icon={"/images/mastercard.png"}
></PaymentOption>
<PaymentOption
paymentType={Enums.Bezahlmethoden.rechnung}
bind:selectedPaymentType
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">Brutto</span>
<span class="font-semibold text-sm">75$</span>
</div>
<div class="flex flex-row items-center justify-between">
<span class="opacity-75 text-sm">Netto</span>
<span class="font-semibold text-sm">75$</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">75$</span>
</div>
<button class="btn btn-secondary w-full mt-4" disabled
>Bestellung Bestätigen</button
>
</div>
</div>
</div>
</div>

View File

@@ -1,397 +1,271 @@
<script lang="ts"> <script lang="ts">
import ProgressBar from "#components/Ausweis/Progressbar.svelte"; import ProgressBar from "#components/Ausweis/Progressbar.svelte";
import HelpLabel from "#components/HelpLabel.svelte"; import type {
import ZipSearch from "../components/PlzSuche.svelte"; BedarfsausweisWohnen,
import Label from "../components/Label.svelte"; Benutzer,
import PriceContainer from "#components/Kaufabschluss/PriceContainer.svelte"; Bezahlmethoden,
import type { BedarfsausweisWohnen, Benutzer, Bezahlmethoden, Rechnungen, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "@ibcornelsen/database/client"; VerbrauchsausweisGewerbe,
import { Enums } from "@ibcornelsen/database/client" VerbrauchsausweisWohnen,
import PaymentOption from "#components/PaymentOption.svelte"; } from "@ibcornelsen/database/client";
import { client } from "src/trpc"; import { Enums } from "@ibcornelsen/database/client";
import type { inferProcedureInput } from "@trpc/server";
import type { AppRouter } from "@ibcornelsen/api";
export let user: Benutzer; export let user: Benutzer;
export let ausweis: VerbrauchsausweisWohnen | BedarfsausweisWohnen | VerbrauchsausweisGewerbe; export let ausweis:
let rechnung: inferProcedureInput<AppRouter["v1"]["rechnungen"]["erstellen"]> = {}; | VerbrauchsausweisWohnen
| BedarfsausweisWohnen
| VerbrauchsausweisGewerbe;
let services = [{ let services = [
name: "Qualitätsdruck per Post (zusätzlich zur PDF Version) für 9€ inkl. MwSt.", {
id: Enums.Service.Qualitaetsdruck, name: "Qualitätsdruck per Post (zusätzlich zur PDF Version) für 9€ inkl. MwSt.",
price: 9, id: Enums.Service.Qualitaetsdruck,
selected: false price: 9,
}, { selected: false,
name: "Aushang (für öffentliche Gebäude gesetzlich vorgeschrieben) für 10€ inkl. MwSt.", },
id: Enums.Service.Aushang, {
price: 10, name: "Aushang (für öffentliche Gebäude gesetzlich vorgeschrieben) für 10€ inkl. MwSt.",
selected: false id: Enums.Service.Aushang,
}, { price: 10,
name: "Same Day Service (Bestellung Werktags vor 12:00 Uhr - Ausstellung bis 18:00 Uhr am gleichen Tag) für 29€ inkl. MwSt.", selected: false,
id: Enums.Service.SameDay, },
price: 29, {
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,
name: "Telefonische Energieeffizienzberatung für 75€ inkl. MwSt.", price: 29,
id: Enums.Service.Telefonberatung, selected: false,
price: 75, },
selected: false {
}] name: "Telefonische Energieeffizienzberatung für 75€ inkl. MwSt.",
id: Enums.Service.Telefonberatung,
price: 75,
selected: false,
},
];
export let selectedPaymentType: Bezahlmethoden = Enums.Bezahlmethoden.PAYPAL; export let selectedPaymentType: Bezahlmethoden =
Enums.Bezahlmethoden.paypal;
let agbAkzeptiert: boolean; import { PRICES } from "#lib/constants";
let datenschutzAkzeptiert: boolean;
async function createPayment(e: SubmitEvent) { const prices = PRICES[ausweis.ausweisart];
e.preventDefault()
const response = await client.v1.rechnungen.erstellen.mutate({ let basePrice: number = prices[0];
...rechnung,
ausweisart: ausweis.ausweisart,
uid: ausweis.uid,
bezahlmethode: selectedPaymentType,
services: services.filter(service => service.selected).map(service => service.id)
})
window.location.href = response.checkout_url $: price =
} basePrice +
services.reduce(
(acc, service) => (service.selected && acc + service.price) || acc,
0
);
</script> </script>
<div class="w-full px-8"> <div class="w-full px-8">
<div class="flex flex-row gap-8 items-center mb-8 w-3/5"> <div class="flex flex-row gap-8 items-center mb-8 w-full">
<div class="flex flex-col w-full"> <div class="flex flex-col w-full">
<h1>Verbrauchsausweis erstellen - 45€</h1> <h1>Verbrauchsausweis erstellen - 45€</h1>
<ProgressBar progress={50} /> <ProgressBar progress={50} />
</div> </div>
</div> </div>
<div <form>
class="w-full" <div class="grid grid-cols-[1.5fr_2fr] gap-4">
> <div class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col gap-4">
<form class="flex flex-row gap-8" on:submit={createPayment}> <div class="flex flex-col gap-2 test-box">
<div class="w-3/5"> <strong>A - Prüfung der Ausweisart</strong>
<div class="GRB3"> <div>
<HelpLabel title="Ansprechpartner" /> <span>Vermietung, Verkauf oder sonstiges</span>
<hr /> <span
<div class="grid grid-cols-3 gap-4"> >Baujahr Heizung nicht kleiner als Baujahr Gebäude</span
<!-- Anrede --> ><span
<div> >Baujahr nach 1977 oder saniert oder mehr als 4
<Label>Anrede *</Label> Wohneinheiten</span
<div> ><span>Heizung min. 3 Jahre alt</span><span
<select name="anrede" bind:value={user.anrede}> >Verbrauchsausweis zulässig</span
<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>
</div> </div>
<div class="flex flex-col gap-2 test-box">
<hr /> <strong
>B - Prüfung der Adresse, Wohnfläche, Keller und Dach</strong
<div class="GRB3"> >
<HelpLabel title="Rechnungsadresse" /> <div>
<hr /> <span>PLZ gültig</span><span>Klimafaktorern</span><span
<!-- Empfänger --> >Wohnfläche passt zu Wohneinheiten</span
>
<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>
</div> </div>
<div class="flex flex-col gap-2 test-box">
<hr /> <strong>C - Prüfung der Verbrauchsangaben</strong>
<div>
<div class="GRB3"> <span>Verbrauchsmenge schlüssig</span><span
<HelpLabel title="Versandadresse" /> >Verbrauchsabweichung im Rahmen</span
<hr /> ><span>Endenergieverbrauch schlüssig</span>
<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>
</div> </div>
<div class="flex flex-col gap-2 test-box">
<hr /> <strong
>D - Prüfung Warmwasser und alternative
<div class="GRB3"> Energieversorgung</strong
<HelpLabel title="Bezahlmethode" /> >
<hr /> <div>
<div class="flex flex-row justify-between gap-4"> <span>Warmwasseranteil schlüssig</span>
<PaymentOption paymentType={Enums.Bezahlmethoden.paypal} bind:selectedPaymentType name={"PayPal"} icon={"/images/paypal.png"}></PaymentOption>
<PaymentOption paymentType={Enums.Bezahlmethoden.sofort} bind:selectedPaymentType name={"Sofort"} icon={"/images/sofort.png"}></PaymentOption>
<PaymentOption paymentType={Enums.Bezahlmethoden.giropay} bind:selectedPaymentType name={"Giropay"} icon={"/images/giropay.png"}></PaymentOption>
<PaymentOption paymentType={Enums.Bezahlmethoden.creditcard} bind:selectedPaymentType name={"Kreditkarte"} icon={"/images/mastercard.png"}></PaymentOption>
<PaymentOption paymentType={Enums.Bezahlmethoden.rechnung} bind:selectedPaymentType name={"Rechnung"} icon={"/images/rechnung.png"}></PaymentOption>
</div> </div>
<div class="w-1/2"> </div>
<div class="flex-row justify-between"> <div class="flex flex-col gap-2 test-box">
<h5>{selectedPaymentType}</h5> <strong
<img >E - Prüfung von Gebäudetyp, Lüftung, Kühlung und
src="../../images/{selectedPaymentType == Leerstand</strong
Enums.Bezahlmethoden.creditcard >
? 'mastercard' <div>
: selectedPaymentType}.png" <span>Leerstand nicht größer als 30%</span>
class="payment-option-logo" </div>
/> </div>
</div> <div class="flex flex-col gap-2 test-box">
{#if selectedPaymentType == Enums.Bezahlmethoden.rechnung} <strong
<p> >F - Prüfung des Sanierungsstandes und der Gebäudebilder</strong
Sobald sie AGB und Datenschutzerklärung >
gelesen und akzeptiert haben können sie den <div>
Kauf fortsetzen. Durch das Klicken auf <span>Mindestens ein Bild pro Abschnitt vorhanden</span
'Kostenpflichtig Bestellen' wird ihnen eine ><span>Angaben zum Sanierungsstand vorhanden</span><span
Email mit weiteren Informationen über ihren >Bei Baujahr vor 1978 Dach oder Geschossdecke min.
Kauf zugeschickt, von der aus sie den 12 cm gedämmt</span
Bezahlvorgang abschließen können. >
</p> </div>
{:else} </div>
<p> </div>
Sobald sie AGB und Datenschutzerklärung <div>
gelesen und akzeptiert haben können sie den <div class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col">
Kauf fortsetzen. Durch das Klicken auf <table>
'Kostenpflichtig Bestellen' werden sie zu <strong <tr>
>{selectedPaymentType}</strong <td><strong>Produkt:</strong></td>
> weitergeleitet. <td
</p> ><div class="py-2">
{/if} Verbrauchsausweis
<div class="column"> </div></td
<div class="flex-row center">
<input type="checkbox" name="agb-akzeptieren" bind:checked={agbAkzeptiert} />
<label for="agb-akzeptieren"
>Ich erkläre mich mit den <a
href="https://online-energieausweis.org/agb"
>AGB</a
> vom Ingenieur-Büro Cornelsen einverstanden.</label
>
</div>
<div class="flex-row center">
<input
type="checkbox"
name="datenschutz-akzeptieren"
bind:checked={datenschutzAkzeptiert}
/>
<label for="datenschutz-akzeptieren"
>Ich erkläre mich mit der <a
href="https://online-energieausweis.org/impressum"
>Datenschutzerklärung</a
>
und
<a
href="https://online-energieausweis.org/agb#widerruf"
>Widerrufsbelehrung</a
> vom Ingenieur-Büro Cornelsen einverstanden.</label
>
</div>
</div>
<button type="submit" class="pay-button" disabled={!agbAkzeptiert || !datenschutzAkzeptiert}
>Kostenpflichtig Bestellen</button
> >
</div> </tr>
<tr>
<td><strong>Beschreibung:</strong></td>
<td>
<div class="py-2">
Registrierung beim DiBt<br />
Prüfung durch Diplom Ingenieur<br />
Energieausweis Vorschau als PDF<br />
</div>
</td>
</tr>
<tr>
<td>Netto-Preis</td>
<td
><div class="py-2">
{(price * 0.81).toFixed(2) + "€"}
</div></td
>
</tr>
<tr>
<td>19% gesetzl. MwSt.</td>
<td
><div class="py-2">
{(price * 0.19).toFixed(2) + "€"}
</div></td
>
</tr>
<hr>
<tr>
<td>Preis inkl. MwSt.</td>
<td
><div class="py-2">
<strong>{price + "€"}</strong>
</div>
</td>
</tr>
</table>
</div>
<h3 class="font-semibold mt-8">Hiermit bestelle ich folgende Version des Energieausweises:</h3>
<div class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col">
<table>
<tr>
<td
>Verbrauchsausweis online für {prices[0]} € inkl. MwSt.
als PDF per E-Mail</td
>
<td
><input
type="radio"
class="radio radio-secondary"
bind:group={basePrice}
value={prices[0]}
name="Preis"
checked
/>
</td>
</tr>
<tr>
<td
>Verbrauchsausweis online inkl. Beratung für {prices[1]}
€ inkl. MwSt. als PDF per E-Mail</td
>
<td
><input
type="radio"
class="radio radio-secondary"
bind:group={basePrice}
value={prices[1]}
name="Preis"
/>
</td>
</tr><tr>
<td
>Verbrauchsausweis offline für {prices[2]} € inkl. MwSt.
als PDF per E-Mail (Sie schicken uns 3 Verbrauchsabrechnungen)</td
>
<td
><input
type="radio"
class="radio radio-secondary"
bind:group={basePrice}
value={prices[2]}
name="Preis"
/></td
>
</tr>
</table>
</div> </div>
<hr /> <h3 class="font-semibold mt-8">Zusatzleistungen</h3>
<div class="rounded-lg border p-4 border-base-300 bg-base-100 flex flex-col">
<div class="flex flex-row w-full justify-between"> <table>
<button class="button">Zurück</button> {#each services as service}
<tr>
<td>{service.name}</td>
<td
><input
type="checkbox"
class="checkbox checkbox-secondary"
bind:checked={service.selected}
/>
</td>
</tr>
{/each}
</table>
</div> </div>
</div> </div>
<div class="w-2/5">
<PriceContainer {ausweis} bind:services /> </div>
<div class="flex flex-row justify-between">
<!-- TODO: Zurück implementieren -->
<button class="btn btn-secondary mt-4">Zurück</button>
<div class="flex flex-row gap-4">
<!-- TODO: Speichern implementieren -->
<button class="btn btn-secondary mt-4">Speichern</button>
<button class="btn btn-secondary mt-4">Zum Kaufabschluss</button>
</div> </div>
</form> </div>
</div> </form>
</div> </div>
<style> <style>
input, .test-box div {
select { @apply flex flex-col gap-1.5;
display: block;
width: 100%;
height: calc(2.25rem + 2px);
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
color: #495057;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: 0.25rem;
}
.pay-button {
@apply w-full px-4 py-3 text-center flex items-center justify-center bg-gray-500 text-white rounded-md cursor-not-allowed mt-4 select-none no-underline font-semibold;
}
.pay-button:hover {
@apply no-underline;
}
.pay-button:not([disabled]) {
@apply cursor-pointer bg-yellow-500;
}
.pay-button:not([disabled]):hover {
@apply bg-yellow-600;
} }
</style> </style>

View File

@@ -0,0 +1,41 @@
---
import KaufabschlussModule from "#modules/KaufabschlussModule.svelte";
import AusweisLayout from "#layouts/AusweisLayout.astro";
import { Benutzer, Enums } from "@ibcornelsen/database/client";
import { prisma } from "@ibcornelsen/database/server";
// Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde.
const uidAusweis = Astro.url.searchParams.get("uid");
if (!uidAusweis) {
return Astro.redirect("/404");
}
const uid = Astro.cookies.get("uid").value;
if (!uid) {
return Astro.redirect("/401");
}
const user = await prisma.benutzer.findUnique({
where: {
uid
},
}) as Benutzer;
const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
where: {
uid: uidAusweis,
},
});
if (!ausweis) {
return Astro.redirect("/404");
}
---
<AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen">
<KaufabschlussModule user={user} ausweis={ausweis} selectedPaymentType={Enums.Bezahlmethoden.PAYPAL} client:load></KaufabschlussModule>
</AusweisLayout>