Awnderung der HTML von Invoice
This commit is contained in:
parent
7ab67a839b
commit
491bd2db7d
@ -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",
|
||||
|
||||
109
controllers/invoicePdf.controller.js_original
Normal file
109
controllers/invoicePdf.controller.js_original
Normal 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 };
|
||||
@ -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 □ Tarjeta □<br>
|
||||
Barzahlung 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>
|
||||
|
||||
|
||||
76
views/invoices/invoice.ejs_original
Normal file
76
views/invoices/invoice.ejs_original
Normal 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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user