From 0f5d575cb9d67cc71c2ad6321f56686b30969aed Mon Sep 17 00:00:00 2001 From: Blitz08 Date: Mon, 2 Mar 2026 12:49:37 +0100 Subject: [PATCH] Improve workshop minimum participant handling and reassignment logic --- includes/zuteilungslogik.php | 142 +++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 40 deletions(-) diff --git a/includes/zuteilungslogik.php b/includes/zuteilungslogik.php index d6db63d..c027878 100644 --- a/includes/zuteilungslogik.php +++ b/includes/zuteilungslogik.php @@ -131,82 +131,144 @@ function kc_run_zuteilung($wahl_id) { $assign($tn, $ws_id, 99); } - // 6.5 Consolidate workshops that did not reach their minimal Teilnehmerzahl - // Load minimal requirements for workshops in this Wahl + // 6.5 Verbesserte Mindestanzahl-Sicherung: Unterbesetzte Workshops auflösen $ws_ids_in_wahl = array_keys($workshops); if (!empty($ws_ids_in_wahl)) { + + // min_teilnehmer laden (einmalig) $placeholders = implode(',', array_fill(0, count($ws_ids_in_wahl), '%d')); - $min_rows = $wpdb->get_results($wpdb->prepare("SELECT id, min_teilnehmer FROM {$prefix}kc_workshops WHERE id IN ($placeholders)", $ws_ids_in_wahl)); + $min_rows = $wpdb->get_results($wpdb->prepare( + "SELECT id, min_teilnehmer FROM {$prefix}kc_workshops WHERE id IN ($placeholders)", + $ws_ids_in_wahl + )); $min_map = []; - foreach($min_rows as $r) $min_map[intval($r->id)] = intval($r->min_teilnehmer); + foreach($min_rows as $r) { + $min_map[intval($r->id)] = intval($r->min_teilnehmer); + } + + // Aktuelle Belegung zählen + $assigned_counts_raw = $wpdb->get_results($wpdb->prepare( + "SELECT workshop_id, COUNT(*) AS cnt + FROM {$prefix}kc_zuteilung + WHERE wahl_id=%d AND phase=%d AND workshop_id IS NOT NULL + GROUP BY workshop_id", + $wahl_id, $phase + ), 'ARRAY_A'); - // Count current assignments per workshop - $assigned_counts_raw = $wpdb->get_results($wpdb->prepare("SELECT workshop_id, COUNT(*) AS cnt FROM {$prefix}kc_zuteilung WHERE wahl_id=%d AND phase=%d AND workshop_id IS NOT NULL GROUP BY workshop_id", $wahl_id, $phase), ARRAY_A); $assigned_counts = []; - foreach($assigned_counts_raw as $ar) $assigned_counts[intval($ar['workshop_id'])] = intval($ar['cnt']); + foreach($assigned_counts_raw as $ar) { + $assigned_counts[intval($ar['workshop_id'])] = intval($ar['cnt']); + } - // Find failing workshops (assigned >0 but < min) + $assigned_counts = []; + foreach($assigned_counts_raw as $ar) { + $assigned_counts[intval($ar['workshop_id'])] = intval($ar['cnt']); + } + + // Unterbesetzte Workshops finden (mit Zuweisung > 0 aber < min) $failing = []; foreach($ws_ids_in_wahl as $wsid) { - $min_req = intval($min_map[$wsid] ?? 0); - $cnt = intval($assigned_counts[$wsid] ?? 0); - if ($cnt > 0 && $min_req > 0 && $cnt < $min_req) { + $min_req = $min_map[$wsid] ?? 0; + $cnt = $assigned_counts[$wsid] ?? 0; + if ($min_req > 0 && $cnt < $min_req) { // ← auch wenn cnt == 0 ! $failing[] = $wsid; } } + // ──────────────── WICHTIGE DIAGNOSE ──────────────── + error_log("=== DIAGNOSE Mindestanzahl Phase $phase ==="); + error_log("Workshops insgesamt: " . count($ws_ids_in_wahl)); + foreach ($ws_ids_in_wahl as $wsid) { + $name = $workshops[$wsid]->name ?? 'ID '.$wsid; + $min = $min_map[$wsid] ?? 0; + $cnt = $assigned_counts[$wsid] ?? 0; + $cap = $caps[$wsid] ?? 'unbekannt'; + $status = ($min > 0 && $cnt > 0 && $cnt < $min) ? 'UNTER MIN → wird umverteilt' : + (($min > 0 && $cnt >= $min) ? 'OK' : + ($cnt == 0 ? 'leer (ignoriert)' : 'keine min-Anforderung')); + error_log("WS $wsid ($name) | min=$min | jetzt=$cnt | Restkap=$cap | $status"); + } + error_log("Anzahl failing Workshops: " . count($failing)); if (!empty($failing)) { - // collect participants from failing workshops + error_log("Umverteilung startet für WS: " . implode(', ', $failing)); + } else { + error_log("Keine Workshops unter Mindestanzahl mit Teilnehmern → nichts zu tun"); + } + error_log("============================"); + + if (!empty($failing)) { + error_log("Phase $phase: Folgende Workshops unter Mindestanzahl → Teilnehmer werden umverteilt: " . implode(', ', $failing)); + + // Alle betroffenen Teilnehmer sammeln $to_reassign = []; foreach($failing as $fw) { - $rows = $wpdb->get_results($wpdb->prepare("SELECT teilnehmer_id FROM {$prefix}kc_zuteilung WHERE wahl_id=%d AND phase=%d AND workshop_id=%d", $wahl_id, $phase, $fw)); - foreach($rows as $r) $to_reassign[] = intval($r->teilnehmer_id); + $rows = $wpdb->get_results($wpdb->prepare( + "SELECT teilnehmer_id FROM {$prefix}kc_zuteilung + WHERE wahl_id=%d AND phase=%d AND workshop_id=%d", + $wahl_id, $phase, $fw + )); + foreach($rows as $r) { + $to_reassign[] = intval($r->teilnehmer_id); + } } if (!empty($to_reassign)) { - // remove those assignments - $fw_placeholders = implode(',', array_map('intval', $failing)); - $wpdb->query("DELETE FROM {$prefix}kc_zuteilung WHERE wahl_id=".intval($wahl_id)." AND phase=".intval($phase)." AND workshop_id IN ($fw_placeholders)"); + // Alte Zuweisungen löschen + $fw_list = implode(',', array_map('intval', $failing)); + $wpdb->query("DELETE FROM {$prefix}kc_zuteilung + WHERE wahl_id = " . intval($wahl_id) . " + AND phase = " . intval($phase) . " + AND workshop_id IN ($fw_list)"); - // free capacity for the failing workshops + // Kapazitäten wieder freigeben foreach($failing as $fw) { - $freed = intval($assigned_counts[$fw] ?? 0); - if (!isset($caps[$fw])) $caps[$fw] = 0; - $caps[$fw] += $freed; + $freed = $assigned_counts[$fw] ?? 0; + $caps[$fw] = ($caps[$fw] ?? 0) + $freed; } - // Try to reassign each participant preferring their wishes 1..3 + // Teilnehmer erneut versuchen zuzuweisen – zuerst Wünsche, dann Rest foreach($to_reassign as $tid) { - $tn = isset($all_teilnehmer_by_id[$tid]) ? $all_teilnehmer_by_id[$tid] : $wpdb->get_row($wpdb->prepare("SELECT * FROM {$prefix}kc_teilnehmer WHERE id=%d", $tid)); + $tn = $all_teilnehmer_by_id[$tid] ?? $wpdb->get_row($wpdb->prepare( + "SELECT * FROM {$prefix}kc_teilnehmer WHERE id = %d", $tid + )); if (!$tn) continue; + $reassigned = false; - for($w=1;$w<=3;$w++) { + + // Nochmal Wunsch 1–3 versuchen + for($w = 1; $w <= 3; $w++) { $choice = intval($tn->{"wunsch$w"}); if ($choice > 0 && isset($caps[$choice]) && $caps[$choice] > 0) { - $assigned = $assign($tn, $choice, $w); - if ($assigned) { $reassigned = true; break; } + if ($assign($tn, $choice, $w)) { + $reassigned = true; + break; + } } } + if ($reassigned) continue; - // otherwise assign to any workshop with free capacity - $available = array_keys(array_filter($caps, function($c){return $c>0;})); + // Falls kein Wunsch frei → irgendein freier Workshop + $available = array_keys(array_filter($caps, fn($c) => $c > 0)); if (!empty($available)) { $target = $available[array_rand($available)]; - $assign($tn, $target, 99); - continue; + if ($assign($tn, $target, 99)) { + $reassigned = true; + } } - // lastly, mark as unassigned - $wpdb->insert("{$prefix}kc_zuteilung", [ - 'wahl_id' => $wahl_id, - 'teilnehmer_id' => $tn->id, - 'vorname' => $tn->vorname, - 'nachname' => $tn->nachname, - 'phase' => $phase, - 'workshop_id' => null, - 'wunsch_rang' => -1 - ]); + // Wenn immer noch nichts frei → unassigned + if (!$reassigned) { + $wpdb->insert("{$prefix}kc_zuteilung", [ + 'wahl_id' => $wahl_id, + 'teilnehmer_id' => $tn->id, + 'vorname' => $tn->vorname, + 'nachname' => $tn->nachname, + 'phase' => $phase, + 'workshop_id' => null, + 'wunsch_rang' => -1 + ]); + } } } }