PDF View i Adminbereich

This commit is contained in:
2026-03-18 17:24:13 +01:00
parent a92694f693
commit 8152aab15b
4 changed files with 599 additions and 0 deletions

129
rebuild-timesheet-pdfs.js Normal file
View File

@@ -0,0 +1,129 @@
// scripts/rebuild-timesheet-pdfs.js
// Läuft im Projekt root: node scripts/rebuild-timesheet-pdfs.js
// Erzeugt (bzw. speichert) fehlende PDFs für alle eingereichten weekly_timesheets,
// basierend auf der bestehenden versionstreuen Generierungslogik.
const path = require('path');
const { db } = require('../database');
const { generatePDFToBuffer } = require('../services/pdf-service');
const {
resolvePdfLocationFromTimesheetRow,
fileExists,
savePdfBufferAtomic,
} = require('../services/pdf-storage-service');
async function getAllSubmittedTimesheets() {
const sql = `
SELECT wt.id, wt.user_id, wt.week_start, wt.week_end, wt.version,
wt.pdf_path,
u.firstname, u.lastname, u.username
FROM weekly_timesheets wt
JOIN users u ON u.id = wt.user_id
WHERE wt.status = 'eingereicht'
ORDER BY wt.week_start, wt.user_id, wt.version
`;
return new Promise((resolve, reject) => {
db.all(sql, [], (err, rows) => {
if (err) return reject(err);
resolve(rows || []);
});
});
}
async function rebuildMissingPdfs() {
const all = await getAllSubmittedTimesheets();
if (!all.length) {
console.log('Keine eingereichten weekly_timesheets gefunden.');
return;
}
console.log(`Gefundene eingereichte weekly_timesheets: ${all.length}`);
let processed = 0;
let created = 0;
let skippedExists = 0;
let failed = 0;
for (const row of all) {
processed += 1;
try {
const loc = resolvePdfLocationFromTimesheetRow(row);
const absolutePath = loc.absolutePath;
const exists = await fileExists(absolutePath);
if (exists) {
skippedExists += 1;
if (processed % 50 === 0) {
console.log(
`[${processed}/${all.length}] Timesheet #${row.id}: PDF existiert bereits -> übersprungen.`,
);
}
continue;
}
console.log(
`[${processed}/${all.length}] Erzeuge PDF für Timesheet #${row.id} (User ${row.user_id}, KW: ${row.week_start}..${row.week_end}, Version ${row.version})`,
);
// Mock-Request für generatePDFToBuffer analog zu verwaltung-routes bulk-download
const mockReq = {
session: {
userId: null, // hier optional eine system-User-ID einsetzen, wenn benötigt
},
query: {},
};
const buffer = await generatePDFToBuffer(row.id, mockReq);
await savePdfBufferAtomic(absolutePath, buffer);
// Optional: pdf_path in DB setzen, falls noch leer
if (!row.pdf_path) {
const relativePath = loc.relativePath;
await new Promise((resolve, reject) => {
db.run(
'UPDATE weekly_timesheets SET pdf_path = ? WHERE id = ?',
[relativePath, row.id],
(err) => {
if (err) return reject(err);
resolve();
},
);
});
}
created += 1;
} catch (err) {
failed += 1;
console.error(
`Fehler beim Erzeugen der PDF für Timesheet #${row.id}:`,
err && err.message ? err.message : err,
);
}
}
console.log('-----------------------------');
console.log('Rebuild abgeschlossen.');
console.log(`Gesamt: ${processed}`);
console.log(`Neu erzeugt: ${created}`);
console.log(`Bereits vorhanden: ${skippedExists}`);
console.log(`Fehler: ${failed}`);
}
// Direktstart, wenn Datei via node aufgerufen wird
if (require.main === module) {
rebuildMissingPdfs()
.then(() => {
console.log('Fertig.');
// DB-Verbindung optional schließen, falls du willst:
// db.close();
})
.catch((err) => {
console.error('Unerwarteter Fehler beim Rebuild:', err);
process.exitCode = 1;
});
}
module.exports = { rebuildMissingPdfs };