diff --git a/server/src/lib/entries.js b/server/src/lib/entries.js
index d16785f..c3258dd 100644
--- a/server/src/lib/entries.js
+++ b/server/src/lib/entries.js
@@ -12,7 +12,7 @@ import { userFilter } from './access.js';
* (Topfbudget / alle auf dem Topf gebuchten Stunden). Nur
* intern, in Reports per Schalter zuschaltbar.
*/
-export async function loadEntries(settings, { from, to, userIds = null, customerId, projectId, taskId } = {}) {
+export async function loadEntries(settings, { from, to, userIds = null, customerId, projectId, taskId, skipNonBillableProjects = false } = {}) {
// Administratoren sind keine Mitarbeiter - ihre Zeiten zaehlen nirgends mit.
const where = ["u.role <> 'admin'"];
const params = [];
@@ -39,6 +39,9 @@ export async function loadEntries(settings, { from, to, userIds = null, customer
where.push('e.task_id = ?');
params.push(Number(taskId));
}
+ // Fuer Auswertungen, die nur das Kundengeschaeft zeigen sollen: interne
+ // Projekte und Abwesenheiten bleiben draussen.
+ if (skipNonBillableProjects) where.push("p.type <> 'non_billable'");
const [rows] = await pool.query(
`SELECT e.id, e.user_id, e.project_id, e.task_id, e.pot_id, e.entry_date, e.minutes, e.note, e.billable,
diff --git a/server/src/routes/exports.js b/server/src/routes/exports.js
index 23f4484..b0b4d94 100644
--- a/server/src/routes/exports.js
+++ b/server/src/routes/exports.js
@@ -244,6 +244,7 @@ router.get('/report', async (req, res, next) => {
info: [
['Kunde', customerName || 'Alle Kunden'],
['Festpreisprojekte', report.include_fixed ? 'im Betrag enthalten' : 'nicht im Betrag enthalten'],
+ ...(report.hide_non_billable ? [['Nicht abrechenbare Projekte', 'ausgeblendet']] : []),
],
kpis: [
['Gesamtstunden', hoursDe(s.minutes)],
diff --git a/server/src/routes/reports.js b/server/src/routes/reports.js
index 4cb2053..578da54 100644
--- a/server/src/routes/reports.js
+++ b/server/src/routes/reports.js
@@ -39,6 +39,9 @@ export async function buildTimeReport(viewer, query) {
const from = query.from;
const to = query.to;
const includeFixed = query.include_fixed === '1' || query.include_fixed === 'true';
+ // Schalter im Report: nicht abrechenbare Projekte (intern, Abwesenheiten)
+ // ausblenden - dann zeigt die Auswertung nur das Kundengeschaeft.
+ const hideNonBillable = query.hide_non_billable === '1' || query.hide_non_billable === 'true';
const userIds = await reportUserIds(viewer, query.team);
const entries = await loadEntries(settings, {
from,
@@ -46,6 +49,7 @@ export async function buildTimeReport(viewer, query) {
userIds,
customerId: query.customer_id,
projectId: query.project_id,
+ skipNonBillableProjects: hideNonBillable,
});
const filter = userFilter(userIds, 'id');
@@ -91,6 +95,7 @@ export async function buildTimeReport(viewer, query) {
return {
range: { from, to },
include_fixed: includeFixed,
+ hide_non_billable: hideNonBillable,
summary: {
minutes,
billable_minutes: billable,
diff --git a/src/components/reports/Reports.tsx b/src/components/reports/Reports.tsx
index d182c06..0d418eb 100644
--- a/src/components/reports/Reports.tsx
+++ b/src/components/reports/Reports.tsx
@@ -75,6 +75,9 @@ const TimeReport: React.FC = () => {
const [customerId, setCustomerId] = useState