diff --git a/includes/class-email-generator.php b/includes/class-email-generator.php index b0e7001..70845a7 100644 --- a/includes/class-email-generator.php +++ b/includes/class-email-generator.php @@ -35,20 +35,17 @@ class Umzugsliste_Email_Generator { // Customer info $content .= self::generate_customer_info_section( $data ); - // All rooms + // All rooms with grand totals in last room's table $content .= self::generate_all_rooms( $data ); - // Additional work sections - $content .= self::generate_additional_work_sections( $data ); + // Weitere Arbeiten (single 3-column table) + $content .= self::generate_weitere_arbeiten( $data ); // Sonstiges if ( ! empty( $data['sonstiges'] ) ) { $content .= self::generate_sonstiges_section( $data['sonstiges'] ); } - // Grand totals - $content .= self::generate_grand_totals( $data ); - // Wrap in HTML document return self::wrap_html( $content ); } @@ -135,7 +132,7 @@ class Umzugsliste_Email_Generator { } /** - * Generate all room sections + * Generate all room sections with grand totals in last room's table * * @param array $data Form data * @return string HTML @@ -144,22 +141,66 @@ class Umzugsliste_Email_Generator { $html = ''; $rooms = Umzugsliste_Furniture_Data::get_rooms(); + // Collect rooms that have items + $rooms_with_items = array(); foreach ( $rooms as $room_key => $room_label ) { - // Get post array name for this room $post_array_name = ucfirst( $room_key ); if ( 'kueche_esszimmer' === $room_key ) { $post_array_name = 'Kueche_Esszimmer'; } - // Get room data from submission $room_data = $data[ $post_array_name ] ?? array(); - - // Only include room if it has items with quantities if ( self::has_items_with_quantities( $room_data ) ) { - $html .= self::generate_room_section( $room_key, $room_label, $room_data ); + $rooms_with_items[ $room_key ] = array( + 'label' => $room_label, + 'data' => $room_data, + ); } } + if ( empty( $rooms_with_items ) ) { + return ''; + } + + $room_keys = array_keys( $rooms_with_items ); + $last_room_key = end( $room_keys ); + + // Grand totals accumulators + $grand_total_quantity = 0; + $grand_total_cbm = 0; + + foreach ( $rooms_with_items as $room_key => $room_info ) { + $is_last = ( $room_key === $last_room_key ); + $html .= self::generate_room_section( + $room_key, + $room_info['label'], + $room_info['data'], + $is_last + ); + + // Accumulate grand totals + foreach ( $room_info['data'] as $key => $value ) { + if ( substr( $key, 0, 1 ) === 'v' && ! empty( $value ) && floatval( $value ) > 0 ) { + $item_name = substr( $key, 1 ); + $quantity = floatval( str_replace( ',', '.', trim( $value ) ) ); + $cbm = isset( $room_info['data'][ 'q' . $item_name ] ) ? floatval( $room_info['data'][ 'q' . $item_name ] ) : 0; + $grand_total_quantity += $quantity; + $grand_total_cbm += ( $quantity * $cbm ); + } + } + } + + // Grand totals row inside last room's table + $grand_total_display = str_replace( '.', ',', number_format( $grand_total_cbm, 2, '.', '' ) ); + + $html .= "  + + " . $grand_total_quantity . " + Gesamtsummen + " . esc_html( $grand_total_display ) . " +   + "; + return $html; } @@ -184,9 +225,10 @@ class Umzugsliste_Email_Generator { * @param string $room_key Room key * @param string $room_label Room label * @param array $room_data Room submission data + * @param bool $is_last Whether this is the last room (keeps table open for grand totals) * @return string HTML */ - private static function generate_room_section( $room_key, $room_label, $room_data ) { + private static function generate_room_section( $room_key, $room_label, $room_data, $is_last = false ) { $html = "
@@ -212,9 +254,6 @@ class Umzugsliste_Email_Generator { $room_total_quantity = 0; $room_total_cbm = 0; - // Process items in groups of v, q, m - $processed_items = array(); - foreach ( $room_data as $key => $value ) { if ( substr( $key, 0, 1 ) === 'v' ) { $item_name = substr( $key, 1 ); @@ -238,8 +277,6 @@ class Umzugsliste_Email_Generator { $html .= "'; $html .= ''; $html .= ''; - - $processed_items[] = $item_name; } } } @@ -254,165 +291,353 @@ class Umzugsliste_Email_Generator { "; + // Only close table if NOT the last room (last room stays open for grand totals) + if ( ! $is_last ) { + $html .= '
" . esc_html( $total_display ) . ' ' . esc_html( $montage ) . '
 
'; + } + + return $html; + } + + /** + * Get field key matching how form handler stores it + * + * @param array $field Field definition + * @return string Field key + */ + private static function get_field_key( $field ) { + if ( ! empty( $field['key'] ) ) { + return sanitize_key( $field['key'] ); + } + return sanitize_title( $field['name'] ); + } + + /** + * Get field value from submitted data + * + * @param array $section_data Submitted data for section + * @param array $field Field definition + * @return string Field value + */ + private static function get_field_value( $section_data, $field ) { + $key = self::get_field_key( $field ); + return $section_data[ $key ] ?? ''; + } + + /** + * Get _anzahl value for checkbox_anzahl fields + * + * @param array $section_data Submitted data for section + * @param array $field Field definition + * @return string Anzahl value + */ + private static function get_field_anzahl( $section_data, $field ) { + $key = self::get_field_key( $field ); + return $section_data[ $key . '_anzahl' ] ?? ''; + } + + /** + * Generate Weitere Arbeiten section as single 3-column table + * + * @param array $data Form data + * @return string HTML + */ + private static function generate_weitere_arbeiten( $data ) { + $additional_data = $data['additional_work'] ?? array(); + $sections = Umzugsliste_Furniture_Data::get_additional_work(); + + $html = "
+
+ + + + + + + + + "; + + $html .= self::generate_montage_rows( $additional_data['montage'] ?? array(), $sections['montage'] ); + $html .= self::generate_schrank_rows( $additional_data['schrank'] ?? array(), $sections['schrank'] ); + $html .= self::generate_elektriker_rows( $additional_data['elektriker'] ?? array(), $sections['elektriker'] ); + $html .= self::generate_duebelarbeiten_rows( $additional_data['duebelarbeiten'] ?? array(), $sections['duebelarbeiten'] ); + $html .= self::generate_packarbeiten_rows( $additional_data['packarbeiten'] ?? array(), $sections['packarbeiten'] ); + $html .= self::generate_anfahrt_rows( $additional_data['anfahrt'] ?? array(), $sections['anfahrt'] ); + + // anfahrt_rows closes the table + + return $html; + } + + /** + * Generate Montagearbeiten rows + * + * @param array $section_data Submitted data + * @param array $section_def Section field definitions + * @return string HTML rows + */ + private static function generate_montage_rows( $section_data, $section_def ) { + $html = " + + "; + + foreach ( $section_def['fields'] as $field ) { + $value = self::get_field_value( $section_data, $field ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + + return $html; + } + + /** + * Generate Schrank rows with Abbau/Aufbau columns + * + * @param array $section_data Submitted data + * @param array $section_def Section field definitions + * @return string HTML rows + */ + private static function generate_schrank_rows( $section_data, $section_def ) { + $html = " + + + + "; + + foreach ( $section_def['fields'] as $field ) { + $value = self::get_field_value( $section_data, $field ); + + $abbau = ' '; + $aufbau = ' '; + + if ( 'Abbau' === $value ) { + $abbau = 'X'; + } elseif ( 'Aufbau' === $value ) { + $aufbau = 'X'; + } elseif ( 'Beides' === $value ) { + $abbau = 'X'; + $aufbau = 'X'; + } + + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + + return $html; + } + + /** + * Generate Elektriker/Installateur rows + * + * @param array $section_data Submitted data + * @param array $section_def Section field definitions + * @return string HTML rows + */ + private static function generate_elektriker_rows( $section_data, $section_def ) { + $html = " + + + + "; + + foreach ( $section_def['fields'] as $field ) { + $value = self::get_field_value( $section_data, $field ); + $anzahl = self::get_field_anzahl( $section_data, $field ); + + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $anzahl_display = ! empty( $anzahl ) ? esc_html( $anzahl ) : ' '; + + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + + return $html; + } + + /** + * Generate Dübelarbeiten rows + * + * @param array $section_data Submitted data + * @param array $section_def Section field definitions + * @return string HTML rows + */ + private static function generate_duebelarbeiten_rows( $section_data, $section_def ) { + $html = " + + + + "; + + foreach ( $section_def['fields'] as $field ) { + $value = self::get_field_value( $section_data, $field ); + $anzahl = self::get_field_anzahl( $section_data, $field ); + + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $anzahl_display = ! empty( $anzahl ) ? esc_html( $anzahl ) : ' '; + + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + + return $html; + } + + /** + * Generate Packarbeiten rows with sub-headers + * + * @param array $section_data Submitted data + * @param array $section_def Section field definitions + * @return string HTML rows + */ + private static function generate_packarbeiten_rows( $section_data, $section_def ) { + $fields = $section_def['fields']; + + // Packarbeiten header + first 2 checkbox rows + $html = " + + "; + + for ( $i = 0; $i < 2 && $i < count( $fields ); $i++ ) { + $value = self::get_field_value( $section_data, $fields[ $i ] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + + // "Wir haben spezielle Packwünsche:" sub-header + next 2 checkbox rows + $html .= " + + "; + + for ( $i = 2; $i < 4 && $i < count( $fields ); $i++ ) { + $value = self::get_field_value( $section_data, $fields[ $i ] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + + // "Packmaterial" sub-header + 2 text quantity rows + $html .= " + + "; + + for ( $i = 4; $i < 6 && $i < count( $fields ); $i++ ) { + $value = self::get_field_value( $section_data, $fields[ $i ] ); + $value_display = ! empty( $value ) ? esc_html( $value ) : ' '; + + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + $html .= ''; + } + + return $html; + } + + /** + * Generate Anfahrt rows with nested sub-headers (also closes the table) + * + * @param array $section_data Submitted data + * @param array $section_def Section field definitions + * @return string HTML rows including table close + */ + private static function generate_anfahrt_rows( $section_data, $section_def ) { + $fields = $section_def['fields']; + + $html = " + + "; + + // "LKW kann direkt vor den Eingang fahren" sub-header + $html .= " + + "; + + // Beladestelle (field index 0) + $value = self::get_field_value( $section_data, $fields[0] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $html .= ''; + + // Entladestelle (field index 1) + $value = self::get_field_value( $section_data, $fields[1] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $html .= ''; + + // "Parkverbotsschilder aufstellen" sub-header + $html .= " + + "; + + // Beladestelle (field index 2) + $value = self::get_field_value( $section_data, $fields[2] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $html .= ''; + + // Entladestelle (field index 3) + $value = self::get_field_value( $section_data, $fields[3] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $html .= ''; + + // "Die Anfahrt ist eng bzw. nicht möglich" sub-header + $html .= " + + "; + + // Beladestelle (field index 4) + $value = self::get_field_value( $section_data, $fields[4] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $html .= ''; + + // Entladestelle (field index 5) + $value = self::get_field_value( $section_data, $fields[5] ); + $checked = ( 'ja' === $value ) ? 'X' : ' '; + $html .= ''; + + // "Abtrageweg" sub-header + $html .= " + + "; + + // Beladestelle distance (field index 6) - value in col3 + $value = self::get_field_value( $section_data, $fields[6] ); + $value_display = ! empty( $value ) ? esc_html( $value ) : ' '; + $html .= ''; + + // Entladestelle distance (field index 7) - value in col3, also closes table + $value = self::get_field_value( $section_data, $fields[7] ); + $value_display = ! empty( $value ) ? esc_html( $value ) : ' '; + $html .= ''; + + // Close the Weitere Arbeiten table $html .= '
Weitere Arbeiten (bitte ankreuzen)  
Montagearbeiten
' . esc_html( $field['name'] ) . '' . $checked . ' 
SchrankAbbauAufbau
' . esc_html( $field['name'] ) . '' . $abbau . '' . $aufbau . '
Elektriker/Installateur Anzahl
' . esc_html( $field['name'] ) . '' . $checked . '' . $anzahl_display . '
Dübelarbeiten Anzahl
' . esc_html( $field['name'] ) . '' . $checked . '' . $anzahl_display . '
Packarbeiten
' . esc_html( $fields[ $i ]['name'] ) . '' . $checked . ' 
Wir haben spezielle Packwünsche:
' . esc_html( $fields[ $i ]['name'] ) . '' . $checked . ' 
Packmaterial
' . esc_html( $fields[ $i ]['name'] ) . ' ' . $value_display . '
Anfahrt
LKW kann direkt vor den Eingang fahren
Beladestelle' . $checked . ' 
Entladestelle' . $checked . ' 
Parkverbotsschilder aufstellen
Beladestelle' . $checked . ' 
Entladestelle' . $checked . ' 
Die Anfahrt ist eng bzw. nicht möglich
Beladestelle' . $checked . ' 
Entladestelle' . $checked . ' 
Abtrageweg
Beladestelle Wegstrecke Haus-LKW in Meter ' . $value_display . '
Entladestelle Wegstrecke LKW-Haus in Meter ' . $value_display . '
'; return $html; } - /** - * Generate grand totals section - * - * @param array $data Form data - * @return string HTML - */ - private static function generate_grand_totals( $data ) { - $grand_total_quantity = 0; - $grand_total_cbm = 0; - - $rooms = Umzugsliste_Furniture_Data::get_rooms(); - - foreach ( $rooms as $room_key => $room_label ) { - $post_array_name = ucfirst( $room_key ); - if ( 'kueche_esszimmer' === $room_key ) { - $post_array_name = 'Kueche_Esszimmer'; - } - - $room_data = $data[ $post_array_name ] ?? array(); - - foreach ( $room_data as $key => $value ) { - if ( substr( $key, 0, 1 ) === 'v' && ! empty( $value ) && floatval( $value ) > 0 ) { - $item_name = substr( $key, 1 ); - $quantity = floatval( str_replace( ',', '.', trim( $value ) ) ); - $cbm = isset( $room_data[ 'q' . $item_name ] ) ? floatval( $room_data[ 'q' . $item_name ] ) : 0; - - $grand_total_quantity += $quantity; - $grand_total_cbm += ( $quantity * $cbm ); - } - } - } - - $grand_total_display = str_replace( '.', ',', number_format( $grand_total_cbm, 2, '.', '' ) ); - - return "  - - " . $grand_total_quantity . " - Gesamtsummen - " . esc_html( $grand_total_display ) . " -   - "; - } - - /** - * Generate additional work sections - * - * @param array $data Form data - * @return string HTML - */ - private static function generate_additional_work_sections( $data ) { - $html = ''; - $sections = Umzugsliste_Furniture_Data::get_additional_work(); - - foreach ( $sections as $section_key => $section_data ) { - // Only include section if it has data - if ( self::has_additional_work_data( $data, $section_key ) ) { - $html .= "
-
- - - - - - - "; - - $section_submitted_data = $data['additional_work'][ $section_key ] ?? array(); - - foreach ( $section_data['fields'] as $field ) { - // Get field key - $field_key = ! empty( $field['key'] ) ? $field['key'] : sanitize_title( $field['name'] ); - - // Get field value - $field_value = $section_submitted_data[ $field_key ] ?? ''; - - // Render based on field type - switch ( $field['type'] ) { - case 'checkbox': - if ( 'ja' === $field_value ) { - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - } - break; - - case 'abbau_aufbau': - if ( ! empty( $field_value ) ) { - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - } - break; - - case 'checkbox_anzahl': - if ( 'ja' === $field_value ) { - $anzahl_value = $section_submitted_data[ $field_key . '_anzahl' ] ?? ''; - $display_value = 'Ja'; - if ( ! empty( $anzahl_value ) ) { - $display_value .= ' (Anzahl: ' . esc_html( $anzahl_value ) . ')'; - } - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - } - break; - - case 'text': - if ( ! empty( $field_value ) ) { - $html .= ''; - $html .= ''; - $html .= ''; - $html .= ''; - } - break; - } - } - - $html .= '
" . esc_html( $section_data['label'] ) . "
' . esc_html( $field['name'] ) . 'Ja
' . esc_html( $field['name'] ) . '' . esc_html( $field_value ) . '
' . esc_html( $field['name'] ) . '' . $display_value . '
' . esc_html( $field['name'] ) . '' . esc_html( $field_value ) . '
'; - } - } - - return $html; - } - - /** - * Check if section has any data - * - * @param array $data Form data - * @param string $section_key Section key - * @return bool True if has data - */ - private static function has_additional_work_data( $data, $section_key ) { - if ( empty( $data['additional_work'][ $section_key ] ) ) { - return false; - } - - $section_data = $data['additional_work'][ $section_key ]; - if ( ! is_array( $section_data ) ) { - return false; - } - - // Check if any value is non-empty - foreach ( $section_data as $value ) { - if ( ! empty( trim( $value ) ) ) { - return true; - } - } - - return false; - } - /** * Generate Sonstiges section * @@ -448,7 +673,7 @@ class Umzugsliste_Email_Generator { return " - Siegel Umzüge - Internetanfrage + Siegel-Umzug " . $content . "