Awnderung der HTML von Invoice

This commit is contained in:
Cay 2026-01-06 19:17:40 +00:00
parent 7ab67a839b
commit 491bd2db7d
4 changed files with 339 additions and 49 deletions

View File

@ -18,18 +18,16 @@ async function createInvoicePdf(req, res) {
return res.status(404).send("Patient nicht gefunden");
}
// 2⃣ Leistungen laden (noch nicht abgerechnet)
// 2⃣ Leistungen laden
const [rows] = await db.promise().query(`
SELECT
ps.quantity,
COALESCE(ps.price_override, s.price) AS price,
CASE
WHEN UPPER(TRIM(?)) = 'ES'
THEN COALESCE(NULLIF(s.name_es, ''), s.name_de)
ELSE s.name_de
END AS name
FROM patient_services ps
JOIN services s ON ps.service_id = s.id
WHERE ps.patient_id = ?
@ -49,10 +47,15 @@ async function createInvoicePdf(req, res) {
const total = services.reduce((sum, s) => sum + s.total, 0);
// 3⃣ HTML aus EJS erzeugen
// 3⃣ HTML rendern (NOCH OHNE invoiceId)
const invoice = {
number: "—",
date: new Date().toLocaleDateString("de-DE")
};
const html = await ejs.renderFile(
path.join(__dirname, "../views/invoices/invoice.ejs"),
{ patient, services, total }
{ patient, services, total, invoice }
);
// 4⃣ PDF erzeugen
@ -61,18 +64,17 @@ async function createInvoicePdf(req, res) {
{ format: "A4" }
);
// 5⃣ Dateiname + Pfad
const date = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
const fileName = `invoice_${patientId}_${date}.pdf`;
// 5⃣ Datei speichern
const dateStr = new Date().toISOString().split("T")[0];
const fileName = `invoice_${patientId}_${dateStr}.pdf`;
const outputPath = path.join(__dirname, "..", "documents", fileName);
// 6⃣ PDF speichern
fs.writeFileSync(outputPath, pdfBuffer);
// 7⃣ OPTIONAL: Rechnung in DB speichern (empfohlen)
// 6⃣ Rechnung EINMAL in DB speichern
const [invoiceResult] = await db.promise().query(`
INSERT INTO invoices
(patient_id, invoice_date, total_amount, file_path, created_by, status)
INSERT INTO invoices
(patient_id, invoice_date, total_amount, file_path, created_by, status)
VALUES (?, CURDATE(), ?, ?, ?, 'open')
`, [
patientId,
@ -83,7 +85,7 @@ async function createInvoicePdf(req, res) {
const invoiceId = invoiceResult.insertId;
// 8️⃣ Leistungen verknüpfen
// 7️⃣ Leistungen verknüpfen
await db.promise().query(`
UPDATE patient_services
SET invoice_id = ?
@ -91,7 +93,7 @@ async function createInvoicePdf(req, res) {
AND invoice_id IS NULL
`, [invoiceId, patientId]);
// 9️⃣ PDF anzeigen
// 8️⃣ PDF anzeigen
res.setHeader("Content-Type", "application/pdf");
res.setHeader(
"Content-Disposition",

View File

@ -0,0 +1,109 @@
const db = require("../db");
const ejs = require("ejs");
const path = require("path");
const fs = require("fs");
const pdf = require("html-pdf-node");
async function createInvoicePdf(req, res) {
const patientId = req.params.id;
try {
// 1⃣ Patient laden
const [[patient]] = await db.promise().query(
"SELECT * FROM patients WHERE id = ?",
[patientId]
);
if (!patient) {
return res.status(404).send("Patient nicht gefunden");
}
// 2⃣ Leistungen laden (noch nicht abgerechnet)
const [rows] = await db.promise().query(`
SELECT
ps.quantity,
COALESCE(ps.price_override, s.price) AS price,
CASE
WHEN UPPER(TRIM(?)) = 'ES'
THEN COALESCE(NULLIF(s.name_es, ''), s.name_de)
ELSE s.name_de
END AS name
FROM patient_services ps
JOIN services s ON ps.service_id = s.id
WHERE ps.patient_id = ?
AND ps.invoice_id IS NULL
`, [patient.country, patientId]);
if (rows.length === 0) {
return res.send("Keine Leistungen vorhanden");
}
const services = rows.map(s => ({
quantity: Number(s.quantity),
name: s.name,
price: Number(s.price),
total: Number(s.price) * Number(s.quantity)
}));
const total = services.reduce((sum, s) => sum + s.total, 0);
// 3⃣ HTML aus EJS erzeugen
const html = await ejs.renderFile(
path.join(__dirname, "../views/invoices/invoice.ejs"),
{ patient, services, total }
);
// 4⃣ PDF erzeugen
const pdfBuffer = await pdf.generatePdf(
{ content: html },
{ format: "A4" }
);
// 5⃣ Dateiname + Pfad
const date = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
const fileName = `invoice_${patientId}_${date}.pdf`;
const outputPath = path.join(__dirname, "..", "documents", fileName);
// 6⃣ PDF speichern
fs.writeFileSync(outputPath, pdfBuffer);
// 7⃣ OPTIONAL: Rechnung in DB speichern (empfohlen)
const [invoiceResult] = await db.promise().query(`
INSERT INTO invoices
(patient_id, invoice_date, total_amount, file_path, created_by, status)
VALUES (?, CURDATE(), ?, ?, ?, 'open')
`, [
patientId,
total,
`documents/${fileName}`,
req.session.user.id
]);
const invoiceId = invoiceResult.insertId;
// 8⃣ Leistungen verknüpfen
await db.promise().query(`
UPDATE patient_services
SET invoice_id = ?
WHERE patient_id = ?
AND invoice_id IS NULL
`, [invoiceId, patientId]);
// 9⃣ PDF anzeigen
res.setHeader("Content-Type", "application/pdf");
res.setHeader(
"Content-Disposition",
`inline; filename="${fileName}"`
);
res.send(pdfBuffer);
} catch (err) {
console.error("❌ PDF ERROR:", err);
res.status(500).send("Fehler beim Erstellen der Rechnung");
}
}
module.exports = { createInvoicePdf };

View File

@ -1,16 +1,28 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<style>
<meta charset="UTF-8">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
color: #000;
}
h1, h2, h3 {
margin-bottom: 10px;
.header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.logo {
width: 160px;
}
h1 {
text-align: center;
margin: 30px 0 20px;
}
table {
@ -22,55 +34,146 @@
th, td {
border: 1px solid #333;
padding: 6px;
text-align: left;
}
th {
background: #f0f0f0;
}
.no-border td {
border: none;
padding: 4px 2px;
}
.total {
margin-top: 20px;
font-weight: bold;
margin-top: 15px;
font-size: 14px;
font-weight: bold;
text-align: right;
}
.footer {
margin-top: 30px;
font-size: 10px;
}
</style>
</head>
<body>
<h2>Rechnung</h2>
<!-- HEADER -->
<div class="header">
<p>
<strong>Patient:</strong> <%= patient.firstname %> <%= patient.lastname %><br>
<strong>Adresse:</strong><br>
<%= patient.street %> <%= patient.house_number %><br>
<%= patient.postal_code %> <%= patient.city %>
</p>
<!-- LOGO -->
<div>
<!-- HIER LOGO EINBINDEN -->
<!-- <img src="file:///ABSOLUTER/PFAD/logo.png" class="logo"> -->
</div>
<table>
<thead>
<tr>
<th>Menge</th>
<th>Leistung</th>
<th>Preis</th>
<th>Summe</th>
</tr>
</thead>
<tbody>
<% services.forEach(s => { %>
<tr>
<td><%= s.quantity %></td>
<td><%= s.name %></td>
<td><%= s.price.toFixed(2) %> €</td>
<td><%= s.total.toFixed(2) %> €</td>
</tr>
<% }) %>
</tbody>
<!-- ADRESSE -->
<div>
<strong>MedCenter Tenerife S.L.</strong><br>
C.I.F. B76766302<br><br>
Praxis El Médano<br>
Calle Teobaldo Power 5<br>
38612 El Médano<br>
Fon: 922 157 527 / 657 497 996<br><br>
Praxis Los Cristianos<br>
Avenida de Suecia 10<br>
38650 Los Cristianos<br>
Fon: 922 157 527 / 654 520 717
</div>
</div>
<h1>RECHNUNG / FACTURA</h1>
<!-- RECHNUNGSDATEN -->
<table class="no-border">
<tr>
<td><strong>Factura número</strong></td>
<td><%= invoice.number %></td>
<td><strong>Fecha</strong></td>
<td><%= invoice.date %></td>
</tr>
<tr>
<td><strong>Rechnungsnummer</strong></td>
<td><%= invoice.number %></td>
<td><strong>Datum</strong></td>
<td><%= invoice.date %></td>
</tr>
<tr>
<td><strong>N.I.E. / DNI</strong></td>
<td><%= patient.dni || "" %></td>
<td><strong>Geburtsdatum</strong></td>
<td><%= patient.birthdate || "" %></td>
</tr>
</table>
<h3>Gesamt: <%= total.toFixed(2) %> €</h3>
<br>
<!-- PATIENT -->
<strong>Patient:</strong><br>
<%= patient.firstname %> <%= patient.lastname %><br>
<%= patient.street %> <%= patient.house_number %><br>
<%= patient.postal_code %> <%= patient.city %>
<br><br>
<!-- DIAGNOSE -->
<strong>Diagnosis / Diagnose:</strong><br>
<br><br>
<!-- LEISTUNGEN -->
<p>Für unsere Leistungen erlauben wir uns Ihnen folgendes in Rechnung zu stellen:</p>
<table>
<thead>
<tr>
<th>Menge</th>
<th>Terapia / Behandlung</th>
<th>Preis (€)</th>
<th>Summe (€)</th>
</tr>
</thead>
<tbody>
<% services.forEach(s => { %>
<tr>
<td><%= s.quantity %></td>
<td><%= s.name %></td>
<td><%= s.price.toFixed(2) %></td>
<td><%= s.total.toFixed(2) %></td>
</tr>
<% }) %>
</tbody>
</table>
<div class="total">
T O T A L: <%= total.toFixed(2) %> €
</div>
<br>
<!-- ZAHLUNGSART -->
<strong>Forma de pago / Zahlungsform:</strong><br>
Efectivo □ &nbsp;&nbsp; Tarjeta □<br>
Barzahlung &nbsp;&nbsp; EC/Kreditkarte
<br><br>
<!-- BANK -->
<strong>Santander</strong><br>
IBAN: ES37 0049 4507 8925 1002 3301<br>
BIC: BSCHESMMXXX
<div class="footer">
Privatärztliche Rechnung gemäß spanischem und deutschem Recht
</div>
</body>
</html>

View File

@ -0,0 +1,76 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
font-size: 12px;
color: #000;
}
h1, h2, h3 {
margin-bottom: 10px;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th, td {
border: 1px solid #333;
padding: 6px;
text-align: left;
}
th {
background: #f0f0f0;
}
.total {
margin-top: 20px;
font-weight: bold;
font-size: 14px;
}
</style>
</head>
<body>
<h2>Rechnung</h2>
<p>
<strong>Patient:</strong> <%= patient.firstname %> <%= patient.lastname %><br>
<strong>Adresse:</strong><br>
<%= patient.street %> <%= patient.house_number %><br>
<%= patient.postal_code %> <%= patient.city %>
</p>
<table>
<thead>
<tr>
<th>Menge</th>
<th>Leistung</th>
<th>Preis</th>
<th>Summe</th>
</tr>
</thead>
<tbody>
<% services.forEach(s => { %>
<tr>
<td><%= s.quantity %></td>
<td><%= s.name %></td>
<td><%= s.price.toFixed(2) %> €</td>
<td><%= s.total.toFixed(2) %> €</td>
</tr>
<% }) %>
</tbody>
</table>
<h3>Gesamt: <%= total.toFixed(2) %> €</h3>
</body>
</html>