13 Commits

Author SHA1 Message Date
Moritz Utcke
d98a5065ef Abrechnung und Workflow 2025-06-11 09:50:41 -05:00
Moritz Utcke
54d8fb5d1b no-start existiert nicht 2025-06-09 12:11:59 -03:00
Moritz Utcke
feef273c8c Disables autorestart for database backup cronjob
Prevents the daily database backup cronjob from restarting automatically.
This ensures that the backup process only runs according to the defined schedule,
avoiding unintended backups outside of the scheduled time.
2025-06-09 12:09:50 -03:00
Moritz Utcke
e48cd6acde Prozentzahl rausgenommen 2025-06-09 10:52:39 -03:00
Moritz Utcke
8791516498 Merge remote-tracking branch 'origin/dev' into dev 2025-06-09 10:43:51 -03:00
Moritz Utcke
19136d475d Makefile 2025-06-09 10:43:46 -03:00
Carl Mahnke
3983aabcb2 Merge remote-tracking branch 'origin/dev' into Dev-Carl 2025-06-03 11:07:14 +02:00
Carl Mahnke
4d6b8283ff Kundendatenmodule - Daten speichern wenn nicht eingeloggt 2025-06-03 11:06:53 +02:00
Moritz Utcke
5f5e3f4bed Heap Snapshot 2025-06-02 21:49:26 -03:00
Moritz Utcke
85591431eb Heap Snapshot 2025-06-02 21:46:30 -03:00
Moritz Utcke
4d9bae412c Merge remote-tracking branch 'origin/dev' into dev 2025-06-02 21:35:08 -03:00
Moritz Utcke
9fa8ee2251 Heap Snapshot Generator 2025-06-02 21:35:00 -03:00
UMBENOMENA
5d0ef29272 Merge pull request #539 from IBCornelsen/UMBE
GTM
2025-06-01 23:28:24 +02:00
12 changed files with 515 additions and 19 deletions

View File

@@ -13,6 +13,8 @@ jobs:
steps:
- name: Prevent dev merges
run: |
echo "${{ github.head_ref }}";
echo "${{ github.base_ref }}";
if [[ "${{ github.head_ref }}" == "dev" ]]; then
echo "ERROR: Merging 'dev' into '${{ github.base_ref }}' is forbidden!"
exit 1
@@ -21,6 +23,8 @@ jobs:
- name: Allow only staging into main
if: github.base_ref == 'main'
run: |
echo "${{ github.head_ref }}";
echo "${{ github.base_ref }}";
if [[ "${{ github.head_ref }}" != "staging" ]]; then
echo "ERROR: Only 'staging' branch is allowed to merge into 'main'. Current: '${{ github.head_ref }}'"
exit 1

View File

@@ -10,7 +10,7 @@ PERSISTENT_DIR := $(HOME)/persistent/$(APP_NAME)
BACKUP_FILENAME := $(HOME)/backups/$(shell date +"%Y-%m-%d_%H-%M-%S").sql.gz
online-energieausweis:
bun run dev --host
NODE_ENV="development" bun run dev --host
dev: database online-energieausweis
@@ -72,4 +72,4 @@ prod: install-dependencies prisma-studio backup-database-cronjob update-dwd-klim
backup-database-cronjob:
- pm2 delete daily-db-backup
pm2 start bash --name "daily-db-backup" --cron "0 0 * * *" -- backup-database.bash
pm2 start bash --name "daily-db-backup" --no-autorestart --cron "0 0 * * *" -- backup-database.bash

View File

@@ -13,10 +13,10 @@ export const createCaller = createCallerFactory({
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"),
"auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"),
"bedarfsausweis-gewerbe/[id]": await import("../src/pages/api/bedarfsausweis-gewerbe/[id].ts"),
"bedarfsausweis-gewerbe": await import("../src/pages/api/bedarfsausweis-gewerbe/index.ts"),
"bedarfsausweis-wohnen/[id]": await import("../src/pages/api/bedarfsausweis-wohnen/[id].ts"),
@@ -33,13 +33,13 @@ export const createCaller = createCallerFactory({
"ticket": await import("../src/pages/api/ticket/index.ts"),
"user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
"aufnahme/[id]/bilder": await import("../src/pages/api/aufnahme/[id]/bilder.ts"),
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id]/index.ts"),
"aufnahme/[id]/unterlagen": await import("../src/pages/api/aufnahme/[id]/unterlagen.ts"),
"webhooks/mollie": await import("../src/pages/api/webhooks/mollie.ts"),
"objekt/[id]": await import("../src/pages/api/objekt/[id]/index.ts"),
})

15
src/client/lib/lesen.ts Normal file
View File

@@ -0,0 +1,15 @@
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { Benutzer } from "#lib/client/prisma.js";
import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie";
export async function benutzerLesen(benutzerId: string): Promise<Benutzer> {
const benutzer = await api.user.GET.fetch({ id: benutzerId }
, {
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
});
return benutzer[0];
}

View File

@@ -0,0 +1,109 @@
<script lang="ts">
import { BedarfsausweisWohnen, Enums, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/server/prisma.js";
import moment from "moment";
import { format } from "sharp";
export let bestellungen: (Rechnung & {
verbrauchsausweis_wohnen: VerbrauchsausweisWohnen | null,
verbrauchsausweis_gewerbe: VerbrauchsausweisGewerbe | null,
bedarfsausweis_wohnen: BedarfsausweisWohnen | null,
})[];
export let provisionen: Record<Enums.Ausweisart, number>;
export let partnerCodeErstesMal: Date;
const bestellungenNachMonat: Record<string, (typeof bestellungen)> = {};
for (const bestellung of bestellungen) {
const monat = moment(bestellung.created_at).format("Y-m");
if (monat in bestellungenNachMonat) {
bestellungenNachMonat[monat].push(bestellung)
} else {
bestellungenNachMonat[monat] = [bestellung]
}
}
// 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(minTime?: Date): moment.Moment[] {
const min = minTime ? moment(minTime) : moment();
const start = min.clone().startOf('month');
const end = moment().add(1, 'month').startOf('month');
const monthsArray: moment.Moment[] = [];
const current = start.clone();
while (current.isBefore(end)) {
monthsArray.push(current.clone());
current.add(1, 'month');
}
return monthsArray.reverse(); // Most recent month first
}
const periods = getMonthlyPeriods(partnerCodeErstesMal)
</script>
{#each periods as dt}
{@const jahrMonat = dt.format("Y-m")}
{#if jahrMonat in bestellungenNachMonat && bestellungenNachMonat[jahrMonat].length > 0}
<!-- Echo dropdown foreach month. -->
{@const provisionMonat = bestellungenNachMonat[jahrMonat].reduce((acc, bestellung) => {
if (bestellung.verbrauchsausweis_wohnen) {
return acc + provisionen[Enums.Ausweisart.VerbrauchsausweisWohnen];
}
if (bestellung.bedarfsausweis_wohnen) {
return acc + provisionen[Enums.Ausweisart.BedarfsausweisWohnen];
}
if (bestellung.verbrauchsausweis_gewerbe) {
return acc + provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe];
}
return acc;
}) * 1.19}
<div onclick="$(this).nextUntil('.dropdown_month').filter('table').toggle(); $('#betrag_gesamt').html('Abrechnungsbetrag $month_name: <b>$provision_month €</b>')" class='dropdown_month'>
<p>$month_name $year_name - Klicke, um Tabelle anzuzeigen</p>
<a target='_blank' rel='noreferrer noopener' href='/user/abrechnung/pdf.php?month={dt.format("m")}&year={dt.format("Y")}'>PDF Ansehen</a>
</div>
<table id='QTT' style='margin-top: 0 !important; display:none;'>
<thead>
<tr>
<td style='text-align:center;'>ID</td>
<td style='text-align:center;'>DATUM</td>
<td style='width:11em;text-align:center;'>GEBÄUDEADRESSE </td>
<td style='width:11em;text-align:center;'>PLZ </td>
<td style='width:11em;text-align:center;'>ORT </td>
<td style='text-align:center;'>AUSWEIS</td>
<td style='width:5em;text-align:center;'>BETRAG NETTO</td>
</tr>
</thead>
<tbody>
{#each bestellungenNachMonat[jahrMonat] as bestellung}
{@const provisionBestellung = bestellung.verbrauchsausweis_wohnen ? provisionen[Enums.Ausweisart.VerbrauchsausweisWohnen] : bestellung.verbrauchsausweis_gewerbe ? provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe] : provisionen[Enums.Ausweisart.BedarfsausweisWohnen]}
<tr>
<td style='width:1em;text-align:center;'>{bestellung.id}</td>
<td style='width:9em;text-align:center;font-weight:bold;'>{moment(bestellung.created_at).format("Y/m/d")}</td>
<td style='width:8em;text-align:left;'>{bestellung["objekt_strasse"]}</td>
<td style='width:5em;text-align:center;'>{bestellung["objekt_plz"]}</td>
<td style='width:6em;text-align:left;'>{bestellung["objekt_ort"]}</td>
<td style='width:3em;text-align:center;'>{bestellung['ausweisart']}</td>
<td style='width:8em;text-align:right;'>{provisionBestellung}</td>
</tr>
{/each}
</table>
{/if}
{/each}
<!-- foreach ($period as $dt) {
$year_month = $dt->format("Y-m");
$month_name = $months[$dt->format("m")];
if ((new DateTime(date("m/d/Y", strtotime($EEtimestamp))))->format("d") - (new DateTime(date("m/d/Y", strtotime($SStimestamp))))->format("d") == 1) {
$Pall = $dt->format("d/m/Y") . ' bis ' . (new DateTime($today))->format("d/m/Y");
} -->
<!-- } -->

View File

@@ -341,9 +341,6 @@
<div class="w-full border rounded-lg my-2">
<div class="bg-green-600 h-4 rounded-lg" class:bg-red-600={progress == 33} class:bg-primary={progress == 66} style="width: {progress}%;"></div>
</div>
<span class="text-sm font-semibold text-base-content"
>{progress}%</span
>
</div>
{#await calculations then calculations}
<div class="flex flex-col mb-4">

View File

@@ -70,6 +70,7 @@
</div>
</div>
{/if}
<a href="/dashboard/abrechnung" class="button ">Conversions</a>
</div>
<hr class="border-gray-600" />

View File

@@ -33,6 +33,7 @@
import { endEnergieVerbrauchVerbrauchsausweis_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016_Client.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016_Client.js";
import { benutzerSpeichern } from "#client/lib/speichern.js";
import { benutzerLesen } from "#client/lib/lesen.js";
import { exclude } from "#lib/exclude.js";
export let user: Partial<BenutzerClient>;
@@ -240,7 +241,7 @@
}
}
async function speichern() {
async function speichern(authuser = null) {
loginAction = speichern;
if (!await validateAccessTokenClient()) {
loginOverlayHidden = false;
@@ -256,7 +257,11 @@
} else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
}
if (authuser) {
user = await benutzerLesen(authuser.id);
}
let resultUser: Awaited<ReturnType<typeof benutzerSpeichern>> | Awaited<ReturnType<typeof benutzerSpeichern>> | null = null;
const { passwort, ...baseUser } = impersonatedUser ?? user;
@@ -289,7 +294,7 @@
}
}
async function bestellen() {
async function bestellen(authuser = null) {
if (!form.checkValidity()) {
addNotification({
dismissable: true,
@@ -332,6 +337,10 @@
}
}
if (authuser) {
user = await benutzerLesen(authuser.id);
}
let resultUser: Awaited<ReturnType<typeof benutzerSpeichern>> | Awaited<ReturnType<typeof benutzerSpeichern>> | null = null;
const { passwort, ...baseUser } = impersonatedUser ?? user;
@@ -1104,7 +1113,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
<button class="order-2 button" type="button" on:click={speichern}>Speichern</button>
<button class="order-2 button" type="button" on:click={() => speichern()}>Speichern</button>
{#if rechnung && rechnung.status === "paid"}
<!-- Von einer GEG Anfrage sollte man sowieso nicht noch mal auf die Kundendaten Seite gelangen, also brauchen wir das hier nicht. -->
@@ -1112,7 +1121,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
class="order-1 sm:order-2 button cursor-pointer"
data-cy="bestellen"
type="button"
on:click={bestellen}>Absenden</button
on:click={() => bestellen()}>Absenden</button
>
{:else}
{#if gegAnfrage}
@@ -1127,7 +1136,7 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
class="order-1 sm:order-2 button cursor-pointer"
data-cy="bestellen"
type="button"
on:click={bestellen}>Kostenpflichtig bestellen</button
on:click={() => bestellen()}>Kostenpflichtig bestellen</button
>
{/if}
{/if}

View File

@@ -17,7 +17,6 @@ import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "astro:content";
import { transport } from "#lib/mail.js";
import {Attachment} from "nodemailer/lib/mailer/index.js";
import { BASE_URI } from "#lib/constants.js";
import { getAnsichtsausweis, getDatenblatt, getAushang } from "#lib/server/ausweis.js";
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { s3Client } from "#lib/s3.js";
@@ -34,7 +33,6 @@ import {
getVerbrauchsausweisWohnenKomplett,
} from "#lib/server/db.js";
import { PDFDocument } from "pdf-lib";
import * as fs from 'fs';
export const GET = defineApiRoute({
input: z.object({

View File

@@ -38,7 +38,7 @@ export const POST = defineApiRoute({
if (input.telefon) updateData.telefon = input.telefon;
if (input.verified) updateData.telefon = input.verified;
//Admin may update other users
//Only Admin can update other users
if (user.rolle == Enums.BenutzerRolle.ADMIN && input.id != user.id) {
updateData.id = input.id;
} else if(user.rolle != Enums.BenutzerRolle.ADMIN && input.id != user.id){
@@ -64,9 +64,14 @@ export const GET = defineApiRoute({
email: z.string()
})),
output: z.array(BenutzerSchema),
middleware: adminMiddleware,
middleware: authorizationMiddleware,
async fetch(input, context, admin) {
if ("id" in input) {
//Only Admin can read other users
if (admin.rolle != Enums.BenutzerRolle.ADMIN && input.id != admin.id) {
return;
}
const user = await prisma.benutzer.findUnique({
where: {
id: input.id
@@ -79,6 +84,11 @@ export const GET = defineApiRoute({
return [user];
} else {
//Only admin can read many users
if (admin.rolle != Enums.BenutzerRolle.ADMIN ) {
return;
}
const users = await prisma.benutzer.findMany({
where: {
email: {

View File

@@ -0,0 +1,334 @@
---
import AbrechungTable from "#components/Abrechnung/AbrechungTable.svelte";
import { Enums, prisma } from "#lib/server/prisma";
import { getCurrentUser } from "#lib/server/user";
import moment from "moment";
const start = moment(Astro.url.searchParams.get("start"))
const end = moment(Astro.url.searchParams.get("end"))
let startdatum = start.toDate();
let enddatum = end.toDate();
const benutzer = await getCurrentUser(Astro)
if (!benutzer) {
return Astro.redirect("/404")
}
const provisionen={
[Enums.Ausweisart.VerbrauchsausweisWohnen]: 10,
[Enums.Ausweisart.BedarfsausweisWohnen]: 10,
[Enums.Ausweisart.VerbrauchsausweisGewerbe]: 10,
}
// $kommission = db()->one("SELECT abr_va, abr_ba, abr_vanw FROM users WHERE resellercode = :resellercode", ["resellercode" => $resellercode]);
// Select every entry from database where user was involved.
let bestellungen;
if (start.isValid() && end.isValid()) {
bestellungen = await prisma.rechnung.findMany({
where: {
partner_code: "immowelt",
OR: [{
verbrauchsausweis_gewerbe: {
ausgestellt: true
}
},
{
bedarfsausweis_wohnen: {
ausgestellt: true
}
},
{
verbrauchsausweis_wohnen: {
ausgestellt: true
}
}],
AND: [{
created_at: {
gte: startdatum
},
}, {
created_at: {
lte: enddatum
},
}]
},
orderBy: {
created_at: "desc"
},
include: {
bedarfsausweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
verbrauchsausweis_wohnen: true
}
});
} else {
bestellungen = await prisma.rechnung.findMany({
where: {
partner_code: "immowelt",
OR: [{
verbrauchsausweis_gewerbe: {
ausgestellt: true
}
},
{
bedarfsausweis_wohnen: {
ausgestellt: true
}
},
{
verbrauchsausweis_wohnen: {
ausgestellt: true
}
}]
},
orderBy: {
created_at: "desc"
},
include: {
bedarfsausweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
verbrauchsausweis_wohnen: true
}
});
}
// Wann wurde der partner_code zum ersten mal benutzt?
const partnerCodeErstesMal = (await prisma.rechnung.findFirst({
select: {
created_at: true
},
where: {
partner_code: "immowelt",
OR: [{
verbrauchsausweis_gewerbe: {
ausgestellt: true
}
},
{
bedarfsausweis_wohnen: {
ausgestellt: true
}
},
{
verbrauchsausweis_wohnen: {
ausgestellt: true
}
}],
created_at: {
gte: moment().set("year", 2020).set("dayOfYear", 1).toDate()
}
},
orderBy: {
created_at: "asc"
}
}))?.created_at
let provision = 0;
const ausweisarten: string[] = [];
for (const bestellung of bestellungen) {
if (bestellung.verbrauchsausweis_wohnen) {
ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisWohnen)
provision += provisionen[Enums.Ausweisart.VerbrauchsausweisWohnen]
}
if (bestellung.bedarfsausweis_wohnen) {
ausweisarten.push(Enums.Ausweisart.BedarfsausweisWohnen)
provision += provisionen[Enums.Ausweisart.BedarfsausweisWohnen]
}
if (bestellung.verbrauchsausweis_gewerbe) {
ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisGewerbe)
provision += provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe]
}
}
---
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Reporting | online-energieausweis.org</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<link rel="stylesheet" href="./main.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</head>
<style>
body {
font-family: arial;
}
#inputwrap {
position: fixed;
top: 0;
left: 10%;
width: 70%;
padding-top: 10px;
padding-bottom: 10px;
background: #fff;
}
#cal {
margin-right: 10px !important;
}
#demo {
width: 76%;
display: inline-block;
}
table tr,
td {
border: 0.1em solid #000;
padding: 0;
margin: 0;
}
#QTT {
border-collapse: collapse;
width: 70%;
margin-top: 8em;
margin-left: 10%;
table-layout: auto;
}
#QTT thead td {
background: #ff7d26;
font-weight: bold;
}
#QTT tr:nth-child(even) {
background-color: #f2f2f2;
}
#QTT td {
padding: 0.4em 0.4em 0.4em 0.4em;
text-align: right;
}
#logo1 {
display: inline-block;
margin-right: 1em;
margin-top: -3px;
}
#logo2 {
width: 18%;
margin-bottom: 0.5em;
float: right;
padding-top: -1px;
margin-right: -5px;
}
</style>
<div id='inputwrap' class='form-group' >
<div style='display:flex; justify-content: space-between; align-items:center;'>
<img id='logo1' src='https://widget.ib-cornelsen.de/OEA_WIDGETS/img/IBC-logo.png' alt='IBCornelsen' />
<h5 style='margin-top: 10px;'><b>Erziehlte Conversions von {benutzer.email}</b></h5>
</div>
<input type='text' id='demo' class='form-control' name='demo' value='' placeholder='Bitte Zeitraum auswählen' />
</div>
<AbrechungTable bestellungen={bestellungen} {provisionen} {partnerCodeErstesMal}></AbrechungTable>
<div id="total" class="footer">
<div class="inner">
<div>
<p id="betrag_gesamt">Abrechnungsbetrag gesamt: <b>{provision} €</b></p>
</div>
<a target='_blank' rel='noreferrer noopener' href=`/user/abrechnung/pdf.php?month=${moment().subtract(1, "month").get("month")}&year=${moment().subtract(1, "month").get("year")}`>PDF für letzten Monat generieren.</a>
</div>
</div>
<script type="text/javascript">
$('#demo').daterangepicker({
"showDropdowns": true,
"minYear": 2019,
ranges: {
'Heute': [moment(), moment()],
'Gestern': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'letzte 7 Tage': [moment().subtract(6, 'days'), moment()],
'letzte 30 Tage': [moment().subtract(29, 'days'), moment()],
'dieser Monat': [moment().startOf('month'), moment().endOf('month')],
'letzter Monat': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
},
"locale": {
"format": "DD/MM/YYYY",
"separator": " - ",
"applyLabel": "Übernehmen",
"cancelLabel": "Abrechen",
"fromLabel": "Von",
"toLabel": "Bis",
"customRangeLabel": "Benutzerdefiniert",
"weekLabel": "W",
"daysOfWeek": [
"So",
"Mo",
"Di",
"Mi",
"Do",
"Fr",
"Sa"
],
"monthNames": [
"Januar",
"Februar",
"März",
"April",
"Mai",
"Juni",
"Juli",
"August",
"September",
"Oktober",
"November",
"Dezember"
],
"firstDay": 1
},
"autoUpdateInput": false,
"alwaysShowCalendars": true,
"startDate": "<?php echo $day_start_display; ?>",
"endDate": "<?php echo $day_end_display; ?>",
"minDate": "01/10/2019"
}, function(start, end, label) {
var Pstart = start.format('MM/DD/YYYY');
var Pend = end.format('MM/DD/YYYY');
$("#start").val(Pstart);
$("#end").val(Pend);
$('#FO').submit();
});
// $("#demo").val(`Conversions im Zeitraum: <?php echo $Pall; ?>`);
</script>
<body>
<form id='FO' method='GET' action='index.php'>
<input type="hidden" id="start" name="start" value='' />
<input type="hidden" id="end" name="end" value='' />
</form>
<script>
</script>
</body>
</html>

View File

@@ -0,0 +1,19 @@
---
import { getHeapSnapshot } from "v8";
import * as fs from "fs";
// Create a named heap snapshot
const snapshotStream = getHeapSnapshot();
const fileName = `heap-${Date.now()}.heapsnapshot`;
const fileStream = fs.createWriteStream(fileName);
snapshotStream.pipe(fileStream);
fileStream.on("finish", () => {
console.log(`Heap snapshot saved to ${fileName}`);
});
fileStream.on("error", (err) => {
console.error("Error writing heap snapshot:", err);
});
---