Files
awo-hamburg-intranet/module/tasks/sql/queries/badge_count_overdue_escalated.md
Moritz Weinmann 743476f64a Module tasks + knowledgecenter_update aus Kundenprojekt übernehmen (bereinigt)
Beide Module wurden aus einem anderen Kundenprojekt kopiert und bereinigt:

Knowledgecenter:
- Bild-Cache (1.985 Dateien) geleert, Ordnerstruktur mit .gitkeep behalten
- Files-Gallery-Lizenzschlüssel entfernt (config.php)
- Kundenspezifische Kategorien gelöscht: Teil I/II/III QM-Struktur,
  nummerierte QM-Kapitel, Gremien (Präsidium/Finanzausschuss/Landesausschuss),
  Sitzungsservice-Serie, Protokoll-Abteilungen, Testeinträge
- 56 generische Kategorien bleiben (Downloads, Onboarding, Personalthemen …)

Tasks:
- Alle Betriebsdaten gelöscht (114 Tasks, 914 Submissions, 579 Assignments)
- Task-Definitionen und Verlinkungen geleert
- Kategoriestruktur bleibt (Allgemein, IT, Personal, Buchhaltung …)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-22 09:20:02 +02:00

2.5 KiB

Badge-Query: Überfällige & eskalierte Aufgaben pro Benutzer

Gibt die Anzahl offener Aufgaben zurück, die überfällig oder eskaliert sind — ideal für einen Navigations-Badge.

Query

SELECT COUNT(*) AS badge_count
FROM task_assignment ta
INNER JOIN task_definition td
    ON td.id = ta.task_id
   AND td.active = 1
WHERE ta.main_contact_id = :contact_id
  AND ta.status IN ('overdue', 'open', 'in_progress', 'approval_pending', 'rejected')
  AND (
      ta.status = 'overdue'
      OR ta.escalation_level > 0
      OR (ta.due_at IS NOT NULL AND ta.due_at < NOW())
  )

Warum diese Bedingungen?

Bedingung Grund
td.active = 1 Deaktivierte Aufgaben sollen keinen Badge erzeugen
ta.status IN (...) Nur nicht-abgeschlossene Status — completed und expired sind erledigt
ta.status = 'overdue' Wurde bereits vom EscalationService als überfällig markiert
ta.escalation_level > 0 Eskalierte Aufgaben unabhängig vom Status (z.B. open aber schon eskaliert)
ta.due_at < NOW() Safety-Net: fängt Aufgaben, bei denen der Cronjob den Status noch nicht aktualisiert hat

Prepared-Statement (PHP)

$count = TaskCertDb::fetchOne(
    "SELECT COUNT(*) AS badge_count
     FROM task_assignment ta
     INNER JOIN task_definition td
         ON td.id = ta.task_id
        AND td.active = 1
     WHERE ta.main_contact_id = ?
       AND ta.status IN ('overdue','open','in_progress','approval_pending','rejected')
       AND (
           ta.status = 'overdue'
           OR ta.escalation_level > 0
           OR (ta.due_at IS NOT NULL AND ta.due_at < NOW())
       )",
    'i',
    $contactId
);

$badgeCount = (int) ($count['badge_count'] ?? 0);

Variante: Aufschlüsselung nach Typ

Falls du im Badge oder Tooltip zwischen überfällig und eskaliert unterscheiden willst:

SELECT
    SUM(ta.status = 'overdue' OR (ta.due_at IS NOT NULL AND ta.due_at < NOW())) AS overdue_count,
    SUM(ta.escalation_level > 0) AS escalated_count,
    COUNT(*) AS total_badge_count
FROM task_assignment ta
INNER JOIN task_definition td
    ON td.id = ta.task_id
   AND td.active = 1
WHERE ta.main_contact_id = :contact_id
  AND ta.status IN ('overdue', 'open', 'in_progress', 'approval_pending', 'rejected')
  AND (
      ta.status = 'overdue'
      OR ta.escalation_level > 0
      OR (ta.due_at IS NOT NULL AND ta.due_at < NOW())
  )

Performance

Der Index idx_task_assignment_contact_status_due (main_contact_id, status, due_at) deckt diese Query optimal ab. Kein Full-Table-Scan nötig.