Merge branch 'main' into dev

This commit is contained in:
Moritz Utcke
2025-08-05 19:49:58 -04:00
12 changed files with 101 additions and 70 deletions

View File

@@ -36,7 +36,7 @@
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"mime": "^4.0.6", "mime": "^4.0.6",
"moment": "^2.30.1", "moment": "^2.30.1",
"moment-timezone": "^0.5.46", "moment-timezone": "^0.6.0",
"nodemailer": "^6.10.0", "nodemailer": "^6.10.0",
"pdf-lib": "^1.17.1", "pdf-lib": "^1.17.1",
"postcss-nested": "^7.0.2", "postcss-nested": "^7.0.2",
@@ -1965,7 +1965,7 @@
"moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], "moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="],
"moment-timezone": ["moment-timezone@0.5.47", "", { "dependencies": { "moment": "^2.29.4" } }, "sha512-UbNt/JAWS0m/NJOebR0QMRHBk0hu03r5dx9GK8Cs0AS3I81yDcOc9k+DytPItgVvBP7J6Mf6U2n3BPAacAV9oA=="], "moment-timezone": ["moment-timezone@0.6.0", "", { "dependencies": { "moment": "^2.29.4" } }, "sha512-ldA5lRNm3iJCWZcBCab4pnNL3HSZYXVb/3TYr75/1WCTWYuTqYUb5f/S384pncYjJ88lbO8Z4uPDvmoluHJc8Q=="],
"mrmime": ["mrmime@2.0.0", "", {}, "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw=="], "mrmime": ["mrmime@2.0.0", "", {}, "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw=="],

View File

@@ -50,7 +50,7 @@
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"mime": "^4.0.6", "mime": "^4.0.6",
"moment": "^2.30.1", "moment": "^2.30.1",
"moment-timezone": "^0.5.46", "moment-timezone": "^0.6.0",
"nodemailer": "^6.10.0", "nodemailer": "^6.10.0",
"pdf-lib": "^1.17.1", "pdf-lib": "^1.17.1",
"postcss-nested": "^7.0.2", "postcss-nested": "^7.0.2",

View File

@@ -1,6 +1,7 @@
model Provisionen { model Provisionen {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
ausweisart Ausweisart ausweisart Ausweisart
ausweistyp AusweisTyp
provision_prozent Float provision_prozent Float
provision_betrag Float provision_betrag Float
benutzer_id String? @db.VarChar(11) benutzer_id String? @db.VarChar(11)

View File

@@ -12,8 +12,8 @@ export const createCaller = createCallerFactory({
"admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"), "admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"),
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"), "admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"), "admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"), "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/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.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"), "auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
@@ -26,17 +26,15 @@ export const createCaller = createCallerFactory({
"geg-nachweis-gewerbe": await import("../src/pages/api/geg-nachweis-gewerbe/index.ts"), "geg-nachweis-gewerbe": await import("../src/pages/api/geg-nachweis-gewerbe/index.ts"),
"geg-nachweis-wohnen/[id]": await import("../src/pages/api/geg-nachweis-wohnen/[id].ts"), "geg-nachweis-wohnen/[id]": await import("../src/pages/api/geg-nachweis-wohnen/[id].ts"),
"geg-nachweis-wohnen": await import("../src/pages/api/geg-nachweis-wohnen/index.ts"), "geg-nachweis-wohnen": await import("../src/pages/api/geg-nachweis-wohnen/index.ts"),
"objekt": await import("../src/pages/api/objekt/index.ts"),
"rechnung/[id]": await import("../src/pages/api/rechnung/[id].ts"), "rechnung/[id]": await import("../src/pages/api/rechnung/[id].ts"),
"rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"), "rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"),
"rechnung": await import("../src/pages/api/rechnung/index.ts"), "rechnung": await import("../src/pages/api/rechnung/index.ts"),
"objekt": await import("../src/pages/api/objekt/index.ts"),
"ticket": await import("../src/pages/api/ticket/index.ts"), "ticket": await import("../src/pages/api/ticket/index.ts"),
"user": await import("../src/pages/api/user/index.ts"), "user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.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/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"), "verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"), "verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"), "verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"), "webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),

View File

@@ -1,7 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Aufnahme, BedarfsausweisWohnen, Enums, Objekt, Provisionen, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/server/prisma.js"; import { Aufnahme, BedarfsausweisWohnen, Enums, Objekt, Provisionen, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/server/prisma.js";
import moment from "moment"; import moment from "moment-timezone"
import { DatePicker } from "@svelte-plugins/datepicker" import { DatePicker } from "@svelte-plugins/datepicker"
import { getProvision } from "#lib/provision.js";
export let bestellungen: (Rechnung & { export let bestellungen: (Rechnung & {
ausweis: (VerbrauchsausweisWohnen | BedarfsausweisWohnen | VerbrauchsausweisGewerbe) & { aufnahme: Aufnahme & { objekt: Objekt }} ausweis: (VerbrauchsausweisWohnen | BedarfsausweisWohnen | VerbrauchsausweisGewerbe) & { aufnahme: Aufnahme & { objekt: Objekt }}
})[]; })[];
@@ -9,6 +10,8 @@
export let email: string; export let email: string;
export let startdatum: Date; export let startdatum: Date;
export let enddatum: Date; export let enddatum: Date;
moment.locale("de");
moment.tz.setDefault("Europe/Berlin");
const bestellungenNachMonat: Record<string, (typeof bestellungen)> = {}; const bestellungenNachMonat: Record<string, (typeof bestellungen)> = {};
for (const bestellung of bestellungen) { for (const bestellung of bestellungen) {
@@ -21,12 +24,6 @@
} }
// Wir brauchen alle Monate zwischen dem ersten Mal, dass der partner_code benutzt wurde bis zum heutigen Zeitpunkt. // Wir brauchen alle Monate zwischen dem ersten Mal, dass der partner_code benutzt wurde bis zum heutigen Zeitpunkt.
const months: Record<string, string> = {
"01": "Januar", "02": "Februar", "03": "März", "04": "April",
"05": "Mai", "06": "Juni", "07": "Juli", "08": "August",
"09": "September", "10": "Oktober", "11": "November", "12": "Dezember"
};
function getMonthlyPeriods(from: Date, to: Date): moment.Moment[] { function getMonthlyPeriods(from: Date, to: Date): moment.Moment[] {
const start = moment(from).startOf('month'); const start = moment(from).startOf('month');
const end = moment(to).endOf('month'); const end = moment(to).endOf('month');
@@ -59,7 +56,7 @@
<div class="fixed top-0 left-0 right-0 bg-white p-4 shadow z-10"> <div class="fixed top-0 left-0 right-0 bg-white p-4 shadow z-10">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<DatePicker bind:isOpen bind:startDate={startdatum} bind:endDate={enddatum} isRange={true} onDateChange={onChange} isMultipane={true}> <DatePicker bind:isOpen bind:startDate={startdatum} bind:endDate={enddatum} enableFutureDates={false} isRange={true} onDateChange={onChange} isMultipane={true}>
<input type="text" class="w-min" readonly value={`${formatiertesStartDatum} - ${formatiertesEndDatum}`} on:click={toggleDatePicker} /> <input type="text" class="w-min" readonly value={`${formatiertesStartDatum} - ${formatiertesEndDatum}`} on:click={toggleDatePicker} />
</DatePicker> </DatePicker>
<p>Abrechnungsübersicht für <strong>{email}</strong></p> <p>Abrechnungsübersicht für <strong>{email}</strong></p>
@@ -75,8 +72,9 @@
{#if jahrMonat in bestellungenNachMonat && bestellungenNachMonat[jahrMonat].length > 0} {#if jahrMonat in bestellungenNachMonat && bestellungenNachMonat[jahrMonat].length > 0}
<!-- Echo dropdown foreach month. --> <!-- Echo dropdown foreach month. -->
{@const provisionMonat = bestellungenNachMonat[jahrMonat].reduce((acc, bestellung) => { {@const provisionMonat = bestellungenNachMonat[jahrMonat].reduce((acc, bestellung) => {
return acc + (provisionen.find((p) => p.ausweisart === bestellung.ausweis.ausweisart)?.provision_betrag || 0); const { provision_prozent, provision_betrag } = getProvision(bestellung.ausweis.ausweisart, bestellung.ausweis.ausweistyp, provisionen);
}, 0) * 1.19} return acc + provision_betrag;
}, 0)}
<details class="group" open> <details class="group" open>
<summary class="flex justify-between items-center cursor-pointer p-4 bg-gray-100 hover:bg-gray-200"> <summary class="flex justify-between items-center cursor-pointer p-4 bg-gray-100 hover:bg-gray-200">
@@ -102,11 +100,11 @@
</thead> </thead>
<tbody class="text-sm"> <tbody class="text-sm">
{#each bestellungenNachMonat[jahrMonat] as bestellung} {#each bestellungenNachMonat[jahrMonat] as bestellung}
{@const provisionBestellung = provisionen.find((p) => p.ausweisart === bestellung.ausweis.ausweisart)} {@const provisionBestellung = getProvision(bestellung.ausweis.ausweisart, bestellung.ausweis.ausweistyp, provisionen)}
<tr class="border-b border-gray-300 hover:bg-gray-100"> <tr class="border-b border-gray-300 hover:bg-gray-100">
<td class="text-center py-2 px-4 w-24" style="font-family: monospace;">{bestellung.ausweis.id}</td> <td class="text-center py-2 px-4 w-24" style="font-family: monospace;">{bestellung.ausweis.id}</td>
<td class="text-center py-2 font-bold w-32">{moment(bestellung.created_at).format("DD.MM.YYYY HH:mm")}</td> <td class="text-center py-2 font-bold w-32">{moment(bestellung.created_at).format("DD.MM.YYYY HH:mm")}</td>
<td class="text-center py-2 w-32">{bestellung.ausweis.ausweisart}</td> <td class="text-center py-2 w-32">{bestellung.ausweis.ausweisart} {bestellung.ausweis.ausweistyp}</td>
<td class="text-center py-2 w-32">{provisionBestellung?.provision_prozent || 0} %</td> <td class="text-center py-2 w-32">{provisionBestellung?.provision_prozent || 0} %</td>
<td class="text-right py-2 w-24" style="font-family: monospace;">{provisionBestellung?.provision_betrag.toFixed(2)}</td> <td class="text-right py-2 w-24" style="font-family: monospace;">{provisionBestellung?.provision_betrag.toFixed(2)}</td>
</tr> </tr>

View File

@@ -1,9 +1,10 @@
import * as z from "zod" import * as z from "zod"
import { Ausweisart } from "@prisma/client" import { Ausweisart, AusweisTyp } from "@prisma/client"
export const ProvisionenSchema = z.object({ export const ProvisionenSchema = z.object({
id: z.number().int(), id: z.number().int(),
ausweisart: z.nativeEnum(Ausweisart), ausweisart: z.nativeEnum(Ausweisart),
ausweistyp: z.nativeEnum(AusweisTyp),
provision_prozent: z.number(), provision_prozent: z.number(),
provision_betrag: z.number(), provision_betrag: z.number(),
benutzer_id: z.string().nullish(), benutzer_id: z.string().nullish(),

14
src/lib/provision.ts Normal file
View File

@@ -0,0 +1,14 @@
import { Enums, Provisionen } from "./client/prisma.js";
export function getProvision(ausweisart: Enums.Ausweisart, ausweistyp: Enums.AusweisTyp, provisionen: Provisionen[]): { provision_prozent: number, provision_betrag: number } {
const provision = provisionen.find(p => p.ausweisart === ausweisart && p.ausweistyp === ausweistyp);
return {
provision_prozent: provision?.provision_prozent || 0,
provision_betrag: provision?.provision_betrag || 0
};
}
export function getProductName(ausweisart: Enums.Ausweisart, ausweistyp: Enums.AusweisTyp): string {
return `${Enums.Ausweisart[ausweisart]} ${Enums.AusweisTyp[ausweistyp]}`;
}

View File

@@ -181,7 +181,7 @@ export function extrahiereAusweisAusFeldMitMehrerenAusweisen<T>(
verbrauchsausweis_wohnen, verbrauchsausweis_wohnen,
verbrauchsausweis_gewerbe, verbrauchsausweis_gewerbe,
...rest ...rest
} = row; } = row;
return { return {
...rest, ...rest,
ausweis: { ausweis: {
@@ -193,6 +193,11 @@ export function extrahiereAusweisAusFeldMitMehrerenAusweisen<T>(
: verbrauchsausweis_wohnen : verbrauchsausweis_wohnen
? Enums.Ausweisart.VerbrauchsausweisWohnen ? Enums.Ausweisart.VerbrauchsausweisWohnen
: Enums.Ausweisart.VerbrauchsausweisGewerbe, : Enums.Ausweisart.VerbrauchsausweisGewerbe,
ausweistyp: bedarfsausweis_wohnen
? bedarfsausweis_wohnen.ausweistyp
: verbrauchsausweis_wohnen
? verbrauchsausweis_wohnen.ausweistyp
: verbrauchsausweis_gewerbe?.ausweistyp || Enums.AusweisTyp.Standard,
}, },
} as { } as {
ausweis: ( ausweis: (

View File

@@ -1,10 +1,14 @@
--- ---
import AbrechnungTable from "#components/Abrechnung/AbrechnungTable.svelte"; import AbrechnungTable from "#components/Abrechnung/AbrechnungTable.svelte";
import BlankLayout from "#layouts/BlankLayout.astro"; import BlankLayout from "#layouts/BlankLayout.astro";
import { getProvision } from "#lib/provision";
import { extrahiereAusweisAusFeldMitMehrerenAusweisen } from "#lib/server/ausweis"; import { extrahiereAusweisAusFeldMitMehrerenAusweisen } from "#lib/server/ausweis";
import { Enums, prisma } from "#lib/server/prisma"; import { Enums, prisma } from "#lib/server/prisma";
import { getCurrentUser } from "#lib/server/user"; import { getCurrentUser } from "#lib/server/user";
import moment from "moment"; import moment from "moment-timezone";
moment.locale("de");
moment.tz.setDefault("Europe/Berlin");
const start = moment(Astro.url.searchParams.get("start")); const start = moment(Astro.url.searchParams.get("start"));
const end = moment(Astro.url.searchParams.get("end")); const end = moment(Astro.url.searchParams.get("end"));
@@ -12,6 +16,12 @@ const end = moment(Astro.url.searchParams.get("end"));
let startdatum = start.isValid() ? start.toDate() : moment().startOf("month").toDate(); let startdatum = start.isValid() ? start.toDate() : moment().startOf("month").toDate();
let enddatum = end.isValid() ? end.toDate() : moment().endOf("month").toDate(); let enddatum = end.isValid() ? end.toDate() : moment().endOf("month").toDate();
// Wir dürfen die Abrechnung erst ab Juni starten lassen.
if (startdatum < moment().set("year", 2025).set("month", 5).set("date", 1).toDate()) {
startdatum = moment().set("year", 2025).set("month", 5).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0).toDate();
enddatum = moment().set("year", 2025).set("month", 5).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0).endOf("month").toDate();
}
const benutzer = await getCurrentUser(Astro); const benutzer = await getCurrentUser(Astro);
if (!benutzer) { if (!benutzer) {
@@ -44,19 +54,19 @@ if (start.isValid() && end.isValid()) {
], ],
AND: [ AND: [
{ {
created_at: { erstellt_am: {
gte: startdatum, gte: startdatum,
}, },
}, },
{ {
created_at: { erstellt_am: {
lte: enddatum, lte: enddatum,
}, },
}, },
], ],
}, },
orderBy: { orderBy: {
created_at: "desc", erstellt_am: "desc",
}, },
include: { include: {
bedarfsausweis_wohnen: { bedarfsausweis_wohnen: {
@@ -111,7 +121,7 @@ if (start.isValid() && end.isValid()) {
], ],
}, },
orderBy: { orderBy: {
created_at: "desc", erstellt_am: "desc",
}, },
include: { include: {
bedarfsausweis_wohnen: { bedarfsausweis_wohnen: {
@@ -150,7 +160,7 @@ if (!startdatum) {
startdatum = ( startdatum = (
await prisma.rechnung.findFirst({ await prisma.rechnung.findFirst({
select: { select: {
created_at: true, erstellt_am: true,
}, },
where: { where: {
partner_code: benutzer.partner_code, partner_code: benutzer.partner_code,
@@ -171,15 +181,15 @@ if (!startdatum) {
}, },
}, },
], ],
created_at: { erstellt_am: {
gte: moment().set("year", 2020).set("dayOfYear", 1).toDate(), gte: moment().set("year", 2020).set("dayOfYear", 1).toDate(),
}, },
}, },
orderBy: { orderBy: {
created_at: "asc", erstellt_am: "asc",
}, },
}) })
)?.created_at || moment().startOf("month").toDate(); )?.erstellt_am || moment().startOf("month").toDate();
} }
@@ -189,29 +199,20 @@ const provisionen = await prisma.provisionen.findMany({
} }
}) })
bestellungen = bestellungen.map((bestellung) =>
extrahiereAusweisAusFeldMitMehrerenAusweisen(bestellung)
);
let provision = 0; let provision = 0;
const ausweisarten: string[] = [];
for (const bestellung of bestellungen) { for (const bestellung of bestellungen) {
if (bestellung.verbrauchsausweis_wohnen) { const { provision_betrag, provision_prozent } = getProvision(bestellung.ausweis.ausweisart, bestellung.ausweis.ausweistyp, provisionen);
ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisWohnen); provision += provision_betrag;
provision += provisionen.find((p) => p.ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen)?.provision_betrag || 0;
}
if (bestellung.bedarfsausweis_wohnen) {
ausweisarten.push(Enums.Ausweisart.BedarfsausweisWohnen);
provision += provisionen.find((p) => p.ausweisart === Enums.Ausweisart.BedarfsausweisWohnen)?.provision_betrag || 0;
}
if (bestellung.verbrauchsausweis_gewerbe) {
ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisGewerbe);
provision += provisionen.find((p) => p.ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe)?.provision_betrag || 0;
}
} }
--- ---
<BlankLayout title="Monatliche Abrechnung"> <BlankLayout title="Monatliche Abrechnung">
<AbrechnungTable <AbrechnungTable
bestellungen={bestellungen.map((bestellung) => bestellungen={bestellungen}
extrahiereAusweisAusFeldMitMehrerenAusweisen(bestellung)
)}
{provisionen} {provisionen}
startdatum={startdatum} startdatum={startdatum}
enddatum={enddatum} enddatum={enddatum}

View File

@@ -6,10 +6,18 @@ import moment from "moment";
import { getCurrentUser } from "#lib/server/user"; import { getCurrentUser } from "#lib/server/user";
import { prisma } from "#lib/server/prisma"; import { prisma } from "#lib/server/prisma";
import { extrahiereAusweisAusFeldMitMehrerenAusweisen } from "#lib/server/ausweis"; import { extrahiereAusweisAusFeldMitMehrerenAusweisen } from "#lib/server/ausweis";
import { getProvision } from "#lib/provision";
moment.locale("de");
moment.tz.setDefault("Europe/Berlin");
const datum = moment(Astro.url.searchParams.get("d")).set("date", 1).set("hour", 0).set("minute", 0).set("second", 0);
const datum = moment(Astro.url.searchParams.get("d"));
const benutzer = await getCurrentUser(Astro); const benutzer = await getCurrentUser(Astro);
// Wir dürfen die Abrechnung erst ab Juni starten lassen.
if (datum.isBefore(moment().set("year", 2025).set("month", 4).endOf("month"))) {
return Astro.redirect("/404")
}
if (!benutzer) { if (!benutzer) {
return Astro.redirect("/404"); return Astro.redirect("/404");
} }
@@ -36,19 +44,19 @@ let bestellungen = await prisma.rechnung.findMany({
], ],
AND: [ AND: [
{ {
created_at: { erstellt_am: {
gte: datum.startOf("month").toDate(), gte: datum.startOf("month").toDate(),
}, },
}, },
{ {
created_at: { erstellt_am: {
lte: datum.endOf("month").toDate(), lte: datum.endOf("month").toDate(),
}, },
}, },
], ],
}, },
orderBy: { orderBy: {
created_at: "desc", erstellt_am: "desc",
}, },
include: { include: {
bedarfsausweis_wohnen: { bedarfsausweis_wohnen: {
@@ -89,9 +97,6 @@ const provisionen = await prisma.provisionen.findMany({
const ausweisBestellungen = bestellungen.map(bestellung => extrahiereAusweisAusFeldMitMehrerenAusweisen(bestellung)); const ausweisBestellungen = bestellungen.map(bestellung => extrahiereAusweisAusFeldMitMehrerenAusweisen(bestellung));
console.log(ausweisBestellungen);
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
headless: true, headless: true,
args: ["--no-sandbox", "--disable-setuid-sandbox"], args: ["--no-sandbox", "--disable-setuid-sandbox"],
@@ -109,28 +114,33 @@ for (let i = 0; i < remainingBlocks.length; i += 20) {
blocks.push(remainingBlocks.slice(i, i + 20)); blocks.push(remainingBlocks.slice(i, i + 20));
} }
Handlebars.registerHelper("get-provision-prozent", function (ausweisart) { Handlebars.registerHelper("get-provision-prozent", function (ausweisart, ausweistyp) {
const provisionEintrag = provisionen.find((p) => p.ausweisart === ausweisart); const { provision_prozent } = getProvision(ausweisart, ausweistyp, provisionen);
return provisionEintrag ? provisionEintrag.provision_prozent : 0; return provision_prozent || 0;
}); });
Handlebars.registerHelper("get-provision-betrag", function (ausweisart) { Handlebars.registerHelper("get-provision-betrag", function (ausweisart, ausweistyp) {
const provisionEintrag = provisionen.find((p) => p.ausweisart === ausweisart); const { provision_betrag } = getProvision(ausweisart, ausweistyp, provisionen);
return provisionEintrag ? provisionEintrag.provision_betrag.toFixed(2) : "0.00"; return provision_betrag ? provision_betrag.toFixed(2) : "0.00";
}); });
const gesamt = ausweisBestellungen.reduce((acc, bestellung) => {
const { provision_betrag } = getProvision(bestellung.ausweis.ausweisart, bestellung.ausweis.ausweistyp, provisionen);
return acc + (provision_betrag || 0);
}, 0).toFixed(2);
const template = Handlebars.compile(abrechnungTemplateHTML); const template = Handlebars.compile(abrechnungTemplateHTML);
const html = template({ monat: datum.format("MMMM YYYY"), bestellungen: blocks }); const html = template({ monat: datum.format("MMMM YYYY"), bestellungen: blocks, heute: moment().format("DD.MM.YYYY"), plz: benutzer.plz, ort: benutzer.ort, adresse: benutzer.adresse, firma: benutzer.firma, email: benutzer.email, gesamt });
await page.goto(`data:text/html;charset=UTF-8,${encodeURIComponent(html)}`, { await page.goto(`data:text/html;charset=UTF-8,${encodeURIComponent(html)}`, {
waitUntil: "networkidle0", waitUntil: "networkidle0",
}); });
const pdf = await page.pdf({ path: "abrechnung.pdf", format: "A4" }); const pdf = await page.pdf({ format: "A4" });
await browser.close(); await browser.close();
return new Response(pdf, { return new Response(pdf, {
headers: { headers: {
"Content-Type": "application/pdf", "Content-Type": "application/pdf",
"Content-Disposition": "attachment; filename=abrechnung.pdf", "Content-Disposition": `attachment; filename="Abrechnung_${datum.format("YYYY_MM")}.pdf"`,
}, },
}); });
--- ---

View File

@@ -52,6 +52,6 @@ if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
} }
if (result.length > 0) { if (result.length > 0) {
return Astro.redirect(`/dashboard/objekte/${result[0].id}?p=${page}`) return Astro.redirect(`/dashboard/objekte/${result[0].id}?p=${page}`);
} }
--- ---

View File

@@ -23,17 +23,20 @@
<p class="text-sm">IB Cornelsen · Katendeich 5A · 21035 Hamburg</p> <p class="text-sm">IB Cornelsen · Katendeich 5A · 21035 Hamburg</p>
</div> </div>
<div class="flex flex-col"> <div class="flex flex-col">
<p>Immowelt GmbH</p> <p>{{ @root.firma }}</p>
<p>Nordostpark 3-5</p> <p>{{ @root.adresse }}</p>
<p>90411 Nürnberg</p> <p>{{ @root.plz }} {{ @root.ort }}</p>
</div> </div>
</div> </div>
{{/if}} {{/if}}
<div class="flex flex-col gap-4 mt-12"> <div class="flex flex-col gap-4 mt-12">
{{#if @first}} {{#if @first}}
<div class="flex flex-row justify-between items-center"> <div class="flex flex-row justify-between items-center">
<p class="font-semibold">Erzielte Conversions {{ @root.monat }}</p> <div class="flex flex-col">
<p>Erstellt am 16.11.23</p> <p class="font-semibold">Erzielte Conversions {{ @root.monat }}</p>
<p>Erstellt am {{ @root.heute }}</p>
</div>
<p class="font-semibold">Gesamt {{ @root.gesamt }} €</p>
</div> </div>
{{/if}} {{/if}}
<table class="table border-collapse border border-black"> <table class="table border-collapse border border-black">
@@ -63,10 +66,10 @@
</td> </td>
{{#with ausweis}} {{#with ausweis}}
<td class=" border-black border p-1 text-sm text-center"> <td class=" border-black border p-1 text-sm text-center">
{{get-provision-prozent ausweisart}} % {{get-provision-prozent ausweisart ausweistyp}} %
</td> </td>
<td class=" border-black border p-1 text-sm text-center"> <td class=" border-black border p-1 text-sm text-center">
{{get-provision-betrag ausweisart}} {{get-provision-betrag ausweisart ausweistyp}}
</td> </td>
{{/with}} {{/with}}
</tr> </tr>