diff --git a/app/(app)/employees/page.tsx b/app/(app)/employees/page.tsx
index db5afa5..c7af32b 100644
--- a/app/(app)/employees/page.tsx
+++ b/app/(app)/employees/page.tsx
@@ -20,7 +20,7 @@ import {
} from "@/lib/employee-sort";
import { derivedStatusFilter } from "@/lib/employee-status-filter";
import { fmtDate, fmtName, todayIso } from "@/lib/format";
-import { breadcrumbLabel, divisionOf, loadOrgMaps, subtreeOf, unitOf, type OrgEb } from "@/lib/org";
+import { breadcrumbLabel, loadOrgMaps, subtreeOf, unitOf, type OrgEb } from "@/lib/org";
import { loadPlacements } from "@/lib/placement";
import type { EmploymentStatus } from "@/lib/types";
@@ -335,7 +335,6 @@ export default async function EmployeesPage({ searchParams }: EmployeesPageProps
{employees.map((e) => {
const placement = placements.get(e.id);
- const division = divisionOf(orgMaps, placement?.orgUnitId);
const unit = unitOf(orgMaps, placement?.orgUnitId);
const location = e.location_id ? orgMaps.locations.get(e.location_id) : undefined;
return (
@@ -359,14 +358,17 @@ export default async function EmployeesPage({ searchParams }: EmployeesPageProps
{/* tabular-nums keeps the numeric columns aligned down the
page instead of jittering per row. */}
{e.personnel_number} |
-
- {division?.name ?? "–"}
- {/* Die eigene Einheit, egal auf welcher Ebene sie hängt —
- eine Bereichsleitung sitzt am Bereich, nicht an einem
- Team, und stand vorher deshalb ohne Zuordnung da. */}
-
- {unit && unit.id !== division?.id ? unit.name : "–"}
-
+ {/* Nur die eigene Einheit, egal auf welcher Ebene sie hängt.
+ Darüber stand der Bereich; der Kunde wollte ihn weg, weil
+ seine Bereiche CEO, CFO, COO heissen und über jedem Namen
+ dasselbe wiederholten. Der ganze Weg von oben steht
+ weiterhin im `title` — eine Einheit wie „Shopleitung"
+ sagt allein nicht, welche gemeint ist. */}
+ |
+ {unit?.name ?? "–"}
|
{location?.name ?? "–"} |
{fmtDate(e.entry_date)} |
diff --git a/lib/employee-sort.ts b/lib/employee-sort.ts
index 82a935a..d62b712 100644
--- a/lib/employee-sort.ts
+++ b/lib/employee-sort.ts
@@ -10,13 +10,14 @@ import type { Schema } from "@/lib/db/schema";
//
// Bedient wird sie über die Spaltenköpfe. Damit das keine leere Zusage ist,
// sortiert **jede** dieser Spalten über den gesamten Bestand, auch die drei,
-// die nicht auf der Person stehen: Bereich/Team hängt an der Planstelle,
-// Standort an einer Nachschlagetabelle, und der Status ist eine Aufzählung.
+// die nicht auf der Person stehen: die Organisationseinheit hängt an der
+// Planstelle, der Standort an einer Nachschlagetabelle, und der Status ist
+// eine Aufzählung.
export const SORTIERFELDER = [
{ value: "name", label: "Mitarbeiter:in" },
{ value: "persnr", label: "Pers.-Nr." },
- { value: "bereich", label: "Bereich/Team" },
+ { value: "einheit", label: "Organisationseinheit" },
{ value: "standort", label: "Standort" },
{ value: "eintritt", label: "Eintritt" },
{ value: "beschaeftigung", label: "Beschäftigung" },
@@ -72,39 +73,13 @@ const einheitAusdruck = sql`(
where pa.employee_id = employees.id and pa.valid_to is null
limit 1)`;
-/**
- * Der Bereich darüber — die nächste Einheit über der Person, die als Bereich
- * geführt wird.
- *
- * Aufgestiegen wird rekursiv, nicht mit einer festen Zahl von Sprüngen. Hier
- * standen zwei `left join`, weil der Baum als höchstens vierstufig galt
- * (Gesellschaft, Bereich, Abteilung, Team) und zwei Sprünge damit reichten.
- * `unit_type` ist aber nur ein Etikett, und die Organisation kann beliebig
- * tief sein: bei Manner sind es sieben Ebenen, und für 317 der 784 Personen
- * lag der Bereich drei oder vier Sprünge über der eigenen Einheit. Der
- * Ausdruck lieferte null, und diese 317 rutschten beim Sortieren nicht unter
- * ihre Bereiche, sondern allesamt in einen Block am Ende der Liste.
- *
- * Der Aufstieg hält beim ersten Bereich an, nimmt also den **nächsten** und
- * nicht den obersten. Ohne das Anhalten stünde bei fast allen „CEO": diese
- * Einheit liegt über den sechs C-Level-Bereichen und ist selbst einer. In den
- * Berichten gilt dieselbe Regel — lib/reports-data.ts steigt von der Wurzel
- * ab, dort gewinnt der letzte Treffer, und das ist derselbe Bereich.
- */
-const bereichAusdruck = sql`(
- with recursive kette as (
- select ou.id, ou.name, ou.unit_type, ou.parent_id, 0 as tiefe
- from position_assignments pa
- join om_positions p on p.id = pa.position_id
- join org_units ou on ou.id = p.org_unit_id
- where pa.employee_id = employees.id and pa.valid_to is null
- union all
- select o.id, o.name, o.unit_type, o.parent_id, k.tiefe + 1
- from kette k
- join org_units o on o.id = k.parent_id
- where k.unit_type <> 'Bereich'
- )
- select name from kette where unit_type = 'Bereich' order by tiefe limit 1)`;
+// Hier stand ein zweiter Ausdruck, der den Bereich über der Person suchte:
+// die Liste sortierte nach Bereich und erst darin nach der Einheit. Der
+// Bereich steht seit 22.09.2026 nicht mehr in der Spalte — der Kunde wollte
+// dort nur die eigene Einheit sehen, weil die Bereiche bei ihm CEO, CFO, COO
+// heissen und als Zeile über jedem Namen nichts beitragen. Sortiert wird
+// seither nach dem, was auch dasteht. Eine Sortierung nach einem Wert, den
+// die Spalte nicht zeigt, sieht von aussen aus wie gar keine Sortierung.
const standortAusdruck = sql`(select name from locations where id = employees.location_id)`;
@@ -169,8 +144,8 @@ export function sortiere(
switch (feld) {
case "persnr":
return q.orderBy(ordne(sql.ref("personnel_number")));
- case "bereich":
- return nachName(q.orderBy(ordne(bereichAusdruck)).orderBy(ordne(einheitAusdruck)));
+ case "einheit":
+ return nachName(q.orderBy(ordne(einheitAusdruck)));
case "standort":
return nachName(q.orderBy(ordne(standortAusdruck)));
case "eintritt":
diff --git a/tests/unit/employee-sort.test.ts b/tests/unit/employee-sort.test.ts
index 783e08b..50f1a4e 100644
--- a/tests/unit/employee-sort.test.ts
+++ b/tests/unit/employee-sort.test.ts
@@ -89,7 +89,7 @@ describe("SORTIERFELDER", () => {
expect(SORTIERFELDER.map((f) => f.label)).toEqual([
"Mitarbeiter:in",
"Pers.-Nr.",
- "Bereich/Team",
+ "Organisationseinheit",
"Standort",
"Eintritt",
"Beschäftigung",
@@ -191,25 +191,17 @@ describe("das erzeugte SQL", () => {
}
});
- it("holt Bereich und Team über die laufende Besetzung", () => {
- const sql = ordnung("bereich", "asc");
+ it("holt die Organisationseinheit über die laufende Besetzung", () => {
+ const sql = ordnung("einheit", "asc");
expect(sql).toContain("position_assignments");
expect(sql).toContain("pa.valid_to is null");
- // Der Bereich ist die Ebene unter der Gesellschaft, nicht die Einheit
- // selbst — sonst stünde in der Spalte etwas anderes als sortiert wird.
- expect(sql).toContain("unit_type = 'Bereich'");
+ expect(sql).toContain("org_units");
- // Und über beliebig viele Ebenen, nicht über eine feste Zahl von
- // Sprüngen. Vorher standen hier zwei `left join`; bei sieben Ebenen lag
- // der Bereich für 317 von 784 Personen ausserhalb ihrer Reichweite, und
- // diese 317 rutschten ohne Bereich ans Listenende.
- expect(sql).toContain("with recursive");
- expect(sql).toContain("join org_units o on o.id = k.parent_id");
-
- // Der Aufstieg hält beim ersten Bereich an. Ohne das Anhalten liefe er
- // bis zur obersten Einheit weiter, und bei fast allen stünde „CEO".
- expect(sql).toContain("k.unit_type <> 'Bereich'");
- expect(sql).toContain("order by tiefe limit 1");
+ // Sortiert wird nach der Einheit selbst, nicht nach dem Bereich darüber:
+ // die Spalte zeigt seit 22.09.2026 nur noch die Einheit, und eine
+ // Sortierung nach einem Wert, der nirgends steht, sieht von aussen aus
+ // wie gar keine Sortierung.
+ expect(sql).not.toContain("unit_type");
});
it("sortiert den Standort nach seinem Namen, nicht nach seiner Kennung", () => {