Implement iterative minimum participant checks for workshop assignments
All checks were successful
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Successful in 12s
All checks were successful
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Successful in 12s
This commit is contained in:
@@ -144,9 +144,14 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
$assign($tn, $ws_id, 99);
|
$assign($tn, $ws_id, 99);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6.5 NEUE LOGIK: NACH Zufallsverteilung Minimalanzahlen überprüfen
|
// 6.5 ITERATIVE MINIMALANZAHL-SICHERUNG: Bis alle erfüllt sind
|
||||||
// Unterbesetzte Workshops auflösen und TN nur auf "sichere" Workshops verteilen
|
|
||||||
$ws_ids_in_wahl = array_keys($workshops);
|
$ws_ids_in_wahl = array_keys($workshops);
|
||||||
|
$iteration = 0;
|
||||||
|
$max_iterations = 10;
|
||||||
|
|
||||||
|
while($iteration < $max_iterations) {
|
||||||
|
$iteration++;
|
||||||
|
error_log("Phase $phase: Minimalanzahl-Check Iteration $iteration");
|
||||||
|
|
||||||
if (!empty($ws_ids_in_wahl)) {
|
if (!empty($ws_ids_in_wahl)) {
|
||||||
// Aktuelle Belegung zählen
|
// Aktuelle Belegung zählen
|
||||||
@@ -163,31 +168,23 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
$assigned_counts[intval($ar['workshop_id'])] = intval($ar['cnt']);
|
$assigned_counts[intval($ar['workshop_id'])] = intval($ar['cnt']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────── DIAGNOSE VOR UMVERTEILUNG ───────────────
|
// Unterbesetzte Workshops finden (NUR die mit Teilnehmern, aber < min)
|
||||||
error_log("=== DIAGNOSE Mindestanzahl Phase $phase (VOR Umverteilung) ===");
|
|
||||||
foreach ($ws_ids_in_wahl as $wsid) {
|
|
||||||
$name = $workshops[$wsid]->name ?? 'ID '.$wsid;
|
|
||||||
$min = $min_map[$wsid] ?? 0;
|
|
||||||
$cnt = $assigned_counts[$wsid] ?? 0;
|
|
||||||
$status = ($min > 0 && $cnt > 0 && $cnt < $min) ? 'UNTER MIN → wird umverteilt' :
|
|
||||||
(($min > 0 && $cnt >= $min) ? 'OK ✓' : ($cnt == 0 ? 'leer' : 'OK (kein Min)'));
|
|
||||||
error_log("WS $wsid ($name) | min=$min | TN=$cnt | $status");
|
|
||||||
}
|
|
||||||
error_log("============================");
|
|
||||||
|
|
||||||
// Unterbesetzte Workshops finden
|
|
||||||
$failing = [];
|
$failing = [];
|
||||||
foreach($ws_ids_in_wahl as $wsid) {
|
foreach($ws_ids_in_wahl as $wsid) {
|
||||||
$min_req = $min_map[$wsid] ?? 0;
|
$min_req = $min_map[$wsid] ?? 0;
|
||||||
$cnt = $assigned_counts[$wsid] ?? 0;
|
$cnt = $assigned_counts[$wsid] ?? 0;
|
||||||
// Workshop ist unterbesetzt wenn: er hat Teilnehmer, aber weniger als Minimum
|
|
||||||
if ($min_req > 0 && $cnt > 0 && $cnt < $min_req) {
|
if ($min_req > 0 && $cnt > 0 && $cnt < $min_req) {
|
||||||
$failing[] = $wsid;
|
$failing[] = $wsid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($failing)) {
|
if (empty($failing)) {
|
||||||
error_log("Phase $phase: Workshops UNTER Mindestanzahl: " . implode(', ', $failing) . " → Umverteilung startet");
|
// Alle erfüllt!
|
||||||
|
error_log("Phase $phase: ✓ Alle Workshops erfüllen ihre Minimalanzahl (Iteration $iteration)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log("Phase $phase [Iter $iteration]: $" . count($failing) . " Workshops UNTER Mindestanzahl → umverteilen");
|
||||||
|
|
||||||
// Alle TN aus unterbesetzten Workshops sammeln
|
// Alle TN aus unterbesetzten Workshops sammeln
|
||||||
$to_reassign = [];
|
$to_reassign = [];
|
||||||
@@ -202,10 +199,15 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($to_reassign)) {
|
if (empty($to_reassign)) {
|
||||||
error_log("Phase $phase: " . count($to_reassign) . " Teilnehmer werden umverteilt");
|
// Keine TN zu umverteilen
|
||||||
|
error_log("Phase $phase [Iter $iteration]: Keine Teilnehmer in unterbesetzten Workshops gefunden");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Alte Zuweisungen löschen
|
error_log("Phase $phase [Iter $iteration]: " . count($to_reassign) . " Teilnehmer werden entfernt und neu verteilt");
|
||||||
|
|
||||||
|
// Alle Zuweisungen aus unterbesetzten Workshops löschen
|
||||||
$fw_list = implode(',', array_map('intval', $failing));
|
$fw_list = implode(',', array_map('intval', $failing));
|
||||||
$wpdb->query("DELETE FROM {$prefix}kc_zuteilung
|
$wpdb->query("DELETE FROM {$prefix}kc_zuteilung
|
||||||
WHERE wahl_id = " . intval($wahl_id) . "
|
WHERE wahl_id = " . intval($wahl_id) . "
|
||||||
@@ -215,25 +217,46 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
// Kapazitäten wieder freigeben
|
// Kapazitäten wieder freigeben
|
||||||
foreach($failing as $fw) {
|
foreach($failing as $fw) {
|
||||||
$freed = $assigned_counts[$fw] ?? 0;
|
$freed = $assigned_counts[$fw] ?? 0;
|
||||||
$caps[$fw] = ($caps[$fw] ?? 0) + $freed;
|
$caps[$fw] = $workshop_caps[$fw]; // Auf max zurücksetzen
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Sichere" Workshops: Nur die, die KEIN Minimum haben ODER ihr Minimum BEREITS erfüllt haben
|
// "Sichere" Workshops für Umverteilung: Kein Min ODER Min erfüllt (OHNE underbesetzte)
|
||||||
$safe_workshops = [];
|
$safe_workshops = [];
|
||||||
foreach($ws_ids_in_wahl as $wsid) {
|
foreach($ws_ids_in_wahl as $wsid) {
|
||||||
if (in_array($wsid, $failing)) continue; // Unterbesetzte raus
|
if (in_array($wsid, $failing)) continue; // Unterbesetzte raus
|
||||||
$min_req = $min_map[$wsid] ?? 0;
|
$min_req = $min_map[$wsid] ?? 0;
|
||||||
$cnt = $assigned_counts[$wsid] ?? 0;
|
$cnt = $assigned_counts[$wsid] ?? 0;
|
||||||
// Sicher wenn: kein Min UND Kapazität übrig OR Min erfüllt und noch Platz
|
|
||||||
if (($min_req == 0 && isset($caps[$wsid]) && $caps[$wsid] > 0) ||
|
// Sicher wenn:
|
||||||
($min_req > 0 && $cnt >= $min_req && isset($caps[$wsid]) && $caps[$wsid] > 0)) {
|
// A) Kein Minimum UND noch Platz, ODER
|
||||||
|
// B) Min > 0 UND Min schon erreicht UND noch Platz, ODER
|
||||||
|
// C) Min > 0 UND alles folgenden TN passen rein (reicht für Min)
|
||||||
|
$remaining_tns_to_reassign = count($to_reassign);
|
||||||
|
$cap_left = $caps[$wsid] ?? 0;
|
||||||
|
|
||||||
|
$can_fit = false;
|
||||||
|
if ($min_req == 0) {
|
||||||
|
$can_fit = $cap_left > 0;
|
||||||
|
} else {
|
||||||
|
// Wenn Min schon erfüllt, kann man noch hinzufügen
|
||||||
|
$current_cnt = $assigned_counts[$wsid] ?? 0;
|
||||||
|
if ($current_cnt >= $min_req && $cap_left > 0) {
|
||||||
|
$can_fit = true;
|
||||||
|
}
|
||||||
|
// ODER: Wenn noch Platz für den Rest + Min
|
||||||
|
elseif ($cap_left >= $min_req) {
|
||||||
|
$can_fit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($can_fit) {
|
||||||
$safe_workshops[] = $wsid;
|
$safe_workshops[] = $wsid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error_log("Phase $phase: " . count($safe_workshops) . " 'sichere' Workshops für Umverteilung verfügbar");
|
error_log("Phase $phase [Iter $iteration]: " . count($safe_workshops) . " sichere Workshops verfügbar");
|
||||||
|
|
||||||
// Teilnehmer auf sichere Workshops verteilen
|
// Teilnehmer auf sichere Workshops neu verteilen
|
||||||
foreach($to_reassign as $tid) {
|
foreach($to_reassign as $tid) {
|
||||||
$tn = $all_teilnehmer_by_id[$tid] ?? $wpdb->get_row($wpdb->prepare(
|
$tn = $all_teilnehmer_by_id[$tid] ?? $wpdb->get_row($wpdb->prepare(
|
||||||
"SELECT * FROM {$prefix}kc_teilnehmer WHERE id = %d", $tid
|
"SELECT * FROM {$prefix}kc_teilnehmer WHERE id = %d", $tid
|
||||||
@@ -242,7 +265,7 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
|
|
||||||
$reassigned = false;
|
$reassigned = false;
|
||||||
|
|
||||||
// Zuerst Wünsche versuchen (nur auf sichere Workshops)
|
// Zuerst Wünsche auf sichere Workshops
|
||||||
for($w = 1; $w <= 3; $w++) {
|
for($w = 1; $w <= 3; $w++) {
|
||||||
$choice = intval($tn->{"wunsch$w"});
|
$choice = intval($tn->{"wunsch$w"});
|
||||||
if ($choice > 0 && in_array($choice, $safe_workshops) && isset($caps[$choice]) && $caps[$choice] > 0) {
|
if ($choice > 0 && in_array($choice, $safe_workshops) && isset($caps[$choice]) && $caps[$choice] > 0) {
|
||||||
@@ -255,7 +278,7 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
|
|
||||||
if ($reassigned) continue;
|
if ($reassigned) continue;
|
||||||
|
|
||||||
// Falls kein Wunsch auf sicherer Liste frei → zufällig auf sichere verteilen
|
// Zufällig auf sichere Workshops
|
||||||
if (!empty($safe_workshops)) {
|
if (!empty($safe_workshops)) {
|
||||||
$available = [];
|
$available = [];
|
||||||
foreach($safe_workshops as $wsid) {
|
foreach($safe_workshops as $wsid) {
|
||||||
@@ -271,7 +294,7 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wenn immer noch nichts frei → unassigned
|
// Falls immer noch nichts frei → unzugewiesen
|
||||||
if (!$reassigned) {
|
if (!$reassigned) {
|
||||||
$wpdb->insert("{$prefix}kc_zuteilung", [
|
$wpdb->insert("{$prefix}kc_zuteilung", [
|
||||||
'wahl_id' => $wahl_id,
|
'wahl_id' => $wahl_id,
|
||||||
@@ -284,18 +307,15 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Unterbesetzte Workshops sind nun aus dem Pool raus
|
if ($iteration >= $max_iterations) {
|
||||||
foreach($failing as $fw) {
|
error_log("Phase $phase: WARNUNG - Max Iterationen ($max_iterations) erreicht. Es könnten noch unterbesetzte Workshops existieren.");
|
||||||
error_log("Workshop $fw wird aus dem Pool entfernt (konnte nicht mit Minimum befüllt werden)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error_log("Phase $phase: Alle Workshops erfüllen ihre Minimalanzahl ✓");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 7) Kapazitätsprüfung (Debug / Log)
|
// 7) Kapazitätsprüfung (Debug / Log)
|
||||||
foreach($caps as $wsid=>$capleft) {
|
foreach($caps as $wsid=>$capleft) {
|
||||||
if($capleft < 0) {
|
if($capleft < 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user