diff --git a/src/add_packing_list.php b/src/add_packing_list.php index 05c3085..c456d6d 100644 --- a/src/add_packing_list.php +++ b/src/add_packing_list.php @@ -1,6 +1,6 @@ prepare("SELECT id, username FROM users WHERE household_id = ?"); $stmt_u->bind_param("i", $household_id_for_user); } else { - // Just the current user $stmt_u = $conn->prepare("SELECT id, username FROM users WHERE id = ?"); $stmt_u->bind_param("i", $current_user_id); } @@ -48,8 +47,28 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") { $description = trim($_POST['description']); $household_id = isset($_POST['is_household_list']) && $household_id_for_user ? $household_id_for_user : NULL; + // Server-Side Validation for duplicate backpacks + $selected_backpacks = []; + $has_duplicate_backpacks = false; + if (isset($_POST['participate']) && is_array($_POST['participate'])) { + foreach ($_POST['participate'] as $uid => $val) { + if ($val) { + $bid = isset($_POST['backpacks'][$uid]) ? intval($_POST['backpacks'][$uid]) : 0; + if ($bid > 0) { + if (in_array($bid, $selected_backpacks)) { + $has_duplicate_backpacks = true; + break; + } + $selected_backpacks[] = $bid; + } + } + } + } + if (empty($name)) { $message = ''; + } elseif ($has_duplicate_backpacks) { + $message = ''; } else { $stmt = $conn->prepare("INSERT INTO packing_lists (user_id, household_id, name, description) VALUES (?, ?, ?, ?)"); if ($stmt === false) { @@ -59,19 +78,11 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") { if ($stmt->execute()) { $new_list_id = $conn->insert_id; - // Handle Backpacks and Participation if (isset($_POST['participate']) && is_array($_POST['participate'])) { foreach ($_POST['participate'] as $uid => $val) { $uid = intval($uid); - // Only add if checked (value is usually '1') if ($val) { $bid = isset($_POST['backpacks'][$uid]) ? intval($_POST['backpacks'][$uid]) : 0; - - // Insert Carrier (even if no backpack is assigned, they are a carrier on the list) - // But DB schema: packing_list_carriers links user to list. Backpack is optional. - // If we want them on the list, we insert. - - // Check if $bid is valid (>0) $bid_to_insert = ($bid > 0) ? $bid : NULL; $stmt_in = $conn->prepare("INSERT INTO packing_list_carriers (packing_list_id, user_id, backpack_id) VALUES (?, ?, ?)"); @@ -84,10 +95,6 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") { } } } - } else { - // If no array (e.g. single user form without checkboxes?), usually we force current user? - // Or assume no one selected. Let's ensure Current User is added if not explicitly unchecked? - // Actually, the UI below will default to checked for everyone. } if ($household_id_for_user) { @@ -117,7 +124,7 @@ require_once 'header.php';
-
+
@@ -142,17 +149,18 @@ require_once 'header.php';

Wähle aus, wer mitkommt und wer welchen Rucksack trägt.

+
+ Achtung: Ein Rucksack wurde mehrfach ausgewählt! +
$current_bp_id, 'backpacks' => $user_backpacks @@ -160,32 +168,103 @@ require_once 'header.php'; ?>
- +
+ -
-
- -
-
-
-
- -
- -
- - Abbrechen -
-
+ + + + + + +
+ +
+ + Abbrechen +
+ + + + + + + + - - - - + \ No newline at end of file diff --git a/src/backpacks.php b/src/backpacks.php index 75cbbe4..4e13ee7 100644 --- a/src/backpacks.php +++ b/src/backpacks.php @@ -33,7 +33,6 @@ if (isset($_POST['delete_backpack_id'])) { } // Fetch Backpacks (Personal + Household) -// Logic: Show my backpacks AND backpacks from my household (if I'm in one) $household_id = null; $stmt_hh = $conn->prepare("SELECT household_id FROM users WHERE id = ?"); $stmt_hh->bind_param("i", $user_id); @@ -44,6 +43,11 @@ if ($row = $res_hh->fetch_assoc()) { } $backpacks = []; +// AUTO-MIGRATION: Check if product_url column exists (just to be safe for display) +// Ideally handled in edit_backpack but good to be safe. +$check_col = $conn->query("SHOW COLUMNS FROM backpacks LIKE 'product_url'"); +$has_product_url = ($check_col && $check_col->num_rows > 0); + $sql = "SELECT b.*, u.username as owner_name FROM backpacks b JOIN users u ON b.user_id = u.id @@ -65,7 +69,6 @@ $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) { $backpacks[] = $row; } - ?>
@@ -112,7 +115,6 @@ while ($row = $result->fetch_assoc()) { prepare("SELECT COUNT(*) as cnt FROM backpack_compartments WHERE backpack_id = ?"); $stmt_c->bind_param("i", $bp['id']); $stmt_c->execute(); @@ -121,16 +123,24 @@ while ($row = $result->fetch_assoc()) {

Fächer definiert

- @@ -140,4 +150,4 @@ while ($row = $result->fetch_assoc()) { - + \ No newline at end of file diff --git a/src/packing_list_detail.php b/src/packing_list_detail.php index 8bb9270..ec3653c 100644 --- a/src/packing_list_detail.php +++ b/src/packing_list_detail.php @@ -1,6 +1,6 @@ close(); $page_title = "Packliste: " . htmlspecialchars($packing_list['name']); -// Robust SQL: Fetches names from Backpacks/Compartments if article is missing -// FIX: Include backpack own weight in weight_grams calculation $sql = "SELECT pli.id, pli.quantity, pli.parent_packing_list_item_id, pli.carrier_user_id, pli.backpack_id, pli.backpack_compartment_id, @@ -67,7 +68,8 @@ $sql = "SELECT a.image_url, a.product_designation, a.consumable, c.name AS category_name, m.name AS manufacturer_name, - u.username AS carrier_name + u.username AS carrier_name, + u.id AS carrier_id FROM packing_list_items AS pli LEFT JOIN articles AS a ON pli.article_id = a.id LEFT JOIN backpacks AS bp ON pli.backpack_id = bp.id @@ -87,9 +89,6 @@ $items_by_id = []; $items_by_parent = []; while ($row = $result->fetch_assoc()) { - // Fix Names for Display: Removed redundant prefix logic - // if ($row['backpack_id']) $row['article_name'] = "Rucksack: " . $row['article_name']; - $items_by_id[$row['id']] = $row; $parent_id = $row['parent_packing_list_item_id'] ?: 0; if (!isset($items_by_parent[$parent_id])) { @@ -102,6 +101,9 @@ while ($row = $result->fetch_assoc()) { $total_weight_grams += $item_weight; $carrier_name = $row['carrier_name'] ?: 'Sonstiges'; + $carrier_id = $row['carrier_id'] ?: 0; + + // Init stats arrays if (!isset($weight_by_carrier[$carrier_name])) $weight_by_carrier[$carrier_name] = 0; $weight_by_carrier[$carrier_name] += $item_weight; @@ -115,13 +117,33 @@ while ($row = $result->fetch_assoc()) { if (!isset($weight_by_carrier_non_consumable[$carrier_name])) $weight_by_carrier_non_consumable[$carrier_name] = 0; $weight_by_carrier_non_consumable[$carrier_name] += $item_weight; } + + // Prepare Detailed Stats per Carrier for Modal + if (!isset($carrier_stats_details[$carrier_name])) { + $carrier_stats_details[$carrier_name] = [ + 'total_weight' => 0, + 'base_weight' => 0, + 'consumable_weight' => 0, + 'categories' => [] + ]; + } + $carrier_stats_details[$carrier_name]['total_weight'] += $item_weight; + if ($row['consumable']) { + $carrier_stats_details[$carrier_name]['consumable_weight'] += $item_weight; + } else { + $carrier_stats_details[$carrier_name]['base_weight'] += $item_weight; + } + if (!isset($carrier_stats_details[$carrier_name]['categories'][$cat_name])) { + $carrier_stats_details[$carrier_name]['categories'][$cat_name] = 0; + } + $carrier_stats_details[$carrier_name]['categories'][$cat_name] += $item_weight; } $stmt->close(); $conn->close(); $total_weight_without_consumables = $total_weight_grams - $total_consumable_weight; -// Helper for recursive counting +// Helper functions (same as before) function get_recursive_quantity($parent_id, $items_by_parent) { $count = 0; if (isset($items_by_parent[$parent_id])) { @@ -133,41 +155,35 @@ function get_recursive_quantity($parent_id, $items_by_parent) { return $count; } -// Helper for recursive weight calculation function get_recursive_weight($parent_id, $items_by_parent) { $weight = 0; if (isset($items_by_parent[$parent_id])) { foreach ($items_by_parent[$parent_id] as $child) { - // Child weight $weight += ($child['quantity'] * $child['weight_grams']); - // Plus its descendants $weight += get_recursive_weight($child['id'], $items_by_parent); } } return $weight; } -// Recursive Rendering function render_item_row($item, $level, $items_by_parent) { $has_children = isset($items_by_parent[$item['id']]); $is_backpack = !empty($item['backpack_id']); $is_compartment = !empty($item['backpack_compartment_id']); - // Visual Styles $bg_class = ""; $text_class = ""; $icon = ""; if ($is_backpack) { - $bg_class = "table-success"; // Greenish for Backpack + $bg_class = "table-success"; $text_class = "fw-bold text-uppercase"; $icon = ''; } elseif ($is_compartment) { - $bg_class = "table-light"; // Light gray for Compartment + $bg_class = "table-light"; $text_class = "fw-bold fst-italic text-muted"; $icon = ''; } else { - // Standard Item $img_src = !empty($item['image_url']) ? htmlspecialchars($item['image_url']) : 'assets/images/keinbild.png'; $icon = ''; } @@ -175,16 +191,12 @@ function render_item_row($item, $level, $items_by_parent) { $indent_px = $level * 25; $weight_display = $item['weight_grams'] > 0 ? number_format($item['weight_grams'], 0, ',', '.') . ' g' : '-'; - // Calculate Total Weight display logic $total_weight_val = 0; if ($is_backpack || $is_compartment) { - // For containers: Recursive weight of children - // For backpacks specifically: Add own weight + children $children_weight = get_recursive_weight($item['id'], $items_by_parent); - $own_weight = $item['quantity'] * $item['weight_grams']; // Usually 1 * empty_weight + $own_weight = $item['quantity'] * $item['weight_grams']; $total_weight_val = $own_weight + $children_weight; } else { - // Standard items $total_weight_val = $item['weight_grams'] * $item['quantity']; } @@ -192,13 +204,10 @@ function render_item_row($item, $level, $items_by_parent) { echo ''; - // Name Column with Indentation echo ''; echo '
'; - // Tree Toggle or Spacer if ($has_children) { - // Explicitly style the button echo ''; } else { echo ''; @@ -209,26 +218,20 @@ function render_item_row($item, $level, $items_by_parent) { echo '
'; echo ''; - // Other Columns echo '' . ($item['consumable'] ? '' : '') . ''; echo '' . htmlspecialchars($item['manufacturer_name'] ?: '') . ''; echo '' . htmlspecialchars($item['product_designation'] ?: '') . ''; echo '' . htmlspecialchars($item['category_name'] ?: '') . ''; - // Quantity / Child Count Badge echo ''; if ($is_backpack) { - // Rucksack: Keine Summe anzeigen (User Wunsch) echo ''; } elseif ($is_compartment) { - // Fächer: Rekursive Summe aller enthaltenen Artikel $total_items = get_recursive_quantity($item['id'], $items_by_parent); if ($total_items > 0) { - // Grün, aber gleiche Form wie Standard (kein rounded-pill) echo '' . $total_items . ''; } } else { - // Standard Artikel Menge echo '' . $item['quantity'] . 'x'; } echo ''; @@ -244,15 +247,6 @@ function render_item_row($item, $level, $items_by_parent) { } } } - -function render_print_table_rows($items, $level = 0) { - foreach($items as $item) { - // Simulate structure for print function which might expect different array format? - // Actually, this function is called below with items from $sorted_items_by_carrier which likely won't work - // because we rewrote the main fetching logic to flattened array $items_by_parent. - // We need to adapt the print view section below to use $items_by_parent logic. - } -} ?> @@ -294,7 +288,6 @@ function render_print_table_rows($items, $level = 0) { Liste ist leer. $roots): ?> - + + + + + (Klicken für Statistik) + +
nach Träger
-
Gewicht nach Kategorie
@@ -366,8 +364,29 @@ function render_print_table_rows($items, $level = 0) {
+ + +
+