Was unten im Brett steht, steht jetzt auch oben im Band
Filipe am 22.09.: "die aufgaben die man unten sieht soll man auch oben sehen." GEMESSEN an den echten Daten: aufgaben_zuteilung hatte NULL Zeilen, waehrend im Brett zwei Aufgaben standen (OFFEN 1, IN ARBEIT 1). Jede Person las oben "nichts zugeteilt". Die Aufgaben hingen am aelteren Feld aufgaben.verantwortlich_id -- genau dem Feld, nach dem das Brett gruppiert. Die Uebersicht las eine andere Quelle als die Liste darunter. resuemeeFuer() zaehlt jetzt BEIDE Wege und keinen doppelt: Gibt es zu einer Aufgabe eine Zuteilungszeile fuer die Person, gewinnt die Zuteilung (genauerer Zustand). Nur wo keine Zeile existiert, zaehlt das alte Feld. Die Zuordnung status->zustand steht an EINER Stelle; "review" zaehlt wie "arbeit", "abgebrochen" zaehlt nirgends -- so wie im Brett auch. Die Personenliste wird nicht mehr aufgezaehlt, sondern abgeleitet: die Rollen des Hauses (immer, auch mit null Aufgaben -- wer frei ist, ist die haeufigste Frage) PLUS jede aktive Person, der eine Aufgabe gehoert. Ohne den zweiten Teil koennte im Brett eine Aufgabe stehen, deren Mensch oben fehlt. pruef-zuteilung 71/0 (war 65). Der neue Abschnitt legt eine Aufgabe GENAU SO an wie die echten alten -- verantwortlich_id, keine Zuteilungszeile -- und misst Filipes Satz direkt: "unten im Brett stehen genauso viele wie oben (2 = 2)". Zahl in der Bedingung, nicht nur im Meldetext. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -333,6 +333,68 @@ melde("\n=== Das Resuemee ===");
|
|||||||
ok(modiTeam.code === 403, `ein Modi bekommt es nicht (HTTP ${modiTeam.code})`);
|
ok(modiTeam.code === 403, `ein Modi bekommt es nicht (HTTP ${modiTeam.code})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* =====================================================================
|
||||||
|
5b. WAS UNTEN IM BRETT STEHT, STEHT AUCH OBEN IM BAND (22.09.2026)
|
||||||
|
=====================================================================
|
||||||
|
Filipe: "die aufgaben die man unten sieht soll man auch oben sehen."
|
||||||
|
|
||||||
|
Gemessen war es so: aufgaben_zuteilung leer, im Brett zwei Aufgaben,
|
||||||
|
oben bei jeder Person "nichts zugeteilt". Die Aufgaben hingen am
|
||||||
|
aelteren Feld verantwortlich_id -- genau dem, nach dem das Brett
|
||||||
|
gruppiert.
|
||||||
|
|
||||||
|
Deshalb wird hier eine Aufgabe GENAU SO angelegt, wie die echten
|
||||||
|
alten liegen: mit verantwortlich_id und OHNE Zeile in
|
||||||
|
aufgaben_zuteilung. Eine Aufgabe ueber die Schnittstelle anzulegen
|
||||||
|
wuerde den Fall nicht treffen -- die legt heute beides an. */
|
||||||
|
melde("\n=== Die alten Aufgaben zaehlen oben mit ===");
|
||||||
|
{
|
||||||
|
const vorher = await rufe("/workspace/api/aufgaben/team-resuemee", { keks: chef });
|
||||||
|
const cemVor = (vorher.json?.leute || []).find((x) => x.name === "Cem") || {};
|
||||||
|
|
||||||
|
/* Die Verbindung von oben ist laengst zu (Zeile 115). Eine eigene,
|
||||||
|
kurz geoeffnete -- und gleich wieder geschlossen, damit sie dem
|
||||||
|
laufenden Server nicht im Weg steht. */
|
||||||
|
{
|
||||||
|
const dd = new DatabaseSync(process.env.WORKSPACE_DB);
|
||||||
|
const setz = dd.prepare(`INSERT INTO aufgaben
|
||||||
|
(titel, status, verantwortlich_id, erstellt_von, erstellt)
|
||||||
|
VALUES (?,?,?,?,?)`);
|
||||||
|
const jetzt = new Date().toISOString();
|
||||||
|
setz.run("Alte Aufgabe ohne Zuteilung", "arbeit", idCem, idChef, jetzt);
|
||||||
|
setz.run("Alte Aufgabe, noch offen", "offen", idCem, idChef, jetzt);
|
||||||
|
/* Eine abgebrochene darf NICHT mitzaehlen -- sie steht auch im
|
||||||
|
Brett in keiner der beiden Spalten. */
|
||||||
|
setz.run("Alte Aufgabe, abgebrochen", "abgebrochen", idCem, idChef, jetzt);
|
||||||
|
dd.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const nachher = await rufe("/workspace/api/aufgaben/team-resuemee", { keks: chef });
|
||||||
|
const cem = (nachher.json?.leute || []).find((x) => x.name === "Cem") || {};
|
||||||
|
|
||||||
|
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG. Ein Vergleich von zwei Nullen
|
||||||
|
waere gruen, ohne irgendetwas bewiesen zu haben. */
|
||||||
|
ok((cemVor.dran || 0) + 2 === (cem.dran || 0),
|
||||||
|
`Cems "dran" steigt um genau 2 (${cemVor.dran || 0} -> ${cem.dran || 0})`);
|
||||||
|
ok(cem.offen >= 1, `eine offene alte Aufgabe zaehlt (offen: ${cem.offen})`);
|
||||||
|
ok(cem.arbeit >= 1, `eine laufende alte Aufgabe zaehlt (arbeit: ${cem.arbeit})`);
|
||||||
|
ok((cemVor.gesamt || 0) + 2 === (cem.gesamt || 0),
|
||||||
|
`die abgebrochene zaehlt NICHT mit (gesamt ${cemVor.gesamt || 0} -> ${cem.gesamt || 0})`);
|
||||||
|
|
||||||
|
/* GEGENPROBE AM BRETT: Genau so viele, wie oben stehen, stehen auch
|
||||||
|
unten -- das ist Filipes Satz, als Messung. */
|
||||||
|
const brett = await rufe("/workspace/api/aufgaben", { keks: chef });
|
||||||
|
const untenCem = (brett.json?.aufgaben || [])
|
||||||
|
.filter((a) => a.verantwortlich_id === idCem
|
||||||
|
&& (a.status === "offen" || a.status === "arbeit" || a.status === "review"));
|
||||||
|
ok(untenCem.length >= 2 && untenCem.length === (cem.dran || 0),
|
||||||
|
`unten im Brett stehen genauso viele wie oben (${untenCem.length} = ${cem.dran})`);
|
||||||
|
|
||||||
|
/* Und die Person darf nicht aus der Liste fallen, nur weil sie
|
||||||
|
ueber den alten Weg etwas hat. */
|
||||||
|
ok(!!cem.id, "Cem steht in der Liste");
|
||||||
|
}
|
||||||
|
|
||||||
/* =====================================================================
|
/* =====================================================================
|
||||||
6. EINZELN -- der haeufigste Fall, und die alte Spalte stimmt noch
|
6. EINZELN -- der haeufigste Fall, und die alte Spalte stimmt noch
|
||||||
===================================================================== */
|
===================================================================== */
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ import {
|
|||||||
db, protokolliere, echteIp, darfAufgabenVerteilen, istDogFather, istHand,
|
db, protokolliere, echteIp, darfAufgabenVerteilen, istDogFather, istHand,
|
||||||
sitzungLesen,
|
sitzungLesen,
|
||||||
} from "./workspace.js";
|
} from "./workspace.js";
|
||||||
|
import { TEAM_DOGI_ROLLEN } from "./crew-adresse.js";
|
||||||
|
|
||||||
export const zuteilungRouter = express.Router();
|
export const zuteilungRouter = express.Router();
|
||||||
|
|
||||||
@@ -450,13 +451,59 @@ zuteilungRouter.post("/workspace/api/aufgaben/:id/bewerten", (req, res) => {
|
|||||||
* ABGELEITET AUS DEN ZUSTÄNDEN, nicht aus einer zweiten Tabelle: Eine
|
* ABGELEITET AUS DEN ZUSTÄNDEN, nicht aus einer zweiten Tabelle: Eine
|
||||||
* mitgeführte Zahl ist eine Zahl von gestern, sobald jemand etwas
|
* mitgeführte Zahl ist eine Zahl von gestern, sobald jemand etwas
|
||||||
* ändert und die Stelle vergisst. */
|
* ändert und die Stelle vergisst. */
|
||||||
|
/** Der Zustand einer Aufgabe, die jemandem auf dem ALTEN Weg gehoert.
|
||||||
|
*
|
||||||
|
* Die Aufgabentabelle kennt offen/arbeit/review/erledigt/abgebrochen,
|
||||||
|
* die Zuteilung kennt offen/angenommen/arbeit/erledigt/abgelehnt.
|
||||||
|
* "review" heisst: liegt zur Freigabe, ist also noch nicht vom Tisch --
|
||||||
|
* deshalb zaehlt es wie "arbeit". "abgebrochen" ist weder dran noch
|
||||||
|
* erledigt und zaehlt gar nicht mit; es erscheint auch im Brett nicht
|
||||||
|
* in den Spalten OFFEN und IN ARBEIT.
|
||||||
|
*
|
||||||
|
* Die Zuordnung steht hier an EINER Stelle. Wer sie an zwei Stellen
|
||||||
|
* schreibt, hat beim naechsten Statuswert eine, die niemand nachzieht. */
|
||||||
|
const STATUS_ALS_ZUSTAND = {
|
||||||
|
offen: "offen", arbeit: "arbeit", review: "arbeit", erledigt: "erledigt",
|
||||||
|
};
|
||||||
|
|
||||||
export function resuemeeFuer(personId) {
|
export function resuemeeFuer(personId) {
|
||||||
|
/* ZWEI QUELLEN, EIN ERGEBNIS (22.09.2026).
|
||||||
|
==========================================================
|
||||||
|
Filipe: "die aufgaben die man unten sieht soll man auch oben
|
||||||
|
sehen."
|
||||||
|
|
||||||
|
Gemessen an den echten Daten: aufgaben_zuteilung hatte NULL
|
||||||
|
Zeilen, waehrend im Brett zwei Aufgaben standen (OFFEN 1,
|
||||||
|
IN ARBEIT 1). Jede Person las oben "nichts zugeteilt" -- weil
|
||||||
|
diese Zaehlung nur die neue Tabelle kannte. Die Aufgaben hingen
|
||||||
|
am aelteren Feld `aufgaben.verantwortlich_id`, und das ist genau
|
||||||
|
das Feld, nach dem das BRETT gruppiert.
|
||||||
|
|
||||||
|
Eine Uebersicht, die eine andere Quelle liest als die Liste
|
||||||
|
darunter, widerspricht ihr frueher oder spaeter. Deshalb zaehlen
|
||||||
|
hier BEIDE Wege -- und keiner doppelt: Gibt es zu einer Aufgabe
|
||||||
|
eine Zuteilungszeile fuer diese Person, gewinnt die Zuteilung
|
||||||
|
(sie hat den genaueren Zustand: angenommen, abgelehnt, bewertet).
|
||||||
|
Nur wo keine Zeile existiert, zaehlt das alte Feld. */
|
||||||
const zeilen = db().prepare(`
|
const zeilen = db().prepare(`
|
||||||
SELECT z.zustand, z.bewertung, a.frist, a.status AS aufgabe_status
|
SELECT z.zustand, z.bewertung, a.frist, a.status AS aufgabe_status
|
||||||
FROM aufgaben_zuteilung z
|
FROM aufgaben_zuteilung z
|
||||||
JOIN aufgaben a ON a.id = z.aufgabe_id
|
JOIN aufgaben a ON a.id = z.aufgabe_id
|
||||||
WHERE z.person_id = ?`).all(Number(personId));
|
WHERE z.person_id = ?`).all(Number(personId));
|
||||||
|
|
||||||
|
const alte = db().prepare(`
|
||||||
|
SELECT a.status, a.frist
|
||||||
|
FROM aufgaben a
|
||||||
|
WHERE a.verantwortlich_id = ?
|
||||||
|
AND NOT EXISTS (SELECT 1 FROM aufgaben_zuteilung z
|
||||||
|
WHERE z.aufgabe_id = a.id AND z.person_id = a.verantwortlich_id)
|
||||||
|
`).all(Number(personId));
|
||||||
|
for (const a of alte) {
|
||||||
|
const zustand = STATUS_ALS_ZUSTAND[a.status];
|
||||||
|
if (!zustand) continue; /* abgebrochen: zaehlt nirgends */
|
||||||
|
zeilen.push({ zustand, bewertung: null, frist: a.frist, aufgabe_status: a.status });
|
||||||
|
}
|
||||||
|
|
||||||
const heute = new Date().toISOString().slice(0, 10);
|
const heute = new Date().toISOString().slice(0, 10);
|
||||||
const zaehl = { offen: 0, angenommen: 0, arbeit: 0, erledigt: 0, abgelehnt: 0 };
|
const zaehl = { offen: 0, angenommen: 0, arbeit: 0, erledigt: 0, abgelehnt: 0 };
|
||||||
let ueberfaellig = 0, gelobt = 0, zuVerbessern = 0;
|
let ueberfaellig = 0, gelobt = 0, zuVerbessern = 0;
|
||||||
@@ -510,11 +557,29 @@ zuteilungRouter.get("/workspace/api/aufgaben/team-resuemee", (req, res) => {
|
|||||||
Abgeleitet aus der Rollenliste dieses Hauses statt aus einer
|
Abgeleitet aus der Rollenliste dieses Hauses statt aus einer
|
||||||
eigenen Aufzählung — wer morgen eine Rolle hinzufügt, muss hier
|
eigenen Aufzählung — wer morgen eine Rolle hinzufügt, muss hier
|
||||||
nichts nachziehen. */
|
nichts nachziehen. */
|
||||||
|
/* WER IN DER LISTE STEHT -- ABGELEITET, NICHT AUFGEZAEHLT.
|
||||||
|
==========================================================
|
||||||
|
Die Rollen des Hauses stehen immer da, auch mit null Aufgaben:
|
||||||
|
Wer frei ist, ist die haeufigste Frage beim Verteilen.
|
||||||
|
|
||||||
|
Dazu kommt JEDE aktive Person, der im Brett eine Aufgabe
|
||||||
|
gehoert. Ohne diesen zweiten Teil koennte im Brett eine Aufgabe
|
||||||
|
stehen, deren Mensch oben fehlt -- genau der Widerspruch, den
|
||||||
|
Filipe am 22.09. gemeldet hat, nur an anderer Stelle. So kann
|
||||||
|
das nicht wieder entstehen: Die Liste folgt den Aufgaben. */
|
||||||
|
const rollen = [...TEAM_DOGI_ROLLEN];
|
||||||
|
const platz = rollen.map(() => "?").join(",");
|
||||||
const leute = db().prepare(`
|
const leute = db().prepare(`
|
||||||
SELECT id, name, rolle FROM personen
|
SELECT id, name, rolle FROM personen
|
||||||
WHERE aktiv = 1 AND rolle IN ('modi','hand','linke')
|
WHERE aktiv = 1
|
||||||
ORDER BY CASE rolle WHEN 'hand' THEN 0 WHEN 'linke' THEN 1 ELSE 2 END,
|
AND (rolle IN (${platz})
|
||||||
name COLLATE NOCASE`).all();
|
OR id IN (SELECT verantwortlich_id FROM aufgaben
|
||||||
|
WHERE verantwortlich_id IS NOT NULL)
|
||||||
|
OR id IN (SELECT person_id FROM aufgaben_zuteilung))
|
||||||
|
AND rolle NOT IN ('creator','scout','manager','spicy','gast')
|
||||||
|
ORDER BY CASE rolle WHEN 'admin' THEN 0 WHEN 'hand' THEN 1
|
||||||
|
WHEN 'linke' THEN 2 ELSE 3 END,
|
||||||
|
name COLLATE NOCASE`).all(...rollen);
|
||||||
res.json({
|
res.json({
|
||||||
leute: leute.map((p) => ({ ...p, ...resuemeeFuer(p.id) })),
|
leute: leute.map((p) => ({ ...p, ...resuemeeFuer(p.id) })),
|
||||||
darf_bewerten: true,
|
darf_bewerten: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user