Files
Arick B 680ca15f5c Fix Time Log: await report filters before executing the query (#10120)
* fix(time-log): await report filters before executing the query

getFilterTimeLogQuery became async (it awaits
ManagedEmployeeService.canManageEmployees), but five report methods still
invoked it inside a synchronous TypeORM `where()` callback without awaiting
it. Whenever the manager check was reached, the callback returned before any
`andWhere` ran, so getMany() built the SQL with no WHERE clause at all:
tenant, organization, employee and date filters were all dropped.

Call the helper directly with `await` before getMany(), as getTimeLogs and
getWeeklyReport already do. The synchronous paths (CHANGE_SELECTED_EMPLOYEE,
onlyMe, no employeeIds) build the same SQL as before, since no clause existed
prior to the call.

Affected: getDailyReportCharts, getDailyReport, getOwedAmountReport,
getOwedAmountReportCharts, getTimeLimit.

The spec drives every report method through a query-builder double that
mirrors TypeORM's synchronous `where(callback)` semantics and asserts the
scoping clauses are present when the query executes. It fails on the
previous code for the five methods above and passes for the admin and
onlyMe paths on both versions.

* fix(timesheet): await the filter helper before executing the query

getFilterTimesheetQuery is declared async and was invoked inside a
synchronous `where()` callback without being awaited in getTimeSheetCount
and getTimeSheets. It contains no await today, so the clauses still land
before the query runs, but the first await added to it would silently drop
every filter, exactly what happened in the time-log reports.

Call it directly with `await`, matching the time-log service, and cover both
methods with a spec asserting the tenant and organization clauses are
present at execution time.

* chore: ignore the local graphify output

graphify-out/ holds the locally generated knowledge graph used to navigate
the codebase. Its graph.json alone weighs over 100 MB, so it must never be
committed.

* test(time-tracking): share the query-builder double and make the timesheet guard real

Review follow-up on the two new specs.

The recording SelectQueryBuilder double, the RequestContext spies and the
executed-clause helper were duplicated between the time-log and timesheet
specs (SonarCloud: 26% duplicated new lines). They now live once in
time-tracking/testing/, which the lib build excludes and the spec tsconfig
includes.

The timesheet spec passed with or without the direct await, because
getFilterTimesheetQuery has no awaited operation today. It now suspends the
helper through a spy before delegating to the real implementation, the way
the first await added to it would, so restoring the previous
where(callback) call makes both tests fail with an empty clause list. The
afterEach lets a dangling helper settle while the context mocks are still
in place, so that regression fails on the assertions instead of crashing
the worker.

Also rewords a comment that used a word outside the cspell dictionary.

* fix(timesheet): drop the stray optional chaining on request

getTimeSheets read `request?.relations` while every other access in the
method, including the one right after it, dereferences `request` directly
(DeepScan INSUFFICIENT_NULL_CHECK). The parameter is required by the
signature, so the optional chaining was the inconsistent part.

* test(time-tracking): evaluate Brackets in the query-builder double

Review follow-up. The double stored a `Brackets` without running its
factory, so the predicates inside the brackets and their parameters were
never recorded: the specs checked that a bracketed clause was attached but
not what it contained.

The double now runs the factory against a nested builder as soon as the
brackets are added, the way `QueryBuilder.getWhereCondition` does, and
`executedFilters` flattens the nested predicates in after their brackets.
The time-log spec asserts both startedAt predicates and the formatted
startDate/endDate parameters; the timesheet spec asserts the object-literal
predicate with the Between range and the employee id a caller without
CHANGE_SELECTED_EMPLOYEE is narrowed to.
2026-09-06 21:51:11 +02:00

165 lines
3.7 KiB
Plaintext

# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# dependencies
node_modules/
# sqlite3 database
*.sqlite3
*.sqlite3-journal
*.sqlite3-shm
*.sqlite3-wal
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
lerna-debug.log
testem.log
/typings
migrations.json
# System Files
.DS_Store
Thumbs.db
.env
.env.prod
# Nx
.nx
# Typeorm Logs
ormlogs.log
# Cache File
/.cache
/apps/**/.cache
/packages/**/.cache
/packages/**/dist
/.deploy/nginx/log
/apps/agent/src/environments/environment.prod.ts
/apps/agent/src/environments/environment.ts
/apps/gauzy/src/environments/environment.prod.ts
/apps/gauzy/src/environments/environment.ts
/packages/ui-config/src/lib/environments/environment.prod.ts
/packages/ui-config/src/lib/environments/environment.ts
/apps/desktop-timer/src/environments/environment.prod.ts
/apps/desktop-timer/src/environments/environment.ts
/apps/desktop/src/environments/environment.prod.ts
/apps/desktop/src/environments/environment.ts
/apps/server/src/environments/environment.prod.ts
/apps/server/src/environments/environment.ts
/apps/server-api/src/environments/environment.prod.ts
/apps/server-api/src/environments/environment.ts
/export
/import
/apps/api/*.tsbuildinfo
megalinter-reports/
/.deploy/jitsu/configurator/data/logs/*.log
/.deploy/jitsu/server/data/logs/*.log
/.deploy/redis/data/*.rdb
/.deploy/redis/jitsu_users_recognition/data/*.rdb
/.deploy/jitsu/server/data/logs/events
# No need to duplicate translations
/apps/agent/src/assets/i18n
/apps/desktop-timer/src/assets/i18n
/apps/desktop/src/assets/i18n
/apps/server/src/assets/i18n
/apps/server-api/src/assets/i18n
# No need to duplicate desktop icons
/apps/agent/src/icons
/apps/desktop-timer/src/icons
/apps/desktop/src/icons
/apps/server/src/icons
/apps/server-api/src/icons
# Generated platform logo
apps/agent/src/assets/images/logos/platform_logo.*
apps/desktop-timer/src/assets/images/logos/platform_logo.*
apps/desktop/src/assets/images/logos/platform_logo.*
apps/server/src/assets/images/logos/platform_logo.*
apps/server-api/src/assets/images/logos/platform_logo.*
# Generated No internet logo
apps/agent/src/assets/images/logos/no_internet_logo.*
apps/desktop-timer/src/assets/images/logos/no_internet_logo.*
apps/desktop/src/assets/images/logos/no_internet_logo.*
apps/server/src/assets/images/logos/no_internet_logo.*
apps/server-api/src/assets/images/logos/no_internet_logo.*
# Generated desktop icon tray
apps/agent/src/assets/icons/tray
apps/desktop-timer/src/assets/icons/tray
apps/desktop/src/assets/icons/tray
apps/server/src/assets/icons/tray
apps/server-api/src/assets/icons/tray
# Generated desktop 512x512 icon
apps/agent/src/assets/icons/desktop_logo_512x512.png
apps/desktop-timer/src/assets/icons/desktop_logo_512x512.png
apps/desktop/src/assets/icons/desktop_logo_512x512.png
apps/server/src/assets/icons/desktop_logo_512x512.png
apps/server-api/src/assets/icons/desktop_logo_512x512.png
# Generated desktop icon menu
apps/agent/src/assets/icons/menu
apps/desktop-timer/src/assets/icons/menu
apps/desktop/src/assets/icons/menu
apps/server/src/assets/icons/menu
apps/server-api/src/assets/icons/menu
.angular
# Ignore cursor AI Rules
.cursor/rules/codacy.mdc
.cursor/rules/nx-rules.mdc
.github/instructions/nx.instructions.md
# MCP Server certificates (contains sensitive data)
**/certs/**
**/certs/**/*.{pem,key,crt,csr,pfx,p12}
!**/certs/**/README.md
!**/certs/**/.gitkeep
/graphify-out
/Tempnx-console-tmp**/**