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:
135
server/utils/pdf-field-mapper.js
Normal file
135
server/utils/pdf-field-mapper.js
Normal 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'
|
||||
}
|
||||
Reference in New Issue
Block a user