diff --git a/scripts/fill-sample-template.js b/scripts/fill-sample-template.js deleted file mode 100644 index d157a08..0000000 --- a/scripts/fill-sample-template.js +++ /dev/null @@ -1,258 +0,0 @@ -import fs from 'fs' -import { PDFDocument, StandardFonts, rgb } from 'pdf-lib' - -async function fill() { - const templatePath = 'server/templates/mitgliedschaft-fillable.pdf' - if (!fs.existsSync(templatePath)) { - console.error('Template not found:', templatePath) - process.exit(1) - } - - const existingPdfBytes = fs.readFileSync(templatePath) - const pdfDoc = await PDFDocument.load(existingPdfBytes) - const form = pdfDoc.getForm() - - // Ensure a readable font is embedded and used for field appearances - const helv = await pdfDoc.embedFont(StandardFonts.Helvetica) - - // Simple sample data - const sample = { - nachname: 'Müller', - vorname: 'Anna', - strasse: 'Hauptstr. 12', - plz_ort: '60389 Frankfurt', - geburtsdatum: '01.01.1990', - telefon: '069 123456', - email: 'anna.mueller@example.de', - telefon_mobil: '0151 2345678', - mitglied_aktiv: true, - mitglied_passiv: false, - sepa_mitglied: 'Anna Müller', - sepa_kontoinhaber: 'Anna Müller', - sepa_strasse: 'Hauptstr. 12', - sepa_plz_ort: '60389 Frankfurt', - sepa_bank: 'Sparkasse', - sepa_iban: 'DE00123456781234567890', - sepa_bic: 'PBNKDEFF', - sepa_datum: '23.10.2025', - sign_datum: '23.10.2025', - page3_name: 'Müller', - page3_vorname: 'Anna', - page3_anschrift: 'Hauptstr. 12, 60389 Frankfurt', - page3_telefon: '069 123456', - page3_fax: '069 654321', - page3_email: 'anna.mueller@example.de', - page3_datum: '23.10.2025' - } - - function safeSetText(name, value) { - try { - const f = form.getTextField(name) - f.setText(value) - } catch (e) { - // ignore missing fields - } - } - - // Robust setter: find a field by name (case-insensitive) and set text/checkbox/select accordingly - function setFieldByName(name, value) { - try { - const lower = name.toLowerCase() - const field = form.getFields().find(f => f.getName() && f.getName().toLowerCase() === lower) - if (!field) { - console.log(`DEBUG: Field not found for '${name}'`) - return false - } - // Text field - if (typeof field.setText === 'function') { - field.setText(value == null ? '' : String(value)) - return true - } - // Check box - if (typeof field.check === 'function') { - if (value === true || String(value).toLowerCase() === 'true') field.check() - else if (typeof field.uncheck === 'function') field.uncheck() - return true - } - // Radio/select (pdf-lib uses select for dropdowns) - if (typeof field.select === 'function') { - try { field.select(String(value)) } catch (e) { /* ignore */ } - return true - } - console.log(`DEBUG: Unsupported field type for '${name}'`) - return false - } catch (e) { - console.log(`DEBUG: Error setting field '${name}':`, e.message) - return false - } - } - - // Debug: list all form fields found in the template - try { - const allFields = form.getFields().map(f => f.getName()) - console.log('DEBUG: Template form fields:', allFields.join(', ')) - } catch (e) { - console.log('DEBUG: Could not list form fields:', e.message) - } - - setFieldByName('nachname', sample.nachname) - setFieldByName('vorname', sample.vorname) - setFieldByName('strasse', sample.strasse) - setFieldByName('plz_ort', sample.plz_ort) - setFieldByName('geburtsdatum', sample.geburtsdatum) - setFieldByName('telefon', sample.telefon) - setFieldByName('email', sample.email) - setFieldByName('telefon_mobil', sample.telefon_mobil) - - // Checkboxes via robust setter - setFieldByName('mitglied_aktiv', sample.mitglied_aktiv) - setFieldByName('mitglied_passiv', sample.mitglied_passiv) - - setFieldByName('sepa_mitglied', sample.sepa_mitglied) - setFieldByName('sepa_kontoinhaber', sample.sepa_kontoinhaber) - setFieldByName('sepa_strasse', sample.sepa_strasse) - setFieldByName('sepa_plz_ort', sample.sepa_plz_ort) - setFieldByName('sepa_bank', sample.sepa_bank) - setFieldByName('sepa_iban', sample.sepa_iban) - setFieldByName('sepa_bic', sample.sepa_bic) - setFieldByName('sepa_datum', sample.sepa_datum) - setFieldByName('sign_datum', sample.sign_datum) - - // page3 fields - setFieldByName('page3_name', sample.page3_name) - setFieldByName('page3_vorname', sample.page3_vorname) - setFieldByName('page3_anschrift', sample.page3_anschrift) - setFieldByName('page3_telefon', sample.page3_telefon) - setFieldByName('page3_fax', sample.page3_fax) - setFieldByName('page3_email', sample.page3_email) - setFieldByName('page3_datum', sample.page3_datum) - - // Debug: check which sample keys correspond to actual fields - try { - const names = form.getFields().map(f => f.getName().toLowerCase()) - for (const key of Object.keys(sample)) { - const found = names.includes(key.toLowerCase()) - console.log(`DEBUG: sample key='${key}' -> field present=${found}`) - } - } catch (e) { - console.log('DEBUG: field presence check failed:', e.message) - } - - // Debug: read back all field values after setting (before flattening) - try { - console.log('DEBUG: Field values after setting:') - for (const f of form.getFields()) { - const name = f.getName() - let val = null - try { - if (typeof f.getText === 'function') val = f.getText() - else if (typeof f.isChecked === 'function') val = f.isChecked() - else val = '(no getter)' - } catch (e) { - val = `(error reading: ${e.message})` - } - console.log(` ${name}: ${val}`) - } - } catch (e) { - console.log('DEBUG: Could not read back field values:', e.message) - } - - // Debug: print widget rectangles for relevant fields (SEPA and page3) - try { - const interesting = ['sepa_mitglied','sepa_kontoinhaber','sepa_strasse','sepa_plz_ort','sepa_bank','sepa_iban','sepa_bic','page3_name','page3_vorname','page3_anschrift','page3_telefon','page3_email'] - for (const fname of interesting) { - const f = form.getFields().find(x => x.getName && x.getName().toLowerCase() === fname) - if (!f) { console.log(`DEBUG: no field object for ${fname}`); continue } - try { - // attempt to access widget rectangle via low-level acroField - const acro = f.acroField - const widgets = acro.getWidgets() - if (!widgets || widgets.length === 0) { console.log(`DEBUG: no widgets for ${fname}`); continue } - const rect = widgets[0].getRectangle() - console.log(`DEBUG: widget rect for ${fname}: ${JSON.stringify(rect)}`) - } catch (e) { - console.log(`DEBUG: cannot read widget rect for ${fname}: ${e.message}`) - } - } - } catch (e) { - console.log('DEBUG: widget rect inspection failed:', e.message) - } - - // Define fallback drawing: draw visible text directly onto pages at widget rect positions - async function fallbackDraw() { - try { - const pages = pdfDoc.getPages() - // draw SEPA fields on page 2 (index 1) - const p2 = pages[1] - const sepaFields = ['sepa_mitglied','sepa_kontoinhaber','sepa_strasse','sepa_plz_ort','sepa_bank','sepa_iban','sepa_bic'] - for (const fname of sepaFields) { - const f = form.getFields().find(x => x.getName && x.getName().toLowerCase() === fname) - if (!f) continue - try { - const widgets = f.acroField.getWidgets() - if (!widgets || widgets.length === 0) continue - const rect = widgets[0].getRectangle() - const text = (typeof f.getText === 'function') ? f.getText() : '' - if (text) { - p2.drawText(String(text), { x: rect.x + 2, y: rect.y + rect.height - 12, size: 11, font: helv }) - console.log(`FALLBACK: drew ${fname} on page2 at ${rect.x},${rect.y}`) - } - } catch (e) { - console.log(`FALLBACK: could not draw ${fname}: ${e.message}`) - } - } - - // draw page3 fields on page 3 (index 2) - const p3 = pages[2] - const p3Fields = ['page3_name','page3_vorname','page3_anschrift','page3_telefon','page3_email'] - for (const fname of p3Fields) { - const f = form.getFields().find(x => x.getName && x.getName().toLowerCase() === fname) - if (!f) continue - try { - const widgets = f.acroField.getWidgets() - if (!widgets || widgets.length === 0) continue - const rect = widgets[0].getRectangle() - const text = (typeof f.getText === 'function') ? f.getText() : '' - if (text) { - p3.drawText(String(text), { x: rect.x + 2, y: rect.y + rect.height - 12, size: 11, font: helv }) - console.log(`FALLBACK: drew ${fname} on page3 at ${rect.x},${rect.y}`) - } - } catch (e) { - console.log(`FALLBACK: could not draw ${fname}: ${e.message}`) - } - } - // write fallback copy - const fallbackBytes = await pdfDoc.save() - if (!fs.existsSync('temp')) fs.mkdirSync('temp') - fs.writeFileSync('temp/mitgliedschaft-sample-filled-fallback.pdf', fallbackBytes) - console.log('Wrote temp/mitgliedschaft-sample-filled-fallback.pdf') - } catch (e) { - console.log('FALLBACK drawing failed:', e.message) - } - } - - // Update field appearances so text is visible, then flatten. Run fallback only when enabled. - try { - form.updateFieldAppearances(helv) - const outUnflattened = await pdfDoc.save() - if (!fs.existsSync('temp')) fs.mkdirSync('temp') - fs.writeFileSync('temp/mitgliedschaft-sample-filled-unflattened.pdf', outUnflattened) - form.flatten() - } catch (e) { - console.warn('Could not update field appearances:', e.message) - const enableFallback = process.env.ENABLE_FALLBACK === '1' || (typeof sample.debug !== 'undefined' && sample.debug) - if (enableFallback) { - try { await fallbackDraw() } catch (err) { console.warn('Fallback draw failed:', err.message) } - try { form.flatten() } catch (err) { /* ignore */ } - } - } - - - - const out = await pdfDoc.save() - if (!fs.existsSync('temp')) fs.mkdirSync('temp') - fs.writeFileSync('temp/mitgliedschaft-sample-filled.pdf', out) - console.log('Wrote temp/mitgliedschaft-sample-filled.pdf') -} - -fill().catch(e => { console.error(e); process.exit(1) }) diff --git a/scripts/smoke-test.js b/scripts/smoke-test.js index d2809a8..d86be5b 100644 --- a/scripts/smoke-test.js +++ b/scripts/smoke-test.js @@ -10,7 +10,6 @@ function run(cmd) { async function main() { const root = process.cwd() run('node scripts/create-fillable-template.js') - run('node scripts/fill-sample-template.js') const uploads = path.join(root, 'public', 'uploads') const files = fs.existsSync(uploads) ? fs.readdirSync(uploads).filter(f => f.toLowerCase().endsWith('.pdf')) : [] console.log('Uploads PDFs:', files)