Improve workshop minimum participant handling and reassignment logic
All checks were successful
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Successful in 13s
All checks were successful
Deploy Workshop-Wahlen (DEV / PROD) / deploy (push) Successful in 13s
This commit is contained in:
@@ -131,73 +131,134 @@ 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;
|
||||
|
||||
// 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
|
||||
// Wenn immer noch nichts frei → unassigned
|
||||
if (!$reassigned) {
|
||||
$wpdb->insert("{$prefix}kc_zuteilung", [
|
||||
'wahl_id' => $wahl_id,
|
||||
'teilnehmer_id' => $tn->id,
|
||||
@@ -211,6 +272,7 @@ function kc_run_zuteilung($wahl_id) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 7) Kapazitätsprüfung (Debug / Log)
|
||||
foreach($caps as $wsid=>$capleft) {
|
||||
|
||||
Reference in New Issue
Block a user