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,82 +131,144 @@ function kc_run_zuteilung($wahl_id) {
|
|||||||
$assign($tn, $ws_id, 99);
|
$assign($tn, $ws_id, 99);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6.5 Consolidate workshops that did not reach their minimal Teilnehmerzahl
|
// 6.5 Verbesserte Mindestanzahl-Sicherung: Unterbesetzte Workshops auflösen
|
||||||
// Load minimal requirements for workshops in this Wahl
|
|
||||||
$ws_ids_in_wahl = array_keys($workshops);
|
$ws_ids_in_wahl = array_keys($workshops);
|
||||||
if (!empty($ws_ids_in_wahl)) {
|
if (!empty($ws_ids_in_wahl)) {
|
||||||
|
|
||||||
|
// min_teilnehmer laden (einmalig)
|
||||||
$placeholders = implode(',', array_fill(0, count($ws_ids_in_wahl), '%d'));
|
$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 = [];
|
$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 = [];
|
$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 = [];
|
$failing = [];
|
||||||
foreach($ws_ids_in_wahl as $wsid) {
|
foreach($ws_ids_in_wahl as $wsid) {
|
||||||
$min_req = intval($min_map[$wsid] ?? 0);
|
$min_req = $min_map[$wsid] ?? 0;
|
||||||
$cnt = intval($assigned_counts[$wsid] ?? 0);
|
$cnt = $assigned_counts[$wsid] ?? 0;
|
||||||
if ($cnt > 0 && $min_req > 0 && $cnt < $min_req) {
|
if ($min_req > 0 && $cnt < $min_req) { // ← auch wenn cnt == 0 !
|
||||||
$failing[] = $wsid;
|
$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)) {
|
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 = [];
|
$to_reassign = [];
|
||||||
foreach($failing as $fw) {
|
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));
|
$rows = $wpdb->get_results($wpdb->prepare(
|
||||||
foreach($rows as $r) $to_reassign[] = intval($r->teilnehmer_id);
|
"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)) {
|
if (!empty($to_reassign)) {
|
||||||
// remove those assignments
|
// Alte Zuweisungen löschen
|
||||||
$fw_placeholders = implode(',', array_map('intval', $failing));
|
$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_placeholders)");
|
$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) {
|
foreach($failing as $fw) {
|
||||||
$freed = intval($assigned_counts[$fw] ?? 0);
|
$freed = $assigned_counts[$fw] ?? 0;
|
||||||
if (!isset($caps[$fw])) $caps[$fw] = 0;
|
$caps[$fw] = ($caps[$fw] ?? 0) + $freed;
|
||||||
$caps[$fw] += $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) {
|
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;
|
if (!$tn) continue;
|
||||||
|
|
||||||
$reassigned = false;
|
$reassigned = false;
|
||||||
for($w=1;$w<=3;$w++) {
|
|
||||||
|
// Nochmal Wunsch 1–3 versuchen
|
||||||
|
for($w = 1; $w <= 3; $w++) {
|
||||||
$choice = intval($tn->{"wunsch$w"});
|
$choice = intval($tn->{"wunsch$w"});
|
||||||
if ($choice > 0 && isset($caps[$choice]) && $caps[$choice] > 0) {
|
if ($choice > 0 && isset($caps[$choice]) && $caps[$choice] > 0) {
|
||||||
$assigned = $assign($tn, $choice, $w);
|
if ($assign($tn, $choice, $w)) {
|
||||||
if ($assigned) { $reassigned = true; break; }
|
$reassigned = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($reassigned) continue;
|
if ($reassigned) continue;
|
||||||
|
|
||||||
// otherwise assign to any workshop with free capacity
|
// Falls kein Wunsch frei → irgendein freier Workshop
|
||||||
$available = array_keys(array_filter($caps, function($c){return $c>0;}));
|
$available = array_keys(array_filter($caps, fn($c) => $c > 0));
|
||||||
if (!empty($available)) {
|
if (!empty($available)) {
|
||||||
$target = $available[array_rand($available)];
|
$target = $available[array_rand($available)];
|
||||||
$assign($tn, $target, 99);
|
if ($assign($tn, $target, 99)) {
|
||||||
continue;
|
$reassigned = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// lastly, mark as unassigned
|
// Wenn immer noch nichts frei → unassigned
|
||||||
$wpdb->insert("{$prefix}kc_zuteilung", [
|
if (!$reassigned) {
|
||||||
'wahl_id' => $wahl_id,
|
$wpdb->insert("{$prefix}kc_zuteilung", [
|
||||||
'teilnehmer_id' => $tn->id,
|
'wahl_id' => $wahl_id,
|
||||||
'vorname' => $tn->vorname,
|
'teilnehmer_id' => $tn->id,
|
||||||
'nachname' => $tn->nachname,
|
'vorname' => $tn->vorname,
|
||||||
'phase' => $phase,
|
'nachname' => $tn->nachname,
|
||||||
'workshop_id' => null,
|
'phase' => $phase,
|
||||||
'wunsch_rang' => -1
|
'workshop_id' => null,
|
||||||
]);
|
'wunsch_rang' => -1
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user