Files
SDSStundenerfassung/rebuild-timesheet-pdfs.js
2026-03-18 17:24:13 +01:00

129 lines
3.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 };