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 .= "| " . esc_html( $total_display ) . ' | ';
$html .= ' ' . esc_html( $montage ) . ' | ';
$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 .= '
';
+ }
+
+ 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 = "
+
+
+
+
+ | Weitere Arbeiten (bitte ankreuzen) |
+ |
+ |
+
+
+ ";
+
+ $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 = "
+ | Montagearbeiten |
+
";
+
+ foreach ( $section_def['fields'] as $field ) {
+ $value = self::get_field_value( $section_data, $field );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+
+ $html .= '';
+ $html .= '| ' . esc_html( $field['name'] ) . ' | ';
+ $html .= '' . $checked . ' | ';
+ $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 = "
+ | Schrank |
+ Abbau |
+ Aufbau |
+
";
+
+ 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 .= '| ' . esc_html( $field['name'] ) . ' | ';
+ $html .= '' . $abbau . ' | ';
+ $html .= '' . $aufbau . ' | ';
+ $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 = "
+ | Elektriker/Installateur |
+ |
+ Anzahl |
+
";
+
+ 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 .= '| ' . esc_html( $field['name'] ) . ' | ';
+ $html .= '' . $checked . ' | ';
+ $html .= '' . $anzahl_display . ' | ';
+ $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 = "
+ | Dübelarbeiten |
+ |
+ Anzahl |
+
";
+
+ 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 .= '| ' . esc_html( $field['name'] ) . ' | ';
+ $html .= '' . $checked . ' | ';
+ $html .= '' . $anzahl_display . ' | ';
+ $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 = "
+ | Packarbeiten |
+
";
+
+ for ( $i = 0; $i < 2 && $i < count( $fields ); $i++ ) {
+ $value = self::get_field_value( $section_data, $fields[ $i ] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+
+ $html .= '';
+ $html .= '| ' . esc_html( $fields[ $i ]['name'] ) . ' | ';
+ $html .= '' . $checked . ' | ';
+ $html .= ' | ';
+ $html .= '
';
+ }
+
+ // "Wir haben spezielle Packwünsche:" sub-header + next 2 checkbox rows
+ $html .= "
+ | Wir haben spezielle Packwünsche: |
+
";
+
+ for ( $i = 2; $i < 4 && $i < count( $fields ); $i++ ) {
+ $value = self::get_field_value( $section_data, $fields[ $i ] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+
+ $html .= '';
+ $html .= '| ' . esc_html( $fields[ $i ]['name'] ) . ' | ';
+ $html .= '' . $checked . ' | ';
+ $html .= ' | ';
+ $html .= '
';
+ }
+
+ // "Packmaterial" sub-header + 2 text quantity rows
+ $html .= "
+ | Packmaterial |
+
";
+
+ 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 .= '| ' . esc_html( $fields[ $i ]['name'] ) . ' | ';
+ $html .= ' | ';
+ $html .= '' . $value_display . ' | ';
+ $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 = "
+ | Anfahrt |
+
";
+
+ // "LKW kann direkt vor den Eingang fahren" sub-header
+ $html .= "
+ | LKW kann direkt vor den Eingang fahren |
+
";
+
+ // Beladestelle (field index 0)
+ $value = self::get_field_value( $section_data, $fields[0] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+ $html .= '| Beladestelle | ' . $checked . ' | |
';
+
+ // Entladestelle (field index 1)
+ $value = self::get_field_value( $section_data, $fields[1] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+ $html .= '| Entladestelle | ' . $checked . ' | |
';
+
+ // "Parkverbotsschilder aufstellen" sub-header
+ $html .= "
+ | Parkverbotsschilder aufstellen |
+
";
+
+ // Beladestelle (field index 2)
+ $value = self::get_field_value( $section_data, $fields[2] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+ $html .= '| Beladestelle | ' . $checked . ' | |
';
+
+ // Entladestelle (field index 3)
+ $value = self::get_field_value( $section_data, $fields[3] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+ $html .= '| Entladestelle | ' . $checked . ' | |
';
+
+ // "Die Anfahrt ist eng bzw. nicht möglich" sub-header
+ $html .= "
+ | Die Anfahrt ist eng bzw. nicht möglich |
+
";
+
+ // Beladestelle (field index 4)
+ $value = self::get_field_value( $section_data, $fields[4] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+ $html .= '| Beladestelle | ' . $checked . ' | |
';
+
+ // Entladestelle (field index 5)
+ $value = self::get_field_value( $section_data, $fields[5] );
+ $checked = ( 'ja' === $value ) ? 'X' : ' ';
+ $html .= '| Entladestelle | ' . $checked . ' | |
';
+
+ // "Abtrageweg" sub-header
+ $html .= "
+ | Abtrageweg |
+
";
+
+ // 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 .= '| Beladestelle Wegstrecke Haus-LKW in Meter | | ' . $value_display . ' |
';
+
+ // 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 .= '| Entladestelle Wegstrecke LKW-Haus in Meter | | ' . $value_display . ' |
';
+
+ // Close the Weitere Arbeiten table
$html .= '
';
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 .= "
-
-
-
-
- | " . esc_html( $section_data['label'] ) . " |
-
-
- ";
-
- $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 .= '| ' . esc_html( $field['name'] ) . ' | ';
- $html .= 'Ja | ';
- $html .= '
';
- }
- break;
-
- case 'abbau_aufbau':
- if ( ! empty( $field_value ) ) {
- $html .= '';
- $html .= '| ' . esc_html( $field['name'] ) . ' | ';
- $html .= '' . esc_html( $field_value ) . ' | ';
- $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 .= '| ' . esc_html( $field['name'] ) . ' | ';
- $html .= '' . $display_value . ' | ';
- $html .= '
';
- }
- break;
-
- case 'text':
- if ( ! empty( $field_value ) ) {
- $html .= '';
- $html .= '| ' . esc_html( $field['name'] ) . ' | ';
- $html .= '' . esc_html( $field_value ) . ' | ';
- $html .= '
';
- }
- break;
- }
- }
-
- $html .= '
';
- }
- }
-
- 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 . "