feat(export): Nachweis fuer andere Berater mit deren Projekten

Wer in der Buchung einen Kollegen ausgewaehlt hatte und dann exportierte,
bekam im Dialog die eigenen Kunden und Projekte zur Auswahl - fuer einen
Nachweis, der jemand anderem gehoert.

Der Dialog laedt die Projekte jetzt zu der Person, fuer die der Nachweis
entsteht, und laedt neu, wenn man die Person darin wechselt; die alte
Kunden- und Projektauswahl wird dabei verworfen, weil sie nicht mehr
passt. Bei "Alle Mitarbeiter" stehen alle sichtbaren Projekte zur Wahl.

Dafuer nimmt GET /projects ein ?user_id an. Wer fremde Projekte sehen
darf, entscheidet dieselbe Sicht wie bei den Zeiten: Mitarbeiter bekommen
403, Vorgesetzte nur ihr Team, Management alle. Die Sammelauswahl heisst
fuer Management "Alle Mitarbeiter" statt "Alle meine Mitarbeiter" - sie
sieht ohnehin jeden.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
schakal00783
2026-09-22 10:44:49 +02:00
co-authored by Claude Opus 5
parent ff71cb40e1
commit dd42fba1cb
3 changed files with 60 additions and 10 deletions
+17 -3
View File
@@ -1,6 +1,7 @@
import express from 'express';
import { pool, withTransaction } from '../db.js';
import { hasRole, requireRole } from '../middleware/auth.js';
import { visibleUserIds } from '../lib/access.js';
import { getSettings } from '../lib/settings.js';
import { parseDate } from '../lib/dates.js';
import {
@@ -148,16 +149,29 @@ async function refreshBillable(conn, projectId) {
}
// Liste. Mitarbeiter sehen nur zugewiesene Projekte, ohne Betraege.
// ?scope=mine liefert auch fuer Fuehrungsrollen nur die eigenen (Buchungsdialog).
/*
* ?scope=mine liefert auch fuer Fuehrungsrollen nur die eigenen (Buchungsdialog).
* ?user_id=<id> die Projekte einer anderen Person - gebraucht, wenn eine
* Fuehrungskraft den Stundennachweis fuer jemanden aus ihrem Team baut. Wer
* eingesehen werden darf, entscheidet dieselbe Sicht wie bei den Zeiten.
*/
router.get('/', async (req, res, next) => {
try {
const settings = await getSettings();
let memberId = req.user.id;
if (req.query.user_id && Number(req.query.user_id) !== req.user.id) {
if (!hasRole(req.user, 'lead')) return res.status(403).json({ error: 'Keine Einsicht in fremde Projekte.' });
const visible = await visibleUserIds(req.user);
const wanted = Number(req.query.user_id);
if (visible !== null && !visible.includes(wanted)) return res.status(403).json({ error: 'Keine Einsicht in diese Projekte.' });
memberId = wanted;
}
// Mitarbeiter und Externe sehen nur zugewiesene Projekte.
const mineOnly = !hasRole(req.user, 'lead') || req.query.scope === 'mine';
const mineOnly = !hasRole(req.user, 'lead') || req.query.scope === 'mine' || memberId !== req.user.id;
const projects = await loadProjects(
settings,
mineOnly
? { where: 'p.id IN (SELECT project_id FROM pulse_project_members WHERE user_id = ?)', params: [req.user.id] }
? { where: 'p.id IN (SELECT project_id FROM pulse_project_members WHERE user_id = ?)', params: [memberId] }
: {}
);
res.json(hasRole(req.user, 'lead') ? projects : projects.map(stripAmounts));