1. Info Box direkt beim Login anzeigen anstatt kleine Box unten in der Ecke 2. Pflichtfelder bei Schritt 2 noch nicht in rot markiert
443 lines
10 KiB
TypeScript
443 lines
10 KiB
TypeScript
import { getAusweisartFromId } from "#components/Ausweis/types.js";
|
|
import { adminMiddleware } from "#lib/middleware/authorization.js";
|
|
import {
|
|
Aufnahme,
|
|
BedarfsausweisWohnen,
|
|
Benutzer,
|
|
Bild,
|
|
Enums,
|
|
Objekt,
|
|
prisma,
|
|
Rechnung,
|
|
VerbrauchsausweisGewerbe,
|
|
VerbrauchsausweisWohnen,
|
|
} from "#lib/server/prisma.js";
|
|
import { join } from "path";
|
|
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 { getAnsichtsausweis, getDatenblatt, getAushang } from "#lib/server/ausweis.js";
|
|
import { PutObjectCommand } from "@aws-sdk/client-s3";
|
|
import { s3Client } from "#lib/s3.js";
|
|
import {
|
|
createInvoice,
|
|
getLexOfficeRechnung,
|
|
getLexOfficeVoucherNumber,
|
|
} from "#lib/server/invoice.js";
|
|
import { tryCatch } from "#lib/tryCatch.js";
|
|
import SFTPClient from "ssh2-sftp-client";
|
|
import {
|
|
getBedarfsausweisWohnenKomplett,
|
|
getVerbrauchsausweisGewerbeKomplett,
|
|
getVerbrauchsausweisWohnenKomplett,
|
|
} from "#lib/server/db.js";
|
|
import { PDFDocument } from "pdf-lib";
|
|
|
|
export const GET = defineApiRoute({
|
|
input: z.object({
|
|
id_ausweis: z.string(),
|
|
post: z
|
|
.boolean()
|
|
.describe("Ob der Ausweis auch per Post ausgestellt werden soll.")
|
|
.optional()
|
|
.default(false),
|
|
}),
|
|
output: z.void(),
|
|
middleware: adminMiddleware,
|
|
async fetch({ id_ausweis, post }, context) {
|
|
const ausweisart = getAusweisartFromId(id_ausweis);
|
|
|
|
let ausweis:
|
|
| ((
|
|
| VerbrauchsausweisGewerbe
|
|
| VerbrauchsausweisWohnen
|
|
| BedarfsausweisWohnen
|
|
) & {
|
|
aufnahme: Aufnahme & {
|
|
bilder: Bild[];
|
|
objekt: Objekt & {
|
|
benutzer: Benutzer | null;
|
|
};
|
|
};
|
|
rechnung: Rechnung;
|
|
})
|
|
| null = null;
|
|
|
|
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
|
|
ausweis = await getVerbrauchsausweisWohnenKomplett(id_ausweis);
|
|
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
|
|
ausweis = await getVerbrauchsausweisGewerbeKomplett(id_ausweis);
|
|
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
|
|
ausweis = await getBedarfsausweisWohnenKomplett(id_ausweis);
|
|
}
|
|
|
|
if (!ausweis) {
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message: "Ausweis existiert nicht.",
|
|
});
|
|
}
|
|
|
|
const rechnung = await prisma.rechnung.findFirst({
|
|
where: {
|
|
OR: [
|
|
{ bedarfsausweis_wohnen: { id: id_ausweis } },
|
|
{ verbrauchsausweis_wohnen: { id: id_ausweis } },
|
|
{ verbrauchsausweis_gewerbe: { id: id_ausweis } },
|
|
],
|
|
},
|
|
orderBy: {
|
|
erstellt_am: "desc",
|
|
},
|
|
include: {
|
|
benutzer: true,
|
|
},
|
|
});
|
|
|
|
if (!rechnung) {
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message:
|
|
"Die Rechnung wurde noch nicht erstellt, wir können nicht fortfahren.",
|
|
});
|
|
}
|
|
|
|
let voucherNumber: string = "";
|
|
if (!rechnung.lex_office_id) {
|
|
const [result, error] = await tryCatch(
|
|
createInvoice(ausweis, rechnung)
|
|
);
|
|
|
|
if (error) {
|
|
throw new APIError({
|
|
code: "BAD_REQUEST",
|
|
message:
|
|
"Die Rechnung konnte bei LexOffice nicht angelegt werden..",
|
|
cause: error,
|
|
});
|
|
}
|
|
|
|
const { id, voucherNumber: lexOfficeVoucherNumber } = result;
|
|
|
|
voucherNumber = lexOfficeVoucherNumber;
|
|
|
|
await prisma.rechnung.update({
|
|
where: {
|
|
id: rechnung.id,
|
|
},
|
|
data: {
|
|
lex_office_id: id,
|
|
},
|
|
});
|
|
} else {
|
|
voucherNumber = await getLexOfficeVoucherNumber(rechnung);
|
|
}
|
|
|
|
const pdfAusweis = await getAnsichtsausweis(
|
|
ausweis,
|
|
ausweis.aufnahme,
|
|
ausweis.aufnahme.objekt,
|
|
ausweis.aufnahme.bilder,
|
|
ausweis.aufnahme.objekt.benutzer,
|
|
false
|
|
);
|
|
const pdfDatenblatt = await getDatenblatt(
|
|
ausweis,
|
|
ausweis.aufnahme,
|
|
ausweis.aufnahme.objekt,
|
|
ausweis.aufnahme.bilder,
|
|
ausweis.aufnahme.objekt.benutzer,
|
|
ausweis.rechnung
|
|
);
|
|
|
|
const pdfAushang = await getAushang(
|
|
ausweis,
|
|
ausweis.aufnahme,
|
|
ausweis.aufnahme.objekt,
|
|
ausweis.aufnahme.bilder,
|
|
ausweis.aufnahme.objekt.benutzer,
|
|
false,
|
|
ausweis.rechnung
|
|
);
|
|
|
|
// TODO: Das ist immer noch scheiße, LexOffice ist doof
|
|
// Hier müssen wir warten, damit wir sichergehen können, dass die Rechnung bei LexOffice existiert.
|
|
setTimeout(async () => {
|
|
const [pdfRechnung, pdfRechnungError] = await tryCatch(
|
|
getLexOfficeRechnung(rechnung)
|
|
);
|
|
|
|
if (pdfRechnungError) {
|
|
throw new APIError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Rechnungs PDF konnte nicht generiert werden.",
|
|
});
|
|
}
|
|
|
|
if (!pdfAusweis) {
|
|
throw new APIError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Ausweis PDF konnte nicht generiert werden.",
|
|
});
|
|
}
|
|
|
|
if (!pdfDatenblatt) {
|
|
throw new APIError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message: "Datenblatt PDF konnte nicht generiert werden.",
|
|
});
|
|
}
|
|
|
|
const ausweisCommand = new PutObjectCommand({
|
|
Bucket: "ibc-pdfs",
|
|
Key: `ID_${ausweis.id}_Energieausweis.pdf`,
|
|
Body: pdfAusweis,
|
|
ACL: "private",
|
|
});
|
|
|
|
await s3Client.send(ausweisCommand);
|
|
|
|
const datenblattCommand = new PutObjectCommand({
|
|
Bucket: "ibc-pdfs",
|
|
Key: `ID_${ausweis.id}_Datenblatt.pdf`,
|
|
Body: pdfDatenblatt,
|
|
ACL: "private",
|
|
});
|
|
|
|
await s3Client.send(datenblattCommand);
|
|
|
|
const rechnungsCommand = new PutObjectCommand({
|
|
Bucket: "ibc-pdfs",
|
|
Key: `ID_${ausweis.id}_Rechnung.pdf`,
|
|
Body: Buffer.from(pdfRechnung),
|
|
ACL: "private",
|
|
});
|
|
|
|
await s3Client.send(rechnungsCommand);
|
|
|
|
if (pdfAushang){
|
|
const aushangCommand = new PutObjectCommand({
|
|
Bucket: "ibc-pdfs",
|
|
Key: `ID_${ausweis.id}_Aushang.pdf`,
|
|
Body: pdfDatenblatt,
|
|
ACL: "private",
|
|
});
|
|
|
|
await s3Client.send(rechnungsCommand);
|
|
}
|
|
|
|
// Falls Postversand angefragt wurde müssen wir die Dateien auf den Postserver hochladen
|
|
if (post) {
|
|
const dateiNameDruck = `1011000000000-AW_ID_${ausweis.id}.pdf`;
|
|
|
|
const outputPdf = await PDFDocument.create();
|
|
|
|
async function appendPdf(buffer: Uint8Array<ArrayBufferLike>) {
|
|
const doc = await PDFDocument.load(buffer);
|
|
const copiedPages = await outputPdf.copyPages(
|
|
doc,
|
|
doc.getPageIndices()
|
|
);
|
|
for (const page of copiedPages) {
|
|
outputPdf.addPage(page);
|
|
}
|
|
}
|
|
|
|
await appendPdf(pdfDatenblatt);
|
|
await appendPdf(pdfAusweis);
|
|
|
|
|
|
if (pdfAushang){
|
|
await appendPdf(pdfAushang);
|
|
}
|
|
|
|
|
|
const pdfBytes = await outputPdf.save();
|
|
|
|
const pdfCommand = new PutObjectCommand({
|
|
Bucket: "ibc-pdfs",
|
|
Key: dateiNameDruck,
|
|
Body: pdfBytes,
|
|
ACL: "private",
|
|
});
|
|
|
|
await s3Client.send(pdfCommand);
|
|
|
|
const sftp = new SFTPClient();
|
|
|
|
try {
|
|
await sftp.connect({
|
|
host: "api.ppost.de",
|
|
username: "jens.cornelsen@ib-cornelsen.de",
|
|
password: "ANTQesWYjd",
|
|
});
|
|
|
|
const cwd = await sftp.cwd();
|
|
await sftp.put(
|
|
Buffer.from(pdfBytes),
|
|
join(cwd, "upload/api", dateiNameDruck)
|
|
);
|
|
} catch (err) {
|
|
console.error("SFTP Upload failed:", err);
|
|
throw new APIError({
|
|
code: "INTERNAL_SERVER_ERROR",
|
|
message:
|
|
"Login zum Postversand Server war nicht erfolgreich.",
|
|
});
|
|
} finally {
|
|
sftp.end();
|
|
}
|
|
}
|
|
|
|
let html: string;
|
|
|
|
if (rechnung.status === Enums.Rechnungsstatus.paid) {
|
|
html = `
|
|
<p>Sehr geehrte/r ${rechnung.empfaenger},</p>
|
|
|
|
<p>im Anhang finden Sie Ihren geprüften Energieusweis inkl. Rechnung als PDF-Datei. ${
|
|
post ? "Zusätzlich haben wir Ihren Ausweis per Post verschickt" : ""
|
|
} Den Rechnungsbetrag haben Sie bereits bezahlt. Vielen Dank.</p>
|
|
|
|
<p>
|
|
Mit freundlichen Grüßen,
|
|
<br>
|
|
Dipl.-Ing. Jens Cornelsen
|
|
<br>
|
|
<br>
|
|
|
|
<strong>IB Cornelsen</strong>
|
|
<br>
|
|
Katendeich 5A
|
|
<br>
|
|
21035 Hamburg
|
|
<br>
|
|
www.online-energieausweis.org
|
|
<br>
|
|
<br>
|
|
|
|
fon 040 · 209339850
|
|
<br>
|
|
fax 040 · 209339859
|
|
</p>`;
|
|
} else {
|
|
html = `
|
|
<p>Sehr geehrte/r ${rechnung.empfaenger},</p>
|
|
|
|
<p>im Anhang finden Sie Ihren geprüften Energieusweis inkl. Rechnung als PDF-Datei. ${
|
|
post ? "Zusätzlich haben wir Ihren Ausweis per Post verschickt" : ""
|
|
} <b>Bitte beachten Sie unsere neue Bankverbindung.</b> Bitte geben Sie als Verwendungszweck die Rechnungsnummer an (siehe unten). Vielen Dank.</p>
|
|
|
|
<br>
|
|
<table>
|
|
<tr><td>Kreditinstitut</td><td>:</td><td>\t Volksbank eG</td>
|
|
<tr><td>Empfänger</td><td>:</td><td>\t IB Cornelsen</td>
|
|
<tr><td>IBAN</td><td>:<td>\t DE13 2519 3331 7209 0731 00</td>
|
|
<tr><td>BIC</td><td>:</td><td>\t GENODEF1PAT</td>
|
|
<tr><td>Betrag</td><td>:</td><td>\t <b>${rechnung.betrag}€</b></td>
|
|
<tr><td>Verwendungszweck</td><td>:</td><td>\t <b>${voucherNumber}</b></td>
|
|
</table>
|
|
<br>
|
|
|
|
<br>
|
|
|
|
<p>
|
|
Mit freundlichen Grüßen,
|
|
<br>
|
|
Dipl.-Ing. Jens Cornelsen
|
|
<br>
|
|
<br>
|
|
|
|
<strong>IB Cornelsen</strong>
|
|
<br>
|
|
Katendeich 5A
|
|
<br>
|
|
21035 Hamburg
|
|
<br>
|
|
www.online-energieausweis.org
|
|
<br>
|
|
<br>
|
|
|
|
fon 040 · 209339850
|
|
<br>
|
|
fax 040 · 209339859
|
|
</p>`;
|
|
}
|
|
|
|
|
|
const attachments: Attachment[] = [
|
|
{
|
|
filename: `ID_${ausweis.id}_Energieausweis.pdf`,
|
|
encoding: "binary",
|
|
content: Buffer.from(pdfAusweis),
|
|
contentType: "application/pdf",
|
|
},
|
|
{
|
|
filename: `ID_${ausweis.id}_Datenblatt.pdf`,
|
|
encoding: "binary",
|
|
content: Buffer.from(pdfDatenblatt),
|
|
contentType: "application/pdf",
|
|
},
|
|
{
|
|
filename: `ID_${ausweis.id}_Rechnung.pdf`,
|
|
encoding: "binary",
|
|
content: Buffer.from(pdfRechnung),
|
|
contentType: "application/pdf",
|
|
}
|
|
];
|
|
|
|
if (pdfAushang) {
|
|
attachments.push({
|
|
filename: `ID_${ausweis.id}_Aushang.pdf`,
|
|
encoding: "binary",
|
|
content: Buffer.from(pdfAushang),
|
|
contentType: "application/pdf",
|
|
});
|
|
}
|
|
|
|
|
|
|
|
await transport.sendMail({
|
|
from: `"IBCornelsen" <info@online-energieausweis.org>`,
|
|
to: rechnung.email || rechnung.benutzer.email,
|
|
bcc: "info@online-energieausweis.org",
|
|
subject: `Ihr Originalausweis vom Ingenieurbüro Cornelsen (ID: ${ausweis.id})`,
|
|
html,
|
|
attachments
|
|
});
|
|
|
|
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
|
|
await prisma.verbrauchsausweisWohnen.update({
|
|
where: {
|
|
id: ausweis.id,
|
|
},
|
|
data: {
|
|
ausgestellt: true,
|
|
},
|
|
});
|
|
} else if (
|
|
ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe
|
|
) {
|
|
await prisma.verbrauchsausweisGewerbe.update({
|
|
where: {
|
|
id: ausweis.id,
|
|
},
|
|
data: {
|
|
ausgestellt: true,
|
|
},
|
|
});
|
|
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
|
|
await prisma.bedarfsausweisWohnen.update({
|
|
where: {
|
|
id: ausweis.id,
|
|
},
|
|
data: {
|
|
ausgestellt: true,
|
|
},
|
|
});
|
|
}
|
|
}, 3000);
|
|
},
|
|
});
|