Refactor membership PDF generation logic to improve maintainability and validation; remove deprecated form filling methods and enhance email notification process. Update membership page styles for better layout and user experience.

This commit is contained in:
Torsten Schulz (local)
2025-10-23 15:04:45 +02:00
parent 28a2d05ab5
commit 95ea3a26bc
11 changed files with 862 additions and 800 deletions

View File

@@ -0,0 +1,135 @@
/**
* PDF Field Mapper - Maps form data to PDF field names
* Clean Code: Single Responsibility Principle
*/
/**
* Formats a date string to DD.MM.YYYY format with leading zeros
* @param {string} dateString - Date string (YYYY-MM-DD format)
* @returns {string} Formatted date string (DD.MM.YYYY)
*/
function formatDateWithLeadingZeros(dateString) {
if (!dateString) return ''
try {
const date = new Date(dateString)
const day = String(date.getDate()).padStart(2, '0')
const month = String(date.getMonth() + 1).padStart(2, '0')
const year = date.getFullYear()
return `${day}.${month}.${year}`
} catch (error) {
return dateString
}
}
/**
* Maps form data to PDF field values based on field name patterns
* @param {Object} data - Form data
* @param {string} fieldName - PDF field name
* @returns {string} Mapped value
*/
export function mapFieldValue(data, fieldName) {
const name = fieldName.toLowerCase()
// Specific field mappings
const specificMappings = {
'sepa_mitglied': () => `${data.vorname || ''} ${data.nachname || ''}`.trim(),
'sepa_kontoinhaber': () => data.kontoinhaber || `${data.vorname || ''} ${data.nachname || ''}`.trim(),
'sepa_plz_ort': () => `${data.plz || ''} ${data.ort || ''}`.trim(),
'page3_anschrift': () => `${data.strasse || ''}, ${data.plz || ''} ${data.ort || ''}`.trim(),
'vorname': () => data.vorname || '',
'given': () => data.vorname || '',
'nachname': () => data.nachname || '',
'zuname': () => data.nachname || '',
'strasse': () => data.strasse || '',
'straße': () => data.strasse || '',
'street': () => data.strasse || '',
'plz': () => data.plz || '',
'ort': () => data.ort || '',
'stadt': () => data.ort || '',
'plz_ort': () => `${data.plz || ''} ${data.ort || ''}`.trim(),
'wohnort': () => `${data.plz || ''} ${data.ort || ''}`.trim(),
'geburtsdatum': () => formatDateWithLeadingZeros(data.geburtsdatum),
'geb': () => formatDateWithLeadingZeros(data.geburtsdatum),
'telefon': () => data.telefon_privat || data.telefon_mobil || '',
'tel': () => data.telefon_privat || data.telefon_mobil || '',
'email': () => data.email || '',
'kontoinhaber': () => data.kontoinhaber || '',
'kontoinh': () => data.kontoinhaber || '',
'iban': () => data.iban || '',
'bic': () => data.bic || '',
'bank': () => data.bank || '',
'kreditinstitut': () => data.bank || '',
'mitgliedschaft': () => data.mitgliedschaftsart || '',
'art': () => data.mitgliedschaftsart || ''
}
// Check for specific mappings first
for (const [pattern, mapper] of Object.entries(specificMappings)) {
if (name.includes(pattern)) {
return mapper()
}
}
// Special handling for PLZ/Ort combinations - more comprehensive
if (name.includes('plz') && (name.includes('ort') || name.includes('wohnort') || name.includes('stadt'))) {
return `${data.plz || ''} ${data.ort || ''}`.trim()
}
// Handle fields that might contain PLZ/Ort but don't explicitly mention both
if (name.includes('plz') && !name.includes('vorname') && !name.includes('nachname') && !name.includes('strasse') && !name.includes('str')) {
return `${data.plz || ''} ${data.ort || ''}`.trim()
}
if (name.includes('wohnort') || name.includes('ort') || name.includes('stadt')) {
if (!name.includes('vorname') && !name.includes('nachname') && !name.includes('strasse') && !name.includes('str')) {
return `${data.plz || ''} ${data.ort || ''}`.trim()
}
}
// Generic name mapping (avoid conflicts with specific mappings)
if (name.includes('name') && !name.includes('vorname') && !name.includes('given')) {
return data.nachname || ''
}
// Date fields
if (name.includes('datum')) {
return data.sign_datum || data.sepa_datum || data.page3_datum || formatDateWithLeadingZeros(new Date().toISOString().split('T')[0])
}
return ''
}
/**
* Checks if a field should be checked based on membership type
* @param {string} fieldName - PDF field name
* @param {string} membershipType - Membership type ('aktiv' or 'passiv')
* @returns {boolean} Whether the field should be checked
*/
export function shouldCheckField(fieldName, membershipType) {
const name = fieldName.toLowerCase()
if (name.includes('aktiv') && membershipType === 'aktiv') {
return true
}
if (name.includes('passiv') && membershipType === 'passiv') {
return true
}
if (name.includes('mitglied') && name.includes(membershipType)) {
return true
}
return false
}
/**
* Checks if a field should be checked based on boolean value
* @param {string} value - Value to check
* @returns {boolean} Whether the field should be checked
*/
export function shouldCheckByValue(value) {
const stringValue = String(value).toLowerCase()
return stringValue === 'true' || stringValue === 'ja' || stringValue === 'checked'
}