const db = require("../db"); const ejs = require("ejs"); const path = require("path"); const htmlToPdf = require("html-pdf-node"); const fs = require("fs"); async function createInvoicePdf(req, res) { const patientId = req.params.id; const connection = await db.promise().getConnection(); try { await connection.beginTransaction(); const year = new Date().getFullYear(); // 🔒 Rechnungszähler sperren const [[counterRow]] = await connection.query( "SELECT counter FROM invoice_counters WHERE year = ? FOR UPDATE", [year] ); let counter; if (!counterRow) { counter = 1; await connection.query( "INSERT INTO invoice_counters (year, counter) VALUES (?, ?)", [year, counter] ); } else { counter = counterRow.counter + 1; await connection.query( "UPDATE invoice_counters SET counter = ? WHERE year = ?", [counter, year] ); } const invoiceNumber = `${year}-${String(counter).padStart(4, "0")}`; // 🔹 Patient const [[patient]] = await connection.query( "SELECT * FROM patients WHERE id = ?", [patientId] ); if (!patient) throw new Error("Patient nicht gefunden"); // 🔹 Leistungen const [rows] = await connection.query( ` SELECT ps.quantity, COALESCE(ps.price_override, s.price) AS price, s.name_de 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 `, [patientId] ); if (!rows.length) throw new Error("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); // 🔹 Arzt const [[doctor]] = await connection.query( ` SELECT first_name, last_name, fachrichtung, arztnummer FROM users WHERE id = ( SELECT created_by FROM patient_services WHERE patient_id = ? ORDER BY service_date DESC LIMIT 1 ) `, [patientId] ); // 🔹 Firma const [[company]] = await connection.query( "SELECT * FROM company_settings LIMIT 1" ); // 🖼 Logo als Base64 let logoBase64 = null; if (company && company.invoice_logo_path) { const logoPath = path.join( __dirname, "..", "public", company.invoice_logo_path ); if (fs.existsSync(logoPath)) { const buffer = fs.readFileSync(logoPath); const ext = path.extname(logoPath).toLowerCase(); const mime = ext === ".jpg" || ext === ".jpeg" ? "image/jpeg" : "image/png"; logoBase64 = `data:${mime};base64,${buffer.toString("base64")}`; } } // 📁 PDF-Pfad vorbereiten const invoiceDir = path.join( __dirname, "..", "public", "invoices", String(year) ); if (!fs.existsSync(invoiceDir)) { fs.mkdirSync(invoiceDir, { recursive: true }); } const fileName = `invoice-${invoiceNumber}.pdf`; const absoluteFilePath = path.join(invoiceDir, fileName); const dbFilePath = `/invoices/${year}/${fileName}`; // 🔹 Rechnung speichern const [result] = await connection.query( ` INSERT INTO invoices (patient_id, invoice_date, file_path, total_amount, created_by, status) VALUES (?, CURDATE(), ?, ?, ?, 'open') `, [patientId, dbFilePath, total, req.session.user.id] ); const invoiceId = result.insertId; const invoice = { number: invoiceNumber, date: new Date().toLocaleDateString("de-DE"), }; // 🔹 HTML rendern const html = await ejs.renderFile( path.join(__dirname, "../views/invoices/invoice.ejs"), { patient, services, total, invoice, doctor, company, logoBase64, } ); // 🔹 PDF erzeugen const pdfBuffer = await htmlToPdf.generatePdf( { content: html }, { format: "A4", printBackground: true } ); // 💾 PDF speichern fs.writeFileSync(absoluteFilePath, pdfBuffer); // 🔗 Leistungen mit Rechnung verknüpfen const [updateResult] = await connection.query( ` UPDATE patient_services SET invoice_id = ? WHERE patient_id = ? AND invoice_id IS NULL `, [invoiceId, patientId] ); const [[cid]] = await connection.query("SELECT CONNECTION_ID() AS cid"); console.log("🔌 INVOICE CID:", cid.cid); await connection.commit(); console.log("🔌 INVOICE CID:", cid.cid); // 📤 PDF anzeigen res.render("invoice_preview", { pdfUrl: dbFilePath, }); } catch (err) { await connection.rollback(); console.error("❌ INVOICE ERROR:", err); res.status(500).send(err.message || "Fehler beim Erstellen der Rechnung"); } finally { connection.release(); } } module.exports = { createInvoicePdf };