@@ -1,76 +0,0 @@
|
|||||||
name: Auto Merge Staging into Main
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '0 2 * * *' # 2:00 UTC = 4:00 Europäische Zeit
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
merge:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set Git user
|
|
||||||
run: |
|
|
||||||
git config user.name "github-actions[bot]"
|
|
||||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
|
|
||||||
- name: Fetch all branches
|
|
||||||
run: |
|
|
||||||
git fetch origin main
|
|
||||||
git fetch origin staging
|
|
||||||
|
|
||||||
- name: Check if main has commits not in staging
|
|
||||||
id: check
|
|
||||||
run: |
|
|
||||||
git fetch origin
|
|
||||||
if [ $(git rev-list --count origin/staging..origin/main) -gt 0 ]; then
|
|
||||||
echo "❌ Staging is behind main and requires manual merging."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create PR from staging to main
|
|
||||||
id: create_pr
|
|
||||||
run: |
|
|
||||||
PR_URL=$(gh pr create --base main --head staging --title "Auto-merge staging into main" --body "This PR was created automatically by GitHub Actions. It merges the latest \`staging\` into \`main\`.")
|
|
||||||
echo "PR_URL=$PR_URL" >> $GITHUB_OUTPUT
|
|
||||||
PR_NUMBER=$(echo $PR_URL | awk -F'/' '{print $NF}')
|
|
||||||
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Enable auto-merge on PR
|
|
||||||
if: steps.create_pr.outputs.PR_NUMBER != ''
|
|
||||||
run: |
|
|
||||||
gh pr merge ${{ steps.create_pr.outputs.PR_NUMBER }} --merge --auto
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
|
|
||||||
notify_failure:
|
|
||||||
needs: merge
|
|
||||||
if: failure()
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Send Discord notification on failure
|
|
||||||
run: |
|
|
||||||
curl -H "Content-Type: application/json" \
|
|
||||||
-X POST \
|
|
||||||
-d "{\"content\": \"🚨 Auto-Merge fehlgeschlagen! Bitte manuell prüfen: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\"}" \
|
|
||||||
${{ secrets.DISCORD_WEBHOOK_URL }}
|
|
||||||
|
|
||||||
notify_success:
|
|
||||||
needs: merge
|
|
||||||
if: success()
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Send Discord notification on success
|
|
||||||
run: |
|
|
||||||
curl -H "Content-Type: application/json" \
|
|
||||||
-X POST \
|
|
||||||
-d "{\"content\": \"✅ Auto-Merge ausgeführt! Ergebnis jetzt auf [GitHub](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) und [online-energieausweis.org](https://online-energieausweis.org) einsehen.\"}" \
|
|
||||||
${{ secrets.DISCORD_WEBHOOK_URL }}
|
|
||||||
3
Makefile
3
Makefile
@@ -30,6 +30,9 @@ run-database: stop-database
|
|||||||
docker volume create $(DB_VOLUME)
|
docker volume create $(DB_VOLUME)
|
||||||
docker build -t $(DB_CONTAINER_NAME) .
|
docker build -t $(DB_CONTAINER_NAME) .
|
||||||
docker run -d --name $(DB_CONTAINER_NAME) \
|
docker run -d --name $(DB_CONTAINER_NAME) \
|
||||||
|
--log-driver=json-file \
|
||||||
|
--log-opt max-size=50m \
|
||||||
|
--log-opt max-file=3 \
|
||||||
--restart=always \
|
--restart=always \
|
||||||
-e POSTGRES_USER=$(DB_USER) \
|
-e POSTGRES_USER=$(DB_USER) \
|
||||||
-e POSTGRES_PASSWORD=$(DB_PASSWORD) \
|
-e POSTGRES_PASSWORD=$(DB_PASSWORD) \
|
||||||
|
|||||||
4
bun.lock
4
bun.lock
@@ -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=="],
|
||||||
|
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "benutzer" ADD COLUMN "partner_code" TEXT;
|
||||||
@@ -21,6 +21,7 @@ model Benutzer {
|
|||||||
rolle BenutzerRolle @default(USER)
|
rolle BenutzerRolle @default(USER)
|
||||||
firma String?
|
firma String?
|
||||||
lex_office_id String?
|
lex_office_id String?
|
||||||
|
partner_code String?
|
||||||
|
|
||||||
verified Boolean @default(false)
|
verified Boolean @default(false)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const createCaller = createCallerFactory({
|
|||||||
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
|
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
|
||||||
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
|
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
|
||||||
"unterlage": await import("../src/pages/api/unterlage.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/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"),
|
||||||
"admin/bedarfsausweis-ausstellen": await import("../src/pages/api/admin/bedarfsausweis-ausstellen.ts"),
|
"admin/bedarfsausweis-ausstellen": await import("../src/pages/api/admin/bedarfsausweis-ausstellen.ts"),
|
||||||
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
|
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
|
||||||
@@ -12,7 +13,6 @@ 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"),
|
||||||
"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"),
|
||||||
@@ -30,18 +30,16 @@ export const createCaller = createCallerFactory({
|
|||||||
"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"),
|
"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": 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"),
|
||||||
|
"ticket": await import("../src/pages/api/ticket/index.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"),
|
"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]/bilder": await import("../src/pages/api/aufnahme/[id]/bilder.ts"),
|
||||||
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),
|
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),
|
||||||
"aufnahme/[id]/unterlagen": await import("../src/pages/api/aufnahme/[id]/unterlagen.ts"),
|
"aufnahme/[id]/unterlagen": await import("../src/pages/api/aufnahme/[id]/unterlagen.ts"),
|
||||||
"objekt/[id]": await import("../src/pages/api/objekt/[id]/index.ts"),
|
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
|
||||||
})
|
})
|
||||||
@@ -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,13 +72,15 @@
|
|||||||
{#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">
|
||||||
<span class="font-semibold">{moment(dt).format("MMMM YYYY")}</span>
|
<span class="font-semibold">{moment(dt).format("MMMM YYYY")}</span>
|
||||||
<div class="flex flex-row gap-4 items-center">
|
<div class="flex flex-row gap-4 items-center">
|
||||||
|
<a href={`/dashboard/abrechnung/monatlich.pdf?d=${moment(dt).format("YYYY-MM")}`} target="_blank" rel="noreferrer noopener">PDF generieren</a>
|
||||||
<span class="text-gray-500">{provisionMonat.toFixed(2)} €</span>
|
<span class="text-gray-500">{provisionMonat.toFixed(2)} €</span>
|
||||||
<svg class="w-4 h-4 transition-transform duration-300 group-open:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg class="w-4 h-4 transition-transform duration-300 group-open:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<polyline points="6 9 12 15 18 9"></polyline>
|
<polyline points="6 9 12 15 18 9"></polyline>
|
||||||
@@ -101,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>
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ const brennstoffe: [
|
|||||||
["Fernwärme HKW FB", "kWh", 1.0, 1.3, 0.4],
|
["Fernwärme HKW FB", "kWh", 1.0, 1.3, 0.4],
|
||||||
["Fernwärme HKW EB", "kWh", 1.0, 0.1, 0.06],
|
["Fernwärme HKW EB", "kWh", 1.0, 0.1, 0.06],
|
||||||
["Fernwärme Hamburg", "kWh", 1.0, 0.33, 0.064],
|
["Fernwärme Hamburg", "kWh", 1.0, 0.33, 0.064],
|
||||||
|
["Fernwärme Erfurt", "kWh", 1.0, 0.3, 0],
|
||||||
|
["Fernwärme Neumünster", "kWh", 1.0, 0.28, 0.0133],
|
||||||
["Erdgas", "kWh", 1.0, 1.1, 0.24],
|
["Erdgas", "kWh", 1.0, 1.1, 0.24],
|
||||||
["Heizöl", "kWh", 1.0, 1.1, 0.31],
|
["Heizöl", "kWh", 1.0, 1.1, 0.31],
|
||||||
["Heizöl", "l", 10.0, 1.1, 0.31],
|
["Heizöl", "l", 10.0, 1.1, 0.31],
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
import { dialogs } from "svelte-dialogs";
|
import { dialogs } from "svelte-dialogs";
|
||||||
import TicketPopup from "./TicketPopup.svelte";
|
import TicketPopup from "./TicketPopup.svelte";
|
||||||
import { addNotification } from "@ibcornelsen/ui";
|
import { addNotification } from "@ibcornelsen/ui";
|
||||||
|
export let userEmail: string = "";
|
||||||
|
|
||||||
async function showTicketPopup() {
|
async function showTicketPopup() {
|
||||||
const success = await dialogs.modal(TicketPopup);
|
const success = await dialogs.modal(TicketPopup, { email: userEmail });
|
||||||
|
|
||||||
console.log(success);
|
console.log(success);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { api } from "astro-typesafe-api/client";
|
import { api } from "astro-typesafe-api/client";
|
||||||
import { getClose } from "svelte-dialogs";
|
import { getClose } from "svelte-dialogs";
|
||||||
|
export let email: string = "";
|
||||||
|
|
||||||
const close = getClose();
|
const close = getClose();
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@
|
|||||||
let category = "";
|
let category = "";
|
||||||
let title = "";
|
let title = "";
|
||||||
let description = "";
|
let description = "";
|
||||||
let email = "";
|
//let email = "";
|
||||||
let telefon = "";
|
let telefon = "";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
<div class="input-standard">
|
<div class="input-standard">
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
class="file-input file-input-ghost h-[38px]"
|
class="file-input file-input-ghost h-[38px]"
|
||||||
bind:this={fileUpload}
|
bind:this={fileUpload}
|
||||||
{name}
|
{name}
|
||||||
@@ -144,6 +145,7 @@
|
|||||||
<div class="input-standard">
|
<div class="input-standard">
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
class="file-input file-input-ghost h-[38px]"
|
class="file-input file-input-ghost h-[38px]"
|
||||||
bind:this={fileUpload}
|
bind:this={fileUpload}
|
||||||
{name}
|
{name}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const BenutzerSchema = z.object({
|
|||||||
rolle: z.nativeEnum(BenutzerRolle),
|
rolle: z.nativeEnum(BenutzerRolle),
|
||||||
firma: z.string().nullish(),
|
firma: z.string().nullish(),
|
||||||
lex_office_id: z.string().nullish(),
|
lex_office_id: z.string().nullish(),
|
||||||
|
partner_code: z.string().nullish(),
|
||||||
verified: z.boolean(),
|
verified: z.boolean(),
|
||||||
created_at: z.date(),
|
created_at: z.date(),
|
||||||
updated_at: z.date(),
|
updated_at: z.date(),
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
|
|||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
<NotificationWrapper client:load />
|
<NotificationWrapper client:load />
|
||||||
<TicketButton client:load></TicketButton>
|
<TicketButton client:load userEmail={user?.email ?? ""}></TicketButton>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|||||||
14
src/lib/provision.ts
Normal file
14
src/lib/provision.ts
Normal 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]}`;
|
||||||
|
}
|
||||||
@@ -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: (
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ export const GET = defineApiRoute({
|
|||||||
})),
|
})),
|
||||||
output: z.array(BenutzerSchema),
|
output: z.array(BenutzerSchema),
|
||||||
middleware: authorizationMiddleware,
|
middleware: authorizationMiddleware,
|
||||||
async fetch(input, context, admin) {
|
async fetch(input, context, benutzer) {
|
||||||
if ("id" in input) {
|
if ("id" in input) {
|
||||||
//Only Admin can read other users
|
// Nur Admins oder der Benutzer selbst kann einen einzelnen Benutzer lesen
|
||||||
if (admin.rolle != Enums.BenutzerRolle.ADMIN && input.id != admin.id) {
|
if (benutzer.rolle != Enums.BenutzerRolle.ADMIN && input.id != benutzer.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +84,8 @@ export const GET = defineApiRoute({
|
|||||||
|
|
||||||
return [user];
|
return [user];
|
||||||
} else {
|
} else {
|
||||||
//Only admin can read many users
|
// Nur Admins können nach mehreren Benutzern suchen
|
||||||
if (admin.rolle != Enums.BenutzerRolle.ADMIN ) {
|
if (benutzer.rolle != Enums.BenutzerRolle.ADMIN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,9 +114,12 @@ export const PUT = defineApiRoute({
|
|||||||
id: IDWithPrefix
|
id: IDWithPrefix
|
||||||
}),
|
}),
|
||||||
async fetch(input) {
|
async fetch(input) {
|
||||||
|
let { email, passwort, vorname, name } = input;
|
||||||
|
email = email.toLowerCase();
|
||||||
|
|
||||||
const existingUser = await prisma.benutzer.findUnique({
|
const existingUser = await prisma.benutzer.findUnique({
|
||||||
where: {
|
where: {
|
||||||
email: input.email
|
email
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -131,10 +134,10 @@ export const PUT = defineApiRoute({
|
|||||||
|
|
||||||
const user = await prisma.benutzer.create({
|
const user = await prisma.benutzer.create({
|
||||||
data: {
|
data: {
|
||||||
email: input.email,
|
email,
|
||||||
passwort: hashPassword(input.passwort),
|
passwort: hashPassword(passwort),
|
||||||
vorname: input.vorname,
|
vorname,
|
||||||
name: input.name,
|
name,
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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) {
|
||||||
@@ -24,7 +34,7 @@ let bestellungen;
|
|||||||
if (start.isValid() && end.isValid()) {
|
if (start.isValid() && end.isValid()) {
|
||||||
bestellungen = await prisma.rechnung.findMany({
|
bestellungen = await prisma.rechnung.findMany({
|
||||||
where: {
|
where: {
|
||||||
partner_code: "immowelt",
|
partner_code: benutzer.partner_code,
|
||||||
OR: [
|
OR: [
|
||||||
{
|
{
|
||||||
verbrauchsausweis_gewerbe: {
|
verbrauchsausweis_gewerbe: {
|
||||||
@@ -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: {
|
||||||
@@ -91,7 +101,7 @@ if (start.isValid() && end.isValid()) {
|
|||||||
} else {
|
} else {
|
||||||
bestellungen = await prisma.rechnung.findMany({
|
bestellungen = await prisma.rechnung.findMany({
|
||||||
where: {
|
where: {
|
||||||
partner_code: "immowelt",
|
partner_code: benutzer.partner_code,
|
||||||
OR: [
|
OR: [
|
||||||
{
|
{
|
||||||
verbrauchsausweis_gewerbe: {
|
verbrauchsausweis_gewerbe: {
|
||||||
@@ -111,7 +121,7 @@ if (start.isValid() && end.isValid()) {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
orderBy: {
|
orderBy: {
|
||||||
created_at: "desc",
|
erstellt_am: "desc",
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
bedarfsausweis_wohnen: {
|
bedarfsausweis_wohnen: {
|
||||||
@@ -150,10 +160,10 @@ if (!startdatum) {
|
|||||||
startdatum = (
|
startdatum = (
|
||||||
await prisma.rechnung.findFirst({
|
await prisma.rechnung.findFirst({
|
||||||
select: {
|
select: {
|
||||||
created_at: true,
|
erstellt_am: true,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
partner_code: "immowelt",
|
partner_code: benutzer.partner_code,
|
||||||
OR: [
|
OR: [
|
||||||
{
|
{
|
||||||
verbrauchsausweis_gewerbe: {
|
verbrauchsausweis_gewerbe: {
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -6,17 +6,25 @@ 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");
|
||||||
}
|
}
|
||||||
|
|
||||||
let bestellungen = await prisma.rechnung.findMany({
|
let bestellungen = await prisma.rechnung.findMany({
|
||||||
where: {
|
where: {
|
||||||
partner_code: "immowelt",
|
partner_code: benutzer.partner_code,
|
||||||
OR: [
|
OR: [
|
||||||
{
|
{
|
||||||
verbrauchsausweis_gewerbe: {
|
verbrauchsausweis_gewerbe: {
|
||||||
@@ -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"`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -61,5 +61,5 @@ Astro.cookies.set(API_ACCESS_TOKEN_COOKIE_NAME, accessToken, {
|
|||||||
expires: moment().add(30, "minutes").toDate()
|
expires: moment().add(30, "minutes").toDate()
|
||||||
})
|
})
|
||||||
|
|
||||||
return Astro.redirect("/dashboard")
|
return Astro.redirect("/dashboard");
|
||||||
---
|
---
|
||||||
@@ -31,7 +31,7 @@ if ((page < 1 || page > totalPageCount) && totalPageCount > 0) {
|
|||||||
let result: { id: string; updated_at: Date }[] = [];
|
let result: { id: string; updated_at: Date }[] = [];
|
||||||
// Wir fragen den neuesten Ausweis ab
|
// Wir fragen den neuesten Ausweis ab
|
||||||
// Falls der Nutzer ein Admin ist dann kommt der ganz neueste ansonsten der neueste des eingeloggten Benutzers.
|
// Falls der Nutzer ein Admin ist dann kommt der ganz neueste ansonsten der neueste des eingeloggten Benutzers.
|
||||||
if (user.rolle !== Enums.BenutzerRolle.ADMIN || user.rolle === Enums.BenutzerRolle.RESELLER) {
|
if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
|
||||||
result =
|
result =
|
||||||
await prisma.$queryRaw`SELECT id, updated_at FROM "VerbrauchsausweisWohnen" WHERE benutzer_id = ${user.id} UNION ALL
|
await prisma.$queryRaw`SELECT id, updated_at FROM "VerbrauchsausweisWohnen" WHERE benutzer_id = ${user.id} UNION ALL
|
||||||
SELECT id, updated_at FROM "VerbrauchsausweisGewerbe" WHERE benutzer_id = ${user.id} UNION ALL
|
SELECT id, updated_at FROM "VerbrauchsausweisGewerbe" WHERE benutzer_id = ${user.id} UNION ALL
|
||||||
@@ -52,10 +52,6 @@ if (user.rolle !== Enums.BenutzerRolle.ADMIN || user.rolle === Enums.BenutzerRol
|
|||||||
}
|
}
|
||||||
|
|
||||||
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}`);
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
|
||||||
<UserLayout title="Objekte" {user} besteller={null}>
|
|
||||||
<p>Keine Ausweise konnten gefunden werden.</p>
|
|
||||||
</UserLayout>
|
|
||||||
|
|||||||
@@ -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">
|
||||||
|
<div class="flex flex-col">
|
||||||
<p class="font-semibold">Erzielte Conversions {{ @root.monat }}</p>
|
<p class="font-semibold">Erzielte Conversions {{ @root.monat }}</p>
|
||||||
<p>Erstellt am 16.11.23</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>
|
||||||
|
|||||||
Reference in New Issue
Block a user