---
title: MZ4 Module Capacity-Reporting (Workdays + Employee) — Reverse-Engineering-Doku
date: 2026-06-30
status: aktiv
type: project
tags: [reverse-engineering, vsm, mz4, capacity-reporting]
---

# MZ4 Capacity-Reporting — Zwei Sub-Module

Beide Module sind unter **Reporting > Kapa-Monitoring** im Top-Nav erreichbar.
Sie teilen dieselbe JS-Klasse (`Mz4CapacityReporting`) und denselben `filterFeature`-Schlüssel
(`mz4_capacityreporting`), verwenden aber unterschiedliche `filterType`-Keys (kein Konflikt).

---

## 1. Zweck der Module

### 1a. Arbeitstage (`mz4_capacity_reporting_workdays`)

Pivot-Auswertung: **Welche Projektkategorie verbraucht wie viele Arbeitstage pro Monat?**
Zeilen = Terminarten/Projektkategorien (14 Stück), Spalten = Monate Jan–Dez + Total.
Jede Kategorie ist aufklappbar in drei Unterzeilen nach Funktionslevel (Berater, AL, Praktikant).
Primärziel: Kapazitätsbelastung nach Auftragstyp im Jahresüberblick.

### 1b. Mitarbeiter (`mz4_capacity_reporting_employee`)

Pivot-Auswertung: **Welcher Mitarbeiter ist wie viele Arbeitstage pro Monat verplant?**
Zeilen = Monate (Jan–Dez), Spalten = je ein Mitarbeiter (42 Spalten) + Gesamtergebnis.
Primärziel: Auslastungsübersicht je Kopf im Monatsverlauf.

---

## 2. Filter & Steuerelemente

### 2a. Arbeitstage-Modul — Filterleiste

Alle Filter in einer `.well`-Box oberhalb der Tabelle. Bootstrap-Grid, responsive.

| Filter-ID | Label | Element | data-type | data-toggle | Optionen / Default |
|---|---|---|---|---|---|
| `departmentNavigation` | Abteilung | multi-select | `DepartmentWorkday` | excelFilter | MO-2 (1), MO-2 UK (2), MO-22 (3), MO-23 (4), MC-14 (8), MN-14 (9), MN-90 (10), MO-24 (13) — Default: MO-2 + MO-23 |
| `kpiBoardDENavigation` | KPI Board DE | multi-select | `KPIBoardDE` | excelFilter + selectFilterPush | MO-21 (1), MO-23 (2), MO-22 (3), Nur MO-2 (4), MO-24 (5) — Default: alle ausgewählt |
| `kpiBoardUSNavigation` | KPI Board Ausland | multi-select | `KPIBoardUS` | excelFilter + selectFilterPush | China (1), USA (4), Mexiko (5) — Default: keiner ausgewählt (Option "keine Daten" value=null) |
| `monthsNavigation` | Monat | multi-select | `MonthsWorkday` | excelFilter | Januar (01) … Dezember (12) — Default: kein Vorselekt sichtbar |
| `yearNavigation` | Jahr | single-select | `YearWorkday` | selectFilterPush | 2018–2027 — Default (persisted): 2023 |
| `projectnumberNavigation` | Auftragsnummer | multi-select | `ProjectNumber` | excelFilter + selectFilterPush | 2.959 Projektnummern, Format YYYY_NNN, Bereich 2014_247–2026_196 |
| `projectManagerNavigation` | Projektleiter | multi-select | `ProjectManager` | excelFilter + selectFilterPush | 43 Mitarbeiter — 28 vorausgewählt (persisted state) |

Mechanismus:
- `excelFilter` = client-seitiger jQuery-Multiselect-Filter (Filter.js / jquery.multiselect.js)
- `selectFilterPush` = bei Änderung sofort AJAX-Push an Server (Reload oder Partial Update)
- Jahres-Select hat nur `selectFilterPush` (kein `excelFilter`) → Jahreswechsel erzwingt Server-Reload

Persistenz: Filter-State wird server-seitig pro User-Session gespeichert und beim nächsten Seitenaufruf
als `mz4Options.filters`-Array in die Seite injiziert.

### 2b. Mitarbeiter-Modul — Filterleiste

| Filter-ID | Label | Element | data-type | data-toggle | Optionen / Default |
|---|---|---|---|---|---|
| `departmentNavigation` | Abteilung | multi-select | `Department` | excelFilter | MO-2 (1), MO-2 UK (2), MO-22 (3), MO-23 (4), MC-14 (8), MN-14 (9), MN-90 (10), MO-24 (13) — kein Default |
| `functionNavigation` | Funktion | multi-select | `Function` | excelFilter | --- (0), Hauptabteilungsleiter (6), Berater (7), Abteilungsleiter (8), Backoffice (9), Diplomand (10), Praktikant (11), Doktorand (12) — kein Default |
| `personsNavigation` | Personen | multi-select | `Persons` | excelFilter | 43 Mitarbeiter mit ID — kein Default |
| `monthsNavigation` | Monat | multi-select | `Months` | excelFilter | Januar (01) … Dezember (12) — kein Default → zeigt Leer-State |
| `yearNavigation` | Jahr | single-select | `Year` | selectFilterPush | 2018–2027 — Default: 2026 (current year) |

Hinweis: Wenn kein Monat ausgewählt → Tabelle zeigt Meldung "- Alle Monate wurden im Filter abgewählt. -"
(colspan über alle Spalten).

---

## 3. Tabellen

### 3a. Arbeitstage-Tabelle

**Struktur**: `<table class="table">` mit `<thead>` + 14 `<tbody>`-Blöcke (ein tbody je Kategorie).

**Spaltenköpfe** (14 Spalten):

| Spalte | Inhalt |
|---|---|
| Zeilenbeschriftung | Kategorienamen / Sub-Zeilen-Label |
| Jan | Arbeitstage im Januar |
| Feb | Februar |
| Mrz | März |
| Apr | April |
| Mai | Mai |
| Juni | Juni |
| Jul | Juli |
| Aug | August |
| Sep | September |
| Okt | Oktober |
| Nov | November |
| Dez | Dezember |
| Total | Jahressumme |

**Zeilenstruktur** (pro Kategorie — 4 Zeilen):

| Zeile | Beschriftung | Besonderheit |
|---|---|---|
| Kategorie-Header | Kategoriename | Span mit `data-toggle="toggle" data-target=".mz4_categorieN" data-icon="true"` + `<i class="fa fa-chevron-circle-up">` — Klick klappt Sub-Zeilen ein/aus |
| Sub 1 | Summe von Arbeitstage Berater | 4 Leerzeichen Einrückung |
| Sub 2 | Summe von Arbeitstage AL | 4 Leerzeichen Einrückung (AL = Abteilungsleiter) |
| Sub 3 | Summe von Arbeitstage Praktik. | 4 Leerzeichen Einrückung (Praktikant/Diplomand) |

Collapse-Mechanismus: `data-target=".mz4_categorie{N}"` — Sub-Zeilen haben CSS-Klasse `mz4_categorieN`
(durch JS dynamisch gesetzt). Chevron-Icon dreht sich (data-icon='true').

**14 Projektkategorien** (Zeilenbeschriftungen):

1. 360° Workshop
2. Entwicklung Produktionssystem
3. Euro-Workshop
4. Investplausibilisierung
5. Kapa-Workshop
6. Lieferantenanalyse - Fabrikanalyse
7. Lieferantenanalyse - Projektanalyse
8. Lieferanteneskalation / Sonderprojektform nach SOP
9. Lieferanteneskalation / Sonderprojektform vor SOP
10. PräventionsTeam Leitung
11. PräventionsTeam Support
12. Sonderauftrag
13. ZDSC Campus
14. 9999er Projekte

Keine Gesamt-Summenzeile sichtbar im HTML (ANNAHME: evtl. via JS nachgeladen oder nicht implementiert).
Keine Sortierung (kein `sorttable`-class auf Tabelle — obwohl sorttable.js geladen ist).
Keine Pagination.

**Beispieldaten** (Jahr 2023, Dept MO-2 + MO-23):

| Kategorie | Total |
|---|---|
| Sonderauftrag | 652 AT |
| Kapa-Workshop | 335 AT |
| Lieferanteneskalation nach SOP | 371 AT |
| Lieferanteneskalation vor SOP | 292 AT |
| Lieferantenanalyse Fabrikanalyse | 234 AT |
| Euro-Workshop | 190 AT |
| Lieferantenanalyse Projektanalyse | 53 AT |

### 3b. Mitarbeiter-Tabelle

**Struktur**: `<table class="table table-striped">` (gestreifte Zeilen).

**Spaltenköpfe** (44 Spalten): Monat | [42 Mitarbeiternachname] | Gesamtergebnis (unterstrichen)

**42 Mitarbeiter-Spalten** (alphabetisch nach Nachname):
Althammer, Arce, Aseckzai, Azano, Barker, Broker, Cooper, Dickens, Duncan, Fanderl, Fekete,
Fischer, Fred, Gilch, Gruber, Hagen, Haro, Hernandez, Iberri, Klockenhoff, Knopf, Kurzmiller,
Lavrin, Leon, Li, Löffler, Miller, Nguyen, Rack, Rogers, Rossi, Schlirf, Schlotterbeck,
Sertpoyraz, Shanshan, Storch, Tian, Weigand, Xu, Xue, Zelin, Zich

**Zeilen**: bis zu 12 (eine pro ausgewähltem Monat) — Zelleninhalt = Arbeitstage (Integer).

**Gesamtergebnis**: letzte Spalte, summiert alle Mitarbeiterwerte je Monatszeile.

Keine Expand/Collapse. Kein Sub-Row-Pattern. Keine Pagination. Keine Sortierung aktiviert.

---

## 4. Charts

Kein Chart-Element in beiden Modulen gefunden. Reine Tabellen-Ansichten.

---

## 5. Export

Im HTML kein expliziter Export-Button (kein `excel_func.php`-Link, kein `pdf.php`-Link sichtbar).

ANNAHME: Export wird durch `Mz4CapacityReporting.js` bereitgestellt — wahrscheinlich ein
Excel-Export-Button, der dynamisch eingeblendet oder über den Filter-Mechanismus (`excelFilter`)
getriggert wird. Der `excelFilter`-Toggle-Name deutet auf eine enge Kopplung an `excel_func.php`
hin (447 Referenzen laut App-Map).

Export-Endpunkte (ANNAHME, nicht direkt beobachtet):
- Excel: `excel_func.php` — POST mit `modul=mz4_capacity_reporting_workdays` oder `..._employee`,
  `sessionkey`, und aktiven Filterwerten
- PDF: `com/pdf.php` — evtl. analog

---

## 6. AJAX-Endpunkte & Parameter

Das Modul nutzt `ajaxbase.js` + `Filter.js` + `Mz4CapacityReporting.js`.
Direkte AJAX-Calls sind nicht inline im HTML sichtbar — alle in externen JS-Files.

**Bekannte Init-Parameter** (aus `mz4Options`-Objekt):

```js
{
  filterFeature: 'mz4_capacityreporting',
  filters: [
    { filterFeature: 'mz4_capacityreporting', filterType: 'YearWorkday', filterText: '2023', filterOptions: [] },
    { filterFeature: 'mz4_capacityreporting', filterType: 'ProjectManager', filterText: [<IDs>], filterOptions: [] },
    { filterFeature: 'mz4_capacityreporting', filterType: 'KPIBoardDE', filterText: ['1','2','3','4','5'], filterOptions: [] },
    { filterFeature: 'mz4_capacityreporting', filterType: 'DepartmentWorkday', filterText: ['1','4'], filterOptions: [] }
  ]
}
```

**ANNAHME**: `selectFilterPush`-Selects (Year, KPIBoardDE, KPIBoardUS, ProjectNumber, ProjectManager im Workdays-Modul)
senden per POST an `index.php` oder `ajaxloader.php`:
- `modul` = Modulname
- `sessionkey` = Session-Token
- `filterFeature` = 'mz4_capacityreporting'
- `filterType` = z.B. 'YearWorkday'
- `filterText` = neuer Wert

**`excelFilter`-Selects** (Department, Function, Persons, Months, DepartmentWorkday) filtern
client-seitig via jQuery-Multiselect (kein Server-Round-trip bei Änderung).

---

## 7. Abgeleitetes Datenmodell (ANNAHME)

### Kern-Entitäten

**Mitarbeiter (Person)**:
- `id` (Integer, PK — z.B. 765 = Aseckzai)
- `nachname`, `vorname`
- `abteilung_id` → Abteilung
- `funktion_id` → Funktion (Berater=7, AL=8, Praktikant=11, ...)

**Abteilung**:
- `id`, `kuerzel` (MO-2, MO-22, MO-23, MO-2 UK, MC-14, MN-14, MN-90, MO-24)

**Funktion**:
- `id`, `bezeichnung` (Berater, Abteilungsleiter, Backoffice, Diplomand, Praktikant, Doktorand, Hauptabteilungsleiter, ---)

**Termin/Einsatz**:
- `id`, `person_id` → Mitarbeiter
- `projekt_id` → Projekt
- `terminart` (entspricht Projektkategorie — 14 Typen)
- `datum`, `arbeitstage` (Anzahl Tage)

**Projekt**:
- `nummer` (Format YYYY_NNN, z.B. 2023_042)
- `projektleiter_id` → Mitarbeiter
- `kategorie` / `terminart` (360° Workshop, Euro-Workshop, Kapa-Workshop, Sonderauftrag, etc.)
- `kpi_board_de_id` (1–5: MO-21/MO-23/MO-22/Nur-MO-2/MO-24)
- `kpi_board_us_id` (1=China, 4=USA, 5=Mexiko)

**KPI-Board DE** (Zuordnung Projekt zu KPI-Reporting-Gruppe):
- `id`, `bezeichnung` (MO-21, MO-23, MO-22, Nur MO-2, MO-24)

**KPI-Board Ausland**:
- `id`, `bezeichnung` (China, USA, Mexiko)

### Aggregations-Logik (ANNAHME)

**Arbeitstage-Report** (Workdays):
- GROUP BY `terminart`, `monat(datum)`, `funktion_id`
- SUM(`arbeitstage`) pro Zelle
- Filter: Jahr, Abteilung, KPIBoardDE, KPIBoardUS, Projektnummer, Projektleiter

**Mitarbeiter-Report**:
- GROUP BY `person_id`, `monat(datum)`
- SUM(`arbeitstage`) pro Zelle
- Filter: Jahr, Abteilung, Funktion, Person, Monat

---

## 8. Berechnungen & Business-Rules

ANNAHME — keine Berechnungslogik direkt im HTML sichtbar, Aggregation server-seitig:

1. **Arbeitstage Berater** = Summe aller Einsatztage von Mitarbeitern mit Funktion "Berater" (id=7)
   pro Projektkategorie + Monat, gefiltert nach aktiven Filtern.

2. **Arbeitstage AL** = analog für Funktion "Abteilungsleiter" (id=8).

3. **Arbeitstage Praktik.** = analog für Funktion "Praktikant" (id=11) und ggf. Diplomand (id=10).

4. **Kategorie-Header-Zeile** = Summe aller drei Funktionslevels (Berater + AL + Praktikant)
   — ANNAHME: wird server-seitig zusammengezählt, nicht JS-seitig.

5. **Total-Spalte** = Summe Jan–Dez pro Zeile — server-seitig.

6. **Gesamtergebnis-Spalte (Employee)** = Summe aller Mitarbeiter pro Monat-Zeile.

7. **9999er Projekte**: ANNAHME — Sammelbucket für Projekte mit internem Platzhalter-Projektcode
   (nicht kundenrelevant, z.B. Urlaub, Fortbildung, interne Meetings).

ANNAHME: Keine Auslastungs-Prozentberechnung in diesen Modulen sichtbar. Nur absolute Arbeitstage.
Auslastungs-KPIs sind vermutlich im `mz4_kpi_charts`-Modul.

---

## 9. UI-Komponenten

| Komponente | Verwendung |
|---|---|
| Bootstrap 3 Grid | Filterleiste (col-xs-12 col-sm-3) |
| jQuery Multiselect (jquery.multiselect.js) | Alle Mehrfach-Auswahl-Dropdowns |
| Bootstrap Table (table-striped) | Employee-Tabelle |
| Bootstrap Toggle (data-toggle="toggle") | Kategorie-Expand/Collapse in Arbeitstage-Tabelle |
| Font Awesome 4.x | Chevron-Icons (fa-chevron-circle-up), Gear (fa-gear) |
| Bootstrap Modal | Basis-Modal (#baseModal) — Settings-Popup |
| Settings Box | Ajaxbox #seetings_box_sub — Seitenleiste |
| InfoBox / DatenInfoBox | Overlay-Infoboxen (allgemeines App-Pattern) |
| sorttable.js | Geladen aber kein `sortable`-class auf den Tabellen — Sortierung inaktiv in diesen Modulen |
| Loading Overlay | #loadstopperover mit Spinner-GIF — bei AJAX-Requests |
| DatenNeuMitarbeiter | Ausgeblendete massnahmeneintragbox (shared App-Pattern, vermutlich für andere Module) |

**Responsive**: col-xs-12 col-sm-3 margin_5_mobile auf Filterelementen — Filter stapeln auf Mobile.
`no_desktop`-Klasse auf Hamburger-Icon — nur Mobile sichtbar.

---

## 10. Offene Fragen

1. **Export-Trigger**: Wie genau wird Excel-Export ausgelöst? Gibt es einen Export-Button der per JS
   dynamisch eingeblendet wird, oder nur Browser-Drucken? `excelFilter`-Toggle deutet auf
   Filter-basiertes Excel hin — genaue Implementierung in `Mz4CapacityReporting.js` unbekannt.

2. **Gesamt-Summenzeile**: Gibt es eine abschließende Summenzeile unter allen Kategorien im
   Arbeitstage-Report? Im HTML nicht sichtbar (letzter tbody endet mit 9999er Projekte).

3. **"May, "** und **"Li, "**: Zwei Personen mit leerem Vornamen (IDs 711 und 747) — Data-Quality-Issue
   oder Platzhalter?

4. **`selectFilterPush` + `excelFilter` kombiniert**: Welche Seite der Doppelfunktion hat Vorrang?
   ANNAHME: excelFilter = lokale Tabellen-Filter-Anzeige, selectFilterPush = paralleles Persistieren
   server-seitig.

5. **KPI Board Ausland mit value=null**: Die Option "(Keine Daten)" hat `value='null'` — wie wird das
   server-seitig behandelt (SQL-NULL oder String "null")?

6. **Arbeitstage vs. Auslastung**: Die Module zeigen absolute Arbeitstage. Wo werden Soll-Kapazitäten
   (verfügbare Tage) hinterlegt, um eine Auslastungs-% zu berechnen? Vermutlich in
   `mz4_kpi_charts` oder in der Mitarbeiter-Konfiguration.

7. **mz4Options.filters im Employee-Modul enthält WorkdayTypes**: Die persistierten Filter-States
   (YearWorkday, DepartmentWorkday) stammen aus der Workdays-Session. Das Employee-Modul ignoriert
   diese anscheinend (nutzt eigene data-types Year/Department). Bestätigt: kein Konflikt wegen
   unterschiedlicher filterType-Keys.

8. **Projektleiter vs. Mitarbeiter**: Im Arbeitstage-Filter heißt der Filter "Projektleiter" (43 Personen),
   in der Employee-Tabelle "Personen" (42 Spalten). Gleiche Menge? Person 712 und 1078 aus
   ProjectManager-Init fehlen in personsNavigation (Mitarbeiter-Modul). Vermutlich haben diese
   Personen Leitungsrollen ohne eigene Einsatzplanung.

9. **Sortierung der Kategorien**: Die 14 Kategorien erscheinen nicht alphabetisch — gibt es eine
   konfigurierbare Reihenfolge in der DB oder ist die Reihenfolge fix im Code?

10. **Zeitraum der Projektdaten**: projectnumberNavigation zeigt 2.959 Projekte von 2014–2026.
    Ältere Projekte können nachträglich noch Einträge haben? Filter müsste auf Jahr eingrenzen.
