server.js aktualisiert
This commit is contained in:
136
server.js
136
server.js
@ -345,6 +345,7 @@ app.post('/accounts/:id', requireAuth, (req, res) => {
|
||||
});
|
||||
|
||||
// PDF Export route
|
||||
// PDF Export route - OPTIMIZED
|
||||
app.get('/accounts/:id/pdf', requireAuth, (req, res) => {
|
||||
const accountId = req.params.id;
|
||||
|
||||
@ -353,7 +354,6 @@ app.get('/accounts/:id/pdf', requireAuth, (req, res) => {
|
||||
return res.status(404).send('Konto nicht gefunden');
|
||||
}
|
||||
|
||||
// Get all transactions for this account
|
||||
db.all(`
|
||||
SELECT t.*, u.username as created_by_name, i.name as item_name
|
||||
FROM transactions t
|
||||
@ -367,80 +367,110 @@ app.get('/accounts/:id/pdf', requireAuth, (req, res) => {
|
||||
return res.status(500).send('Fehler beim Generieren des PDFs');
|
||||
}
|
||||
|
||||
// Create PDF document
|
||||
const doc = new PDFDocument({ margin: 30 });
|
||||
const doc = new PDFDocument({
|
||||
margin: 30,
|
||||
bufferPages: true,
|
||||
autoFirstPage: true,
|
||||
compress: true
|
||||
});
|
||||
|
||||
// Set response headers for PDF download
|
||||
res.setHeader('Content-Type', 'application/pdf');
|
||||
res.setHeader('Content-Disposition', `attachment; filename="Kontoauszug_${account.name.replace(/\s+/g, '_')}_${new Date().toISOString().split('T')[0]}.pdf"`);
|
||||
|
||||
// Pipe the PDF to the response
|
||||
doc.pipe(res);
|
||||
|
||||
// Add content to PDF
|
||||
doc.fontSize(20).text(`Kontoauszug für ${account.name}`, { align: 'center' });
|
||||
doc.moveDown();
|
||||
// Title - smaller
|
||||
doc.fontSize(16).text(`Kontoauszug für ${account.name}`, { align: 'center' });
|
||||
doc.moveDown(0.5);
|
||||
|
||||
doc.fontSize(14).text(`Kontostand: ${account.balance.toFixed(2)} €`);
|
||||
doc.fontSize(12).text(`Erstellt am: ${new Date(account.created_at).toLocaleDateString('de-DE')}`);
|
||||
doc.moveDown(2);
|
||||
// Account info - smaller fonts
|
||||
doc.fontSize(10);
|
||||
doc.text(`Kontostand: ${account.balance.toFixed(2)} €`);
|
||||
doc.text(`Konto erstellt: ${new Date(account.created_at).toLocaleDateString('de-DE')}`);
|
||||
doc.text(`Generiert am: ${new Date().toLocaleString('de-DE')}`);
|
||||
doc.text(`Generiert von: ${req.user.username}`);
|
||||
doc.moveDown(1.5);
|
||||
|
||||
doc.fontSize(16).text('Transaktionshistorie:', { underline: true });
|
||||
doc.moveDown();
|
||||
// Transaction history header
|
||||
doc.fontSize(12).text('Transaktionshistorie:', { underline: true });
|
||||
doc.moveDown(1);
|
||||
|
||||
// Table headers
|
||||
const table = {
|
||||
headers: ['Datum', 'Typ', 'Betrag', 'Beschreibung', 'Artikel', 'Durchgeführt von'],
|
||||
rows: []
|
||||
};
|
||||
// Table setup
|
||||
const tableTop = doc.y;
|
||||
const columnSpacing = 8;
|
||||
const pageWidth = doc.page.width - 60;
|
||||
|
||||
transactions.forEach(tx => {
|
||||
table.rows.push([
|
||||
const columns = [
|
||||
{ name: 'Datum', width: 100 },
|
||||
{ name: 'Typ', width: 60 },
|
||||
{ name: 'Betrag', width: 50 },
|
||||
{ name: 'Beschreibung', width: 120 },
|
||||
{ name: 'Artikel', width: 80 },
|
||||
{ name: 'Von', width: 70 }
|
||||
];
|
||||
|
||||
const totalWidth = columns.reduce((sum, col) => sum + col.width, 0) + (columnSpacing * (columns.length - 1));
|
||||
const scaleFactor = totalWidth > pageWidth ? pageWidth / totalWidth : 1;
|
||||
const scaledColumns = columns.map(col => ({ ...col, width: col.width * scaleFactor }));
|
||||
|
||||
// Draw headers
|
||||
doc.font('Helvetica-Bold').fontSize(10);
|
||||
let x = 30;
|
||||
scaledColumns.forEach(col => {
|
||||
doc.text(col.name, x, tableTop, { width: col.width, align: 'left' });
|
||||
x += col.width + columnSpacing;
|
||||
});
|
||||
|
||||
const tableEndX = x - columnSpacing;
|
||||
doc.moveTo(30, tableTop + 14).lineTo(tableEndX, tableTop + 14).stroke('#000000');
|
||||
|
||||
// Draw rows
|
||||
doc.font('Helvetica').fontSize(9);
|
||||
let y = tableTop + 22;
|
||||
const rowHeight = 16;
|
||||
|
||||
transactions.forEach((tx, rowIndex) => {
|
||||
if (y > doc.page.height - 80) {
|
||||
doc.addPage();
|
||||
y = 30;
|
||||
doc.font('Helvetica-Bold').fontSize(10);
|
||||
x = 30;
|
||||
scaledColumns.forEach(col => {
|
||||
doc.text(col.name, x, y, { width: col.width, align: 'left' });
|
||||
x += col.width + columnSpacing;
|
||||
});
|
||||
doc.moveTo(30, y + 14).lineTo(tableEndX, y + 14).stroke('#000000');
|
||||
doc.font('Helvetica').fontSize(9);
|
||||
y += 22;
|
||||
}
|
||||
|
||||
x = 30;
|
||||
const rowData = [
|
||||
new Date(tx.created_at).toLocaleString('de-DE'),
|
||||
tx.type === 'deposit' ? 'Einzahlung' : 'Abbuchung',
|
||||
`${tx.amount.toFixed(2)} €`,
|
||||
tx.description || '-',
|
||||
tx.item_name || '-',
|
||||
tx.created_by_name || 'System'
|
||||
]);
|
||||
(tx.description || '-').substring(0, 40),
|
||||
(tx.item_name || '-').substring(0, 25),
|
||||
(tx.created_by_name || 'System').substring(0, 20)
|
||||
];
|
||||
|
||||
rowData.forEach((cell, i) => {
|
||||
doc.text(cell, x, y, { width: scaledColumns[i].width, align: 'left' });
|
||||
x += scaledColumns[i].width + columnSpacing;
|
||||
});
|
||||
|
||||
// Draw table
|
||||
const tableTop = doc.y;
|
||||
const columnSpacing = 10;
|
||||
const columnWidths = [80, 60, 50, 120, 80, 80];
|
||||
y += rowHeight;
|
||||
|
||||
// Draw headers
|
||||
doc.font('Helvetica-Bold');
|
||||
let x = 30;
|
||||
table.headers.forEach((header, i) => {
|
||||
doc.text(header, x, tableTop, { width: columnWidths[i], align: 'left' });
|
||||
x += columnWidths[i] + columnSpacing;
|
||||
});
|
||||
doc.font('Helvetica');
|
||||
|
||||
// Draw rows
|
||||
let y = tableTop + 20;
|
||||
transactions.forEach((tx, rowIndex) => {
|
||||
x = 30;
|
||||
const row = table.rows[rowIndex];
|
||||
row.forEach((cell, i) => {
|
||||
doc.text(cell, x, y, { width: columnWidths[i], align: 'left' });
|
||||
x += columnWidths[i] + columnSpacing;
|
||||
});
|
||||
y += 20;
|
||||
|
||||
// Add horizontal line between rows
|
||||
if (rowIndex < transactions.length - 1) {
|
||||
doc.moveTo(30, y - 5).lineTo(550, y - 5).stroke('#cccccc');
|
||||
doc.moveTo(30, y - 6).lineTo(tableEndX, y - 6).stroke('#e0e0e0');
|
||||
}
|
||||
});
|
||||
|
||||
doc.moveDown(2);
|
||||
doc.fontSize(10).text(`Generiert am: ${new Date().toLocaleString('de-DE')}`, { align: 'right' });
|
||||
doc.fontSize(10).text(`Generiert von: ${req.user.username}`, { align: 'right' });
|
||||
doc.fontSize(10);
|
||||
doc.text(`Gesamt: ${transactions.length} Transaktionen`, { align: 'right' });
|
||||
doc.text(`Endstand: ${account.balance.toFixed(2)} €`, { align: 'right' });
|
||||
|
||||
// Finalize PDF
|
||||
doc.end();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user