@open-mercato/core 0.7.1-develop.7178.1.ab93fbaf4e → 0.7.1-develop.7180.1.9717fbbb43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/staff_time_entry/index.js +14 -0
- package/dist/generated/entities/staff_time_entry/index.js.map +2 -2
- package/dist/generated/entities/staff_time_entry_tag/index.js +15 -0
- package/dist/generated/entities/staff_time_entry_tag/index.js.map +7 -0
- package/dist/generated/entities/staff_time_project/index.js +16 -0
- package/dist/generated/entities/staff_time_project/index.js.map +2 -2
- package/dist/generated/entities/staff_time_report/index.js +57 -0
- package/dist/generated/entities/staff_time_report/index.js.map +7 -0
- package/dist/generated/entities/staff_time_report_entry/index.js +27 -0
- package/dist/generated/entities/staff_time_report_entry/index.js.map +7 -0
- package/dist/generated/entities/staff_time_report_event/index.js +21 -0
- package/dist/generated/entities/staff_time_report_event/index.js.map +7 -0
- package/dist/generated/entities/staff_time_report_project/index.js +15 -0
- package/dist/generated/entities/staff_time_report_project/index.js.map +7 -0
- package/dist/generated/entities/staff_time_tag/index.js +21 -0
- package/dist/generated/entities/staff_time_tag/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task/index.js +37 -0
- package/dist/generated/entities/staff_time_task/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task_comment/index.js +21 -0
- package/dist/generated/entities/staff_time_task_comment/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task_status/index.js +29 -0
- package/dist/generated/entities/staff_time_task_status/index.js.map +7 -0
- package/dist/generated/entities/staff_time_task_tag/index.js +15 -0
- package/dist/generated/entities/staff_time_task_tag/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +11 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +149 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/timesheetFixtures.js +7 -0
- package/dist/helpers/integration/timesheetFixtures.js.map +2 -2
- package/dist/modules/auth/cli.js +16 -0
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/lib/backendChrome.js +1 -0
- package/dist/modules/auth/lib/backendChrome.js.map +2 -2
- package/dist/modules/customer_accounts/lib/customerRoleAcls.js +44 -0
- package/dist/modules/customer_accounts/lib/customerRoleAcls.js.map +7 -0
- package/dist/modules/customer_accounts/setup.js +1 -28
- package/dist/modules/customer_accounts/setup.js.map +2 -2
- package/dist/modules/data_sync/api/options.js +2 -0
- package/dist/modules/data_sync/api/options.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +39 -17
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/lib/start-controls.js +42 -0
- package/dist/modules/data_sync/lib/start-controls.js.map +7 -0
- package/dist/modules/staff/acl.js +9 -1
- package/dist/modules/staff/acl.js.map +2 -2
- package/dist/modules/staff/ai-agents.js +142 -0
- package/dist/modules/staff/ai-agents.js.map +7 -0
- package/dist/modules/staff/ai-tools/time-tracking-pack.js +348 -0
- package/dist/modules/staff/ai-tools/time-tracking-pack.js.map +7 -0
- package/dist/modules/staff/ai-tools/types.js +54 -0
- package/dist/modules/staff/ai-tools/types.js.map +7 -0
- package/dist/modules/staff/ai-tools.js +8 -0
- package/dist/modules/staff/ai-tools.js.map +7 -0
- package/dist/modules/staff/analytics.js +84 -1
- package/dist/modules/staff/analytics.js.map +2 -2
- package/dist/modules/staff/api/guards.js +37 -3
- package/dist/modules/staff/api/guards.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/accept/route.js +1 -3
- package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/reject/route.js +1 -3
- package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
- package/dist/modules/staff/api/portal/time-reports/[id]/route.js +131 -0
- package/dist/modules/staff/api/portal/time-reports/[id]/route.js.map +7 -0
- package/dist/modules/staff/api/portal/time-reports/route.js +179 -0
- package/dist/modules/staff/api/portal/time-reports/route.js.map +7 -0
- package/dist/modules/staff/api/team-members/self/route.js +1 -3
- package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/assign/route.js +1 -3
- package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/unassign/route.js +1 -3
- package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +174 -0
- package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +7 -0
- package/dist/modules/staff/api/timesheets/access-requests/route.js +226 -0
- package/dist/modules/staff/api/timesheets/access-requests/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +15 -8
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/route.js +13 -1
- package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js +42 -0
- package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js.map +7 -0
- package/dist/modules/staff/api/timesheets/my-work/route.js +383 -0
- package/dist/modules/staff/api/timesheets/my-work/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js +14 -2
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +168 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +246 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +183 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +164 -0
- package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/preview/route.js +360 -0
- package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/route.js +316 -0
- package/dist/modules/staff/api/timesheets/reports/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/reports/shared.js +63 -0
- package/dist/modules/staff/api/timesheets/reports/shared.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +164 -0
- package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js +168 -0
- package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/route.js +199 -0
- package/dist/modules/staff/api/timesheets/settings/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/access.js +76 -0
- package/dist/modules/staff/api/timesheets/tags/access.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +235 -0
- package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/route.js +160 -0
- package/dist/modules/staff/api/timesheets/tags/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +233 -0
- package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/task-statuses/route.js +188 -0
- package/dist/modules/staff/api/timesheets/task-statuses/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +399 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +210 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/route.js +333 -0
- package/dist/modules/staff/api/timesheets/tasks/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +228 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +29 -10
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +31 -18
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +21 -7
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +27 -7
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +215 -32
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +378 -0
- package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +340 -0
- package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-entries/route.js +238 -26
- package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +23 -8
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +209 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +59 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/route.js +264 -22
- package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/board/page.js +110 -0
- package/dist/modules/staff/backend/staff/time-tracking/board/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +981 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.js +583 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.meta.js +15 -0
- package/dist/modules/staff/backend/staff/time-tracking/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js +65 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +229 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +1014 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js +97 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.js +1040 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js +19 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +353 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +457 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js +697 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js +16 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.js +174 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +546 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js +710 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js +646 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js.map +7 -0
- package/dist/modules/staff/backend/staff/timesheets/page.js +4 -793
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.meta.js +2 -7
- package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +5 -136
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +1 -7
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +5 -445
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +3 -3
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +1 -7
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +4 -76
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +1 -7
- package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -613
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +2 -17
- package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +2 -2
- package/dist/modules/staff/ce.js +40 -0
- package/dist/modules/staff/ce.js.map +2 -2
- package/dist/modules/staff/cli.js +166 -1
- package/dist/modules/staff/cli.js.map +2 -2
- package/dist/modules/staff/commands/index.js +5 -0
- package/dist/modules/staff/commands/index.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-entries.js +569 -21
- package/dist/modules/staff/commands/timesheets-entries.js.map +3 -3
- package/dist/modules/staff/commands/timesheets-projects.js +450 -7
- package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-reports.js +1036 -0
- package/dist/modules/staff/commands/timesheets-reports.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-tags.js +1015 -0
- package/dist/modules/staff/commands/timesheets-tags.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-task-comments.js +438 -0
- package/dist/modules/staff/commands/timesheets-task-comments.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-task-statuses.js +723 -0
- package/dist/modules/staff/commands/timesheets-task-statuses.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-tasks.js +834 -0
- package/dist/modules/staff/commands/timesheets-tasks.js.map +7 -0
- package/dist/modules/staff/data/enrichers.js +426 -12
- package/dist/modules/staff/data/enrichers.js.map +2 -2
- package/dist/modules/staff/data/entities.js +552 -3
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/staff/data/extensions.js +41 -0
- package/dist/modules/staff/data/extensions.js.map +7 -0
- package/dist/modules/staff/data/validators.js +254 -9
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/di.js +42 -1
- package/dist/modules/staff/di.js.map +2 -2
- package/dist/modules/staff/events.js +84 -6
- package/dist/modules/staff/events.js.map +2 -2
- package/dist/modules/staff/events.payloads.js +158 -0
- package/dist/modules/staff/events.payloads.js.map +7 -0
- package/dist/modules/staff/extension-points.js +261 -0
- package/dist/modules/staff/extension-points.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +138 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js +12 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +133 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js +19 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js.map +7 -0
- package/dist/modules/staff/lib/crud.js +11 -1
- package/dist/modules/staff/lib/crud.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/access.js +92 -0
- package/dist/modules/staff/lib/time-tracking/access.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/billability.js +39 -0
- package/dist/modules/staff/lib/time-tracking/billability.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/capacity.js +68 -0
- package/dist/modules/staff/lib/time-tracking/capacity.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/componentContracts.js +15 -0
- package/dist/modules/staff/lib/time-tracking/componentContracts.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/cost.js +82 -0
- package/dist/modules/staff/lib/time-tracking/cost.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/duration.js +55 -0
- package/dist/modules/staff/lib/time-tracking/duration.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/featureAccess.js +41 -0
- package/dist/modules/staff/lib/time-tracking/featureAccess.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/interval.js +72 -0
- package/dist/modules/staff/lib/time-tracking/interval.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js +88 -0
- package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/moneyVisibility.js +10 -0
- package/dist/modules/staff/lib/time-tracking/moneyVisibility.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/overlap.js +87 -0
- package/dist/modules/staff/lib/time-tracking/overlap.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js +27 -0
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/portalReports.js +16 -0
- package/dist/modules/staff/lib/time-tracking/portalReports.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/projectCode.js +135 -0
- package/dist/modules/staff/lib/time-tracking/projectCode.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/reapplyRounding.js +187 -0
- package/dist/modules/staff/lib/time-tracking/reapplyRounding.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/recalculationRunner.js +80 -0
- package/dist/modules/staff/lib/time-tracking/recalculationRunner.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/recalculations.js +56 -0
- package/dist/modules/staff/lib/time-tracking/recalculations.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/registries/invoke.js +63 -0
- package/dist/modules/staff/lib/time-tracking/registries/invoke.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/registries/registry.js +62 -0
- package/dist/modules/staff/lib/time-tracking/registries/registry.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/registries/scope.js +21 -0
- package/dist/modules/staff/lib/time-tracking/registries/scope.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/rollup.js +34 -0
- package/dist/modules/staff/lib/time-tracking/rollup.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/rounding.js +66 -0
- package/dist/modules/staff/lib/time-tracking/rounding.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/roundingImpact.js +39 -0
- package/dist/modules/staff/lib/time-tracking/roundingImpact.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js +214 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/settings.js +87 -0
- package/dist/modules/staff/lib/time-tracking/settings.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/sqlInClause.js +9 -0
- package/dist/modules/staff/lib/time-tracking/sqlInClause.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/timeEntrySources.js +48 -0
- package/dist/modules/staff/lib/time-tracking/timeEntrySources.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +283 -0
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js +324 -0
- package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js +121 -0
- package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js +188 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js +89 -0
- package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +855 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +360 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js +259 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js +238 -0
- package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +130 -0
- package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js +98 -0
- package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js +27 -0
- package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js +166 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js +295 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +212 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js +729 -0
- package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +217 -0
- package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js +158 -0
- package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +224 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +93 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +1196 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +176 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js +307 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js +284 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js +73 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js +1499 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js +95 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js +188 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js +61 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js +45 -0
- package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +176 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +82 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js +5 -0
- package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +152 -0
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js +92 -0
- package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +111 -0
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js +243 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js +151 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +105 -0
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js +132 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js +205 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js +53 -0
- package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js +77 -0
- package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js +151 -0
- package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js.map +7 -0
- package/dist/modules/staff/lib/timeTrackingSeeds.js +809 -0
- package/dist/modules/staff/lib/timeTrackingSeeds.js.map +7 -0
- package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js +2 -3
- package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js.map +2 -2
- package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js +152 -0
- package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js +36 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js +66 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js +78 -0
- package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js +81 -0
- package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects/reportSelection.js +44 -0
- package/dist/modules/staff/lib/timesheets-projects/reportSelection.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js +169 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js +22 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +51 -1
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js +70 -0
- package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +63 -0
- package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +170 -0
- package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/pdf.js +205 -0
- package/dist/modules/staff/lib/timesheets-reports/pdf.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js +68 -0
- package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js +135 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js +48 -0
- package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExport.js +262 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExport.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js +34 -0
- package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js +79 -0
- package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportLabels.js +11 -0
- package/dist/modules/staff/lib/timesheets-reports/reportLabels.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportReference.js +83 -0
- package/dist/modules/staff/lib/timesheets-reports/reportReference.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportRows.js +42 -0
- package/dist/modules/staff/lib/timesheets-reports/reportRows.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js +107 -0
- package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/reportTotals.js +289 -0
- package/dist/modules/staff/lib/timesheets-reports/reportTotals.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-reports/xlsx.js +145 -0
- package/dist/modules/staff/lib/timesheets-reports/xlsx.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js +116 -0
- package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js +50 -0
- package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js +27 -0
- package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js +65 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js +31 -0
- package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js +31 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js +17 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskReference.js +51 -0
- package/dist/modules/staff/lib/timesheets-tasks/taskReference.js.map +7 -0
- package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +11 -4
- package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-ui/ListView.js +369 -111
- package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +47 -2
- package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +2 -2
- package/dist/modules/staff/migrations/Migration20260813073131_staff.js +79 -0
- package/dist/modules/staff/migrations/Migration20260813073131_staff.js.map +7 -0
- package/dist/modules/staff/migrations/Migration20260824143357_staff.js +15 -0
- package/dist/modules/staff/migrations/Migration20260824143357_staff.js.map +7 -0
- package/dist/modules/staff/notifications.client.js +16 -0
- package/dist/modules/staff/notifications.client.js.map +7 -0
- package/dist/modules/staff/notifications.handlers.js +80 -0
- package/dist/modules/staff/notifications.handlers.js.map +7 -0
- package/dist/modules/staff/notifications.js +168 -0
- package/dist/modules/staff/notifications.js.map +2 -2
- package/dist/modules/staff/search.js +159 -1
- package/dist/modules/staff/search.js.map +2 -2
- package/dist/modules/staff/setup.js +20 -1
- package/dist/modules/staff/setup.js.map +2 -2
- package/dist/modules/staff/subscribers/time-project-access-requested-notification.js +68 -0
- package/dist/modules/staff/subscribers/time-project-access-requested-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js +149 -0
- package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/time-report-approved-notification.js +78 -0
- package/dist/modules/staff/subscribers/time-report-approved-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/time-report-portal-broadcast.js +78 -0
- package/dist/modules/staff/subscribers/time-report-portal-broadcast.js.map +7 -0
- package/dist/modules/staff/translations.js +4 -1
- package/dist/modules/staff/translations.js.map +2 -2
- package/dist/modules/staff/widgets/components.js +7 -0
- package/dist/modules/staff/widgets/components.js.map +7 -0
- package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +5 -4
- package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +2 -2
- package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js +135 -0
- package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js.map +7 -0
- package/dist/modules/staff/widgets/notifications/index.js +5 -0
- package/dist/modules/staff/widgets/notifications/index.js.map +7 -0
- package/dist/modules/staff/workers/timesheets-reapply-rounding.js +43 -0
- package/dist/modules/staff/workers/timesheets-reapply-rounding.js.map +7 -0
- package/generated/entities/staff_time_entry/index.ts +7 -0
- package/generated/entities/staff_time_entry_tag/index.ts +6 -0
- package/generated/entities/staff_time_project/index.ts +8 -0
- package/generated/entities/staff_time_report/index.ts +27 -0
- package/generated/entities/staff_time_report_entry/index.ts +12 -0
- package/generated/entities/staff_time_report_event/index.ts +9 -0
- package/generated/entities/staff_time_report_project/index.ts +6 -0
- package/generated/entities/staff_time_tag/index.ts +9 -0
- package/generated/entities/staff_time_task/index.ts +17 -0
- package/generated/entities/staff_time_task_comment/index.ts +9 -0
- package/generated/entities/staff_time_task_status/index.ts +13 -0
- package/generated/entities/staff_time_task_tag/index.ts +6 -0
- package/generated/entities.ids.generated.ts +11 -1
- package/generated/entity-fields-registry.ts +149 -0
- package/package.json +7 -7
- package/src/helpers/integration/timesheetFixtures.ts +31 -1
- package/src/modules/auth/README.md +1 -1
- package/src/modules/auth/cli.ts +35 -1
- package/src/modules/auth/i18n/de.json +7 -0
- package/src/modules/auth/i18n/en.json +7 -0
- package/src/modules/auth/i18n/es.json +7 -0
- package/src/modules/auth/i18n/ko.json +7 -0
- package/src/modules/auth/i18n/pl.json +7 -0
- package/src/modules/auth/lib/backendChrome.tsx +1 -0
- package/src/modules/customer_accounts/lib/customerRoleAcls.ts +79 -0
- package/src/modules/customer_accounts/setup.ts +1 -45
- package/src/modules/data_sync/AGENTS.md +34 -0
- package/src/modules/data_sync/api/options.ts +2 -0
- package/src/modules/data_sync/backend/data-sync/page.tsx +82 -33
- package/src/modules/data_sync/i18n/de.json +1 -0
- package/src/modules/data_sync/i18n/en.json +1 -0
- package/src/modules/data_sync/i18n/es.json +1 -0
- package/src/modules/data_sync/i18n/ko.json +1 -0
- package/src/modules/data_sync/i18n/pl.json +1 -0
- package/src/modules/data_sync/lib/adapter.ts +45 -0
- package/src/modules/data_sync/lib/start-controls.ts +89 -0
- package/src/modules/staff/AGENTS.md +769 -1
- package/src/modules/staff/acl.ts +9 -0
- package/src/modules/staff/ai-agents.ts +189 -0
- package/src/modules/staff/ai-tools/time-tracking-pack.ts +494 -0
- package/src/modules/staff/ai-tools/types.ts +82 -0
- package/src/modules/staff/ai-tools.ts +13 -0
- package/src/modules/staff/analytics.ts +113 -0
- package/src/modules/staff/api/guards.ts +85 -3
- package/src/modules/staff/api/leave-requests/accept/route.ts +0 -2
- package/src/modules/staff/api/leave-requests/reject/route.ts +0 -2
- package/src/modules/staff/api/portal/time-reports/[id]/route.ts +182 -0
- package/src/modules/staff/api/portal/time-reports/route.ts +270 -0
- package/src/modules/staff/api/team-members/self/route.ts +0 -2
- package/src/modules/staff/api/team-members/tags/assign/route.ts +0 -2
- package/src/modules/staff/api/team-members/tags/unassign/route.ts +0 -2
- package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +292 -0
- package/src/modules/staff/api/timesheets/access-requests/route.ts +299 -0
- package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +15 -7
- package/src/modules/staff/api/timesheets/my-projects/route.ts +14 -1
- package/src/modules/staff/api/timesheets/my-work/myWorkAggregate.ts +90 -0
- package/src/modules/staff/api/timesheets/my-work/route.ts +475 -0
- package/src/modules/staff/api/timesheets/projects/kpis/route.ts +15 -2
- package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +203 -0
- package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +315 -0
- package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +220 -0
- package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +208 -0
- package/src/modules/staff/api/timesheets/reports/preview/route.ts +449 -0
- package/src/modules/staff/api/timesheets/reports/route.ts +386 -0
- package/src/modules/staff/api/timesheets/reports/shared.ts +121 -0
- package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +205 -0
- package/src/modules/staff/api/timesheets/settings/rounding-impact/route.ts +226 -0
- package/src/modules/staff/api/timesheets/settings/route.ts +242 -0
- package/src/modules/staff/api/timesheets/tags/access.ts +134 -0
- package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +290 -0
- package/src/modules/staff/api/timesheets/tags/route.ts +177 -0
- package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +294 -0
- package/src/modules/staff/api/timesheets/task-statuses/route.ts +232 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +532 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +271 -0
- package/src/modules/staff/api/timesheets/tasks/route.ts +443 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +306 -0
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +32 -10
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +32 -17
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +27 -6
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +36 -6
- package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +331 -34
- package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +533 -0
- package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +457 -0
- package/src/modules/staff/api/timesheets/time-entries/route.ts +378 -24
- package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +31 -9
- package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +246 -0
- package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +62 -2
- package/src/modules/staff/api/timesheets/time-projects/route.ts +397 -22
- package/src/modules/staff/backend/staff/time-tracking/board/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/board/page.tsx +151 -0
- package/src/modules/staff/backend/staff/time-tracking/entries/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +1229 -0
- package/src/modules/staff/backend/staff/time-tracking/page.meta.ts +11 -0
- package/src/modules/staff/backend/staff/time-tracking/page.tsx +823 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.tsx +81 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +275 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +1420 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/create/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/create/page.tsx +109 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/page.meta.ts +15 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/page.tsx +1254 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +466 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +632 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/create/page.meta.ts +12 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/create/page.tsx +867 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/reports/page.tsx +246 -0
- package/src/modules/staff/backend/staff/time-tracking/settings/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +701 -0
- package/src/modules/staff/backend/staff/time-tracking/timesheet/GridView.tsx +953 -0
- package/src/modules/staff/backend/staff/time-tracking/timesheet/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/timesheet/page.tsx +800 -0
- package/src/modules/staff/backend/staff/timesheets/page.meta.ts +6 -6
- package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1010
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +0 -6
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +4 -158
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +0 -6
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -609
- package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +0 -6
- package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +3 -89
- package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +2 -19
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +3 -778
- package/src/modules/staff/ce.ts +63 -0
- package/src/modules/staff/cli.ts +207 -1
- package/src/modules/staff/commands/index.ts +5 -0
- package/src/modules/staff/commands/timesheets-entries.ts +1006 -28
- package/src/modules/staff/commands/timesheets-projects.ts +593 -7
- package/src/modules/staff/commands/timesheets-reports.ts +1329 -0
- package/src/modules/staff/commands/timesheets-tags.ts +1315 -0
- package/src/modules/staff/commands/timesheets-task-comments.ts +583 -0
- package/src/modules/staff/commands/timesheets-task-statuses.ts +889 -0
- package/src/modules/staff/commands/timesheets-tasks.ts +1121 -0
- package/src/modules/staff/data/enrichers.ts +675 -10
- package/src/modules/staff/data/entities.ts +494 -2
- package/src/modules/staff/data/extensions.ts +68 -0
- package/src/modules/staff/data/validators.ts +348 -3
- package/src/modules/staff/di.ts +96 -0
- package/src/modules/staff/events.payloads.ts +268 -0
- package/src/modules/staff/events.ts +87 -5
- package/src/modules/staff/extension-points.ts +308 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.ts +10 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +225 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.ts +17 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +182 -0
- package/src/modules/staff/i18n/de.json +899 -0
- package/src/modules/staff/i18n/en.json +899 -0
- package/src/modules/staff/i18n/es.json +899 -0
- package/src/modules/staff/i18n/ko.json +899 -0
- package/src/modules/staff/i18n/pl.json +899 -0
- package/src/modules/staff/lib/crud.ts +14 -3
- package/src/modules/staff/lib/time-tracking/access.ts +155 -0
- package/src/modules/staff/lib/time-tracking/billability.ts +68 -0
- package/src/modules/staff/lib/time-tracking/capacity.ts +124 -0
- package/src/modules/staff/lib/time-tracking/componentContracts.ts +26 -0
- package/src/modules/staff/lib/time-tracking/cost.ts +144 -0
- package/src/modules/staff/lib/time-tracking/duration.ts +68 -0
- package/src/modules/staff/lib/time-tracking/featureAccess.ts +115 -0
- package/src/modules/staff/lib/time-tracking/interval.ts +90 -0
- package/src/modules/staff/lib/time-tracking/migrateProjectCodes.ts +161 -0
- package/src/modules/staff/lib/time-tracking/moneyVisibility.ts +37 -0
- package/src/modules/staff/lib/time-tracking/overlap.ts +159 -0
- package/src/modules/staff/lib/time-tracking/portalRecipients.ts +76 -0
- package/src/modules/staff/lib/time-tracking/portalReports.ts +31 -0
- package/src/modules/staff/lib/time-tracking/projectCode.ts +221 -0
- package/src/modules/staff/lib/time-tracking/reapplyRounding.ts +313 -0
- package/src/modules/staff/lib/time-tracking/recalculationRunner.ts +118 -0
- package/src/modules/staff/lib/time-tracking/recalculations.ts +135 -0
- package/src/modules/staff/lib/time-tracking/registries/invoke.ts +122 -0
- package/src/modules/staff/lib/time-tracking/registries/registry.ts +124 -0
- package/src/modules/staff/lib/time-tracking/registries/scope.ts +56 -0
- package/src/modules/staff/lib/time-tracking/rollup.ts +59 -0
- package/src/modules/staff/lib/time-tracking/rounding.ts +126 -0
- package/src/modules/staff/lib/time-tracking/roundingImpact.ts +75 -0
- package/src/modules/staff/lib/time-tracking/settingKeys.ts +274 -0
- package/src/modules/staff/lib/time-tracking/settings.ts +168 -0
- package/src/modules/staff/lib/time-tracking/sqlInClause.ts +22 -0
- package/src/modules/staff/lib/time-tracking/timeEntrySources.ts +85 -0
- package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +360 -0
- package/src/modules/staff/lib/time-tracking-ui/CustomerPicker.tsx +427 -0
- package/src/modules/staff/lib/time-tracking-ui/DurationInput.tsx +192 -0
- package/src/modules/staff/lib/time-tracking-ui/EntryDetailsFields.tsx +224 -0
- package/src/modules/staff/lib/time-tracking-ui/EntryFilterBar.tsx +144 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +1065 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +435 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanColumn.tsx +316 -0
- package/src/modules/staff/lib/time-tracking-ui/NewTaskDialog.tsx +291 -0
- package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +162 -0
- package/src/modules/staff/lib/time-tracking-ui/PeriodSelector.tsx +149 -0
- package/src/modules/staff/lib/time-tracking-ui/PhasePlaceholder.tsx +31 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectCodeField.tsx +230 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.tsx +432 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +323 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.tsx +930 -0
- package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +357 -0
- package/src/modules/staff/lib/time-tracking-ui/TagPicker.tsx +195 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +243 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +137 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +1405 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +260 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskPicker.tsx +435 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskQuickLog.tsx +296 -0
- package/src/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.tsx +97 -0
- package/src/modules/staff/lib/time-tracking-ui/TimeEntryDialog.tsx +1929 -0
- package/src/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.tsx +126 -0
- package/src/modules/staff/lib/time-tracking-ui/TimesheetCalendar.tsx +265 -0
- package/src/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.tsx +78 -0
- package/src/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.tsx +70 -0
- package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +231 -0
- package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +128 -0
- package/src/modules/staff/lib/time-tracking-ui/boardSummary.ts +20 -0
- package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +228 -0
- package/src/modules/staff/lib/time-tracking-ui/projectTeamAssignment.ts +143 -0
- package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +194 -0
- package/src/modules/staff/lib/time-tracking-ui/timeEntryDialogState.ts +400 -0
- package/src/modules/staff/lib/time-tracking-ui/timeEntryListData.ts +271 -0
- package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +168 -0
- package/src/modules/staff/lib/time-tracking-ui/timesheetData.ts +225 -0
- package/src/modules/staff/lib/time-tracking-ui/timesheetPeriod.ts +278 -0
- package/src/modules/staff/lib/time-tracking-ui/timesheetTargets.ts +93 -0
- package/src/modules/staff/lib/time-tracking-ui/useBoardFilters.ts +107 -0
- package/src/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.ts +245 -0
- package/src/modules/staff/lib/timeTrackingSeeds.ts +1037 -0
- package/src/modules/staff/lib/timesheets/timeEntryCacheInvalidation.ts +11 -10
- package/src/modules/staff/lib/timesheets/timeEntryDecoration.ts +256 -0
- package/src/modules/staff/lib/timesheets-projects/budgetBurn.ts +60 -0
- package/src/modules/staff/lib/timesheets-projects/budgetThreshold.ts +135 -0
- package/src/modules/staff/lib/timesheets-projects/budgetThresholdState.ts +137 -0
- package/src/modules/staff/lib/timesheets-projects/computeProjectFinancials.ts +142 -0
- package/src/modules/staff/lib/timesheets-projects/reportSelection.ts +82 -0
- package/src/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.tsx +237 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.tsx +33 -0
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +56 -1
- package/src/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.tsx +90 -0
- package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +125 -0
- package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +251 -0
- package/src/modules/staff/lib/timesheets-reports/pdf.ts +263 -0
- package/src/modules/staff/lib/timesheets-reports/reportApprovalPolicies.ts +137 -0
- package/src/modules/staff/lib/timesheets-reports/reportConfigData.ts +247 -0
- package/src/modules/staff/lib/timesheets-reports/reportConfigState.ts +89 -0
- package/src/modules/staff/lib/timesheets-reports/reportExport.ts +373 -0
- package/src/modules/staff/lib/timesheets-reports/reportExportFormats.ts +71 -0
- package/src/modules/staff/lib/timesheets-reports/reportGroupings.ts +153 -0
- package/src/modules/staff/lib/timesheets-reports/reportLabels.ts +23 -0
- package/src/modules/staff/lib/timesheets-reports/reportReference.ts +146 -0
- package/src/modules/staff/lib/timesheets-reports/reportRows.ts +89 -0
- package/src/modules/staff/lib/timesheets-reports/reportSheetData.ts +196 -0
- package/src/modules/staff/lib/timesheets-reports/reportTotals.ts +544 -0
- package/src/modules/staff/lib/timesheets-reports/xlsx.ts +207 -0
- package/src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts +238 -0
- package/src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts +90 -0
- package/src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts +43 -0
- package/src/modules/staff/lib/timesheets-tasks/statusPositions.ts +132 -0
- package/src/modules/staff/lib/timesheets-tasks/statusSlug.ts +43 -0
- package/src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts +99 -0
- package/src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts +42 -0
- package/src/modules/staff/lib/timesheets-tasks/taskReference.ts +108 -0
- package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +18 -4
- package/src/modules/staff/lib/timesheets-ui/ListView.tsx +504 -149
- package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +50 -2
- package/src/modules/staff/migrations/.snapshot-open-mercato.json +3244 -228
- package/src/modules/staff/migrations/Migration20260813073131_staff.ts +94 -0
- package/src/modules/staff/migrations/Migration20260824143357_staff.ts +17 -0
- package/src/modules/staff/notifications.client.ts +16 -0
- package/src/modules/staff/notifications.handlers.ts +88 -0
- package/src/modules/staff/notifications.ts +163 -0
- package/src/modules/staff/search.ts +191 -1
- package/src/modules/staff/setup.ts +22 -0
- package/src/modules/staff/subscribers/time-project-access-requested-notification.ts +95 -0
- package/src/modules/staff/subscribers/time-project-budget-threshold-notification.ts +226 -0
- package/src/modules/staff/subscribers/time-report-approved-notification.ts +116 -0
- package/src/modules/staff/subscribers/time-report-portal-broadcast.ts +120 -0
- package/src/modules/staff/translations.ts +17 -0
- package/src/modules/staff/widgets/components.ts +34 -0
- package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +6 -5
- package/src/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.tsx +138 -0
- package/src/modules/staff/widgets/notifications/index.ts +1 -0
- package/src/modules/staff/workers/timesheets-reapply-rounding.ts +59 -0
- package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +0 -123
- package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +0 -7
- package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +0 -138
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rounding impact projection (T7.2) — the warning card on screen 16.
|
|
3
|
+
*
|
|
4
|
+
* Changing the rounding rule changes what clients are billed, and the effect is
|
|
5
|
+
* invisible until an invoice. The preview answers the only question that matters
|
|
6
|
+
* before saving: at the candidate rule, what would the last 90 days have billed?
|
|
7
|
+
*
|
|
8
|
+
* Two properties this file exists to guarantee:
|
|
9
|
+
*
|
|
10
|
+
* 1. **It rounds through `roundMinutes`, never a second implementation.** A
|
|
11
|
+
* preview that disagreed with the write path would be worse than no preview.
|
|
12
|
+
* 2. **It rounds per entry, not per sum** (D-7). That is why the projection is
|
|
13
|
+
* driven by `(durationMinutes, entryCount)` buckets rather than a SQL
|
|
14
|
+
* `SUM(duration_minutes)`: the database groups identical durations, and each
|
|
15
|
+
* distinct duration is rounded exactly once and multiplied by its count. The
|
|
16
|
+
* result is arithmetically identical to rounding every row, at a fraction of
|
|
17
|
+
* the rows.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { roundMinutes, type RoundingSettings } from './rounding'
|
|
21
|
+
|
|
22
|
+
export type DurationBucket = {
|
|
23
|
+
durationMinutes: number
|
|
24
|
+
entryCount: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type RoundingImpact = {
|
|
28
|
+
entryCount: number
|
|
29
|
+
rawMinutes: number
|
|
30
|
+
roundedMinutes: number
|
|
31
|
+
/** Positive when the rule bills more than the raw time; negative when it bills less. */
|
|
32
|
+
deltaMinutes: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const EMPTY_ROUNDING_IMPACT: RoundingImpact = {
|
|
36
|
+
entryCount: 0,
|
|
37
|
+
rawMinutes: 0,
|
|
38
|
+
roundedMinutes: 0,
|
|
39
|
+
deltaMinutes: 0,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function toCount(value: unknown): number {
|
|
43
|
+
const parsed = typeof value === 'number' ? value : Number(value)
|
|
44
|
+
return Number.isFinite(parsed) && parsed > 0 ? Math.trunc(parsed) : 0
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function toMinutes(value: unknown): number {
|
|
48
|
+
const parsed = typeof value === 'number' ? value : Number(value)
|
|
49
|
+
return Number.isFinite(parsed) ? Math.trunc(parsed) : 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function projectRoundingImpact(
|
|
53
|
+
buckets: readonly DurationBucket[],
|
|
54
|
+
settings: RoundingSettings,
|
|
55
|
+
): RoundingImpact {
|
|
56
|
+
let entryCount = 0
|
|
57
|
+
let rawMinutes = 0
|
|
58
|
+
let roundedMinutes = 0
|
|
59
|
+
|
|
60
|
+
for (const bucket of buckets) {
|
|
61
|
+
const count = toCount(bucket.entryCount)
|
|
62
|
+
if (count === 0) continue
|
|
63
|
+
const duration = toMinutes(bucket.durationMinutes)
|
|
64
|
+
entryCount += count
|
|
65
|
+
rawMinutes += duration * count
|
|
66
|
+
roundedMinutes += roundMinutes(duration, settings) * count
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
entryCount,
|
|
71
|
+
rawMinutes,
|
|
72
|
+
roundedMinutes,
|
|
73
|
+
deltaMinutes: roundedMinutes - rawMinutes,
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EP-42 — the time-tracking settings key registry.
|
|
3
|
+
*
|
|
4
|
+
* `TIME_TRACKING_SETTING_KEYS` used to be a frozen array, `normalizeTimeTrackingSettings`
|
|
5
|
+
* a hand-written coercion per key, and `staffTimeTrackingSettingsSchema` a literal
|
|
6
|
+
* `z.object`. All three now read this registry, and the eight keys the module shipped
|
|
7
|
+
* are registered here as built-ins — so with no contribution the read, the write, the
|
|
8
|
+
* validating schema and the defaults are byte-identical to what they were.
|
|
9
|
+
*
|
|
10
|
+
* Storage is `ModuleConfigService` under module id `staff.time_tracking`, one config
|
|
11
|
+
* row per key, named `<group>.<key>` and scoped by **tenant only** (spec §10: time
|
|
12
|
+
* tracking settings are tenant-global; there is no per-organization override and no
|
|
13
|
+
* per-project override). A contributed key inherits exactly that scope — it is written
|
|
14
|
+
* with `{ tenantId }` and `organization_id` stays null.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { z } from 'zod'
|
|
18
|
+
import { extensionPoints } from '@open-mercato/core/modules/staff/extension-points'
|
|
19
|
+
import { BUILT_IN_STRATEGY_PRIORITY, createStrategyRegistry } from './registries/registry'
|
|
20
|
+
import { DEFAULT_ROUNDING_SETTINGS } from './rounding'
|
|
21
|
+
|
|
22
|
+
export const TIME_TRACKING_SETTING_KEY_REGISTRY_ID = extensionPoints.hosts.settingKeyRegistry.spotId
|
|
23
|
+
|
|
24
|
+
export const TIME_TRACKING_ROUNDING_GROUP = 'rounding'
|
|
25
|
+
export const TIME_TRACKING_DEFAULTS_GROUP = 'defaults'
|
|
26
|
+
export const TIME_TRACKING_TARGETS_GROUP = 'targets'
|
|
27
|
+
export const TIME_TRACKING_WARNINGS_GROUP = 'warnings'
|
|
28
|
+
export const TIME_TRACKING_ACCESS_GROUP = 'access'
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Days past `assigned_end_date` that project access survives (spec D-12). The
|
|
32
|
+
* grace window exists so a consultant rolled off at the end of a month can still
|
|
33
|
+
* log and correct that month's time; `0` ends access the day the assignment ends.
|
|
34
|
+
*/
|
|
35
|
+
export const DEFAULT_ASSIGNMENT_GRACE_DAYS = 14
|
|
36
|
+
|
|
37
|
+
export const MAX_ASSIGNMENT_GRACE_DAYS = 365
|
|
38
|
+
|
|
39
|
+
export const timeTrackingRoundingUnitMinutesSchema = z.union([
|
|
40
|
+
z.literal(0),
|
|
41
|
+
z.literal(5),
|
|
42
|
+
z.literal(10),
|
|
43
|
+
z.literal(15),
|
|
44
|
+
])
|
|
45
|
+
|
|
46
|
+
export const timeTrackingRoundingDirectionSchema = z.enum(['up', 'nearest'])
|
|
47
|
+
|
|
48
|
+
export type TimeTrackingSettingKeyInput = {
|
|
49
|
+
/** Group the value lives under in the settings object, e.g. `rounding`. */
|
|
50
|
+
group: string
|
|
51
|
+
/** Leaf name inside the group, e.g. `unitMinutes`. */
|
|
52
|
+
key: string
|
|
53
|
+
/** Validates the stored value; an invalid one falls back to `default`. */
|
|
54
|
+
schema: z.ZodTypeAny
|
|
55
|
+
/** Used when the tenant never stored the key and when the stored value no longer validates. */
|
|
56
|
+
default: unknown
|
|
57
|
+
/** i18n key for the label a settings section renders. Never a literal — the module holds no user-facing strings. */
|
|
58
|
+
labelKey: string
|
|
59
|
+
/** Higher first in `listTimeTrackingSettingKeys()`; built-ins sit below every contribution. */
|
|
60
|
+
priority?: number
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type TimeTrackingSettingKeyDefinition = TimeTrackingSettingKeyInput & {
|
|
64
|
+
/** `<group>.<key>` — the `ModuleConfigService` config name. */
|
|
65
|
+
id: string
|
|
66
|
+
builtIn: boolean
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const registry = createStrategyRegistry<TimeTrackingSettingKeyDefinition>(
|
|
70
|
+
TIME_TRACKING_SETTING_KEY_REGISTRY_ID,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
const builtInIds = new Set<string>()
|
|
74
|
+
|
|
75
|
+
export function timeTrackingSettingStorageName(group: string, key: string): string {
|
|
76
|
+
return `${group}.${key}`
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function registerKey(input: TimeTrackingSettingKeyInput, builtIn: boolean): () => void {
|
|
80
|
+
const group = input.group.trim()
|
|
81
|
+
const key = input.key.trim()
|
|
82
|
+
if (!group || !key) {
|
|
83
|
+
throw new Error('[internal] a time-tracking setting key requires a non-empty group and key')
|
|
84
|
+
}
|
|
85
|
+
const id = timeTrackingSettingStorageName(group, key)
|
|
86
|
+
if (!builtIn && builtInIds.has(id)) {
|
|
87
|
+
throw new Error(`[internal] ${id} is a built-in time-tracking setting key and cannot be replaced`)
|
|
88
|
+
}
|
|
89
|
+
const parsed = input.schema.safeParse(input.default)
|
|
90
|
+
if (!parsed.success) {
|
|
91
|
+
throw new Error(`[internal] the default for the time-tracking setting key ${id} fails its own schema`)
|
|
92
|
+
}
|
|
93
|
+
const definition = { ...input, group, key, id, builtIn }
|
|
94
|
+
if (builtIn) {
|
|
95
|
+
registry.registerBuiltIn(definition)
|
|
96
|
+
return () => {}
|
|
97
|
+
}
|
|
98
|
+
return registry.register(definition)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Contribute a tenant-scoped time-tracking setting key. Pair it with a widget on the
|
|
103
|
+
* `staff.time_tracking.settings:sections` injection spot (EP-26) to render it: the spot
|
|
104
|
+
* context carries `values` for every contributed key and a `setValue(id, value)` that
|
|
105
|
+
* writes into the page draft, so the page's own Save round-trips the contribution.
|
|
106
|
+
*/
|
|
107
|
+
export function registerTimeTrackingSettingKey(input: TimeTrackingSettingKeyInput): () => void {
|
|
108
|
+
return registerKey(input, false)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function listTimeTrackingSettingKeys(): TimeTrackingSettingKeyDefinition[] {
|
|
112
|
+
return registry.list()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function getTimeTrackingSettingKey(id: string | null | undefined): TimeTrackingSettingKeyDefinition | null {
|
|
116
|
+
return registry.get(id)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function timeTrackingSettingKeyIds(): string[] {
|
|
120
|
+
return registry.ids()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The contributed keys only — the eight built-ins are rendered by the settings page's own form. */
|
|
124
|
+
export function contributedTimeTrackingSettingKeys(): TimeTrackingSettingKeyDefinition[] {
|
|
125
|
+
return registry.list().filter((entry) => !entry.builtIn)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function timeTrackingSettingGroups(): string[] {
|
|
129
|
+
const groups: string[] = []
|
|
130
|
+
for (const entry of registry.list()) {
|
|
131
|
+
if (!groups.includes(entry.group)) groups.push(entry.group)
|
|
132
|
+
}
|
|
133
|
+
return groups
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const BUILT_IN_SETTING_KEYS: readonly TimeTrackingSettingKeyInput[] = [
|
|
137
|
+
{
|
|
138
|
+
group: TIME_TRACKING_ROUNDING_GROUP,
|
|
139
|
+
key: 'unitMinutes',
|
|
140
|
+
schema: timeTrackingRoundingUnitMinutesSchema,
|
|
141
|
+
default: DEFAULT_ROUNDING_SETTINGS.unitMinutes,
|
|
142
|
+
labelKey: 'staff.time_tracking.settings.rounding.unit',
|
|
143
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
group: TIME_TRACKING_ROUNDING_GROUP,
|
|
147
|
+
key: 'direction',
|
|
148
|
+
schema: timeTrackingRoundingDirectionSchema,
|
|
149
|
+
default: DEFAULT_ROUNDING_SETTINGS.direction,
|
|
150
|
+
labelKey: 'staff.time_tracking.settings.rounding.direction',
|
|
151
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
group: TIME_TRACKING_DEFAULTS_GROUP,
|
|
155
|
+
key: 'billable',
|
|
156
|
+
schema: z.boolean(),
|
|
157
|
+
default: true,
|
|
158
|
+
labelKey: 'staff.time_tracking.settings.defaults.billable',
|
|
159
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
group: TIME_TRACKING_DEFAULTS_GROUP,
|
|
163
|
+
key: 'chainStartFromPreviousEnd',
|
|
164
|
+
schema: z.boolean(),
|
|
165
|
+
default: true,
|
|
166
|
+
labelKey: 'staff.time_tracking.settings.defaults.chainStart',
|
|
167
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
group: TIME_TRACKING_TARGETS_GROUP,
|
|
171
|
+
key: 'dailyHours',
|
|
172
|
+
schema: z.number().min(0).max(24).nullable(),
|
|
173
|
+
default: 8,
|
|
174
|
+
labelKey: 'staff.time_tracking.settings.targets.dailyHours',
|
|
175
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
group: TIME_TRACKING_WARNINGS_GROUP,
|
|
179
|
+
key: 'overlap',
|
|
180
|
+
schema: z.boolean(),
|
|
181
|
+
default: true,
|
|
182
|
+
labelKey: 'staff.time_tracking.settings.warnings.overlap',
|
|
183
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
group: TIME_TRACKING_WARNINGS_GROUP,
|
|
187
|
+
key: 'runningTimer',
|
|
188
|
+
schema: z.boolean(),
|
|
189
|
+
default: true,
|
|
190
|
+
labelKey: 'staff.time_tracking.settings.warnings.runningTimer',
|
|
191
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
group: TIME_TRACKING_ACCESS_GROUP,
|
|
195
|
+
key: 'assignmentGraceDays',
|
|
196
|
+
schema: z.number().int().min(0).max(MAX_ASSIGNMENT_GRACE_DAYS),
|
|
197
|
+
default: DEFAULT_ASSIGNMENT_GRACE_DAYS,
|
|
198
|
+
labelKey: 'staff.time_tracking.settings.access.graceDays',
|
|
199
|
+
priority: BUILT_IN_STRATEGY_PRIORITY,
|
|
200
|
+
},
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
for (const input of BUILT_IN_SETTING_KEYS) {
|
|
204
|
+
registerKey(input, true)
|
|
205
|
+
builtInIds.add(timeTrackingSettingStorageName(input.group, input.key))
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export const BUILT_IN_TIME_TRACKING_SETTING_KEY_IDS: readonly string[] = Object.freeze(
|
|
209
|
+
BUILT_IN_SETTING_KEYS.map((input) => timeTrackingSettingStorageName(input.group, input.key)),
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
export function isBuiltInTimeTrackingSettingKey(id: string): boolean {
|
|
213
|
+
return builtInIds.has(id)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export type TimeTrackingSettingsRecord = Record<string, Record<string, unknown>>
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* The validating schema the settings route parses against, rebuilt per call so a key
|
|
220
|
+
* registered after this module first loaded still validates (the same reason EP-35's
|
|
221
|
+
* export-format enum is an OpenAPI getter).
|
|
222
|
+
*/
|
|
223
|
+
export function buildTimeTrackingSettingsSchema(): z.ZodObject<Record<string, z.ZodTypeAny>> {
|
|
224
|
+
const byGroup = new Map<string, Record<string, z.ZodTypeAny>>()
|
|
225
|
+
const defaultsByGroup = new Map<string, Record<string, unknown>>()
|
|
226
|
+
for (const entry of registry.list()) {
|
|
227
|
+
const shape = byGroup.get(entry.group) ?? {}
|
|
228
|
+
shape[entry.key] = entry.schema.optional().default(entry.default)
|
|
229
|
+
byGroup.set(entry.group, shape)
|
|
230
|
+
const defaults = defaultsByGroup.get(entry.group) ?? {}
|
|
231
|
+
defaults[entry.key] = entry.default
|
|
232
|
+
defaultsByGroup.set(entry.group, defaults)
|
|
233
|
+
}
|
|
234
|
+
const shape: Record<string, z.ZodTypeAny> = {}
|
|
235
|
+
for (const [group, groupShape] of byGroup) {
|
|
236
|
+
shape[group] = z.object(groupShape).optional().default(defaultsByGroup.get(group) ?? {})
|
|
237
|
+
}
|
|
238
|
+
return z.object(shape)
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** The canonical settings object with every registered key at its registered default. */
|
|
242
|
+
export function buildDefaultTimeTrackingSettings(): TimeTrackingSettingsRecord {
|
|
243
|
+
const result: TimeTrackingSettingsRecord = {}
|
|
244
|
+
for (const entry of registry.list()) {
|
|
245
|
+
const group = result[entry.group] ?? {}
|
|
246
|
+
group[entry.key] = entry.default
|
|
247
|
+
result[entry.group] = group
|
|
248
|
+
}
|
|
249
|
+
return result
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function readGroup(source: unknown, group: string): Record<string, unknown> | null {
|
|
253
|
+
if (!source || typeof source !== 'object') return null
|
|
254
|
+
const value = (source as Record<string, unknown>)[group]
|
|
255
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null
|
|
256
|
+
return value as Record<string, unknown>
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Coerce an arbitrary (possibly partial or malformed) settings shape into the canonical
|
|
261
|
+
* one: every registered key present, every absent or invalid value replaced by the
|
|
262
|
+
* registered default.
|
|
263
|
+
*/
|
|
264
|
+
export function normalizeTimeTrackingSettingsRecord(input: unknown): TimeTrackingSettingsRecord {
|
|
265
|
+
const result: TimeTrackingSettingsRecord = {}
|
|
266
|
+
for (const entry of registry.list()) {
|
|
267
|
+
const group = result[entry.group] ?? {}
|
|
268
|
+
const raw = readGroup(input, entry.group)?.[entry.key]
|
|
269
|
+
const parsed = entry.schema.safeParse(raw)
|
|
270
|
+
group[entry.key] = parsed.success ? parsed.data : entry.default
|
|
271
|
+
result[entry.group] = group
|
|
272
|
+
}
|
|
273
|
+
return result
|
|
274
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'
|
|
2
|
+
import type { StaffTimeTrackingSettingsInput } from '../../data/validators'
|
|
3
|
+
import {
|
|
4
|
+
type RoundingDirection,
|
|
5
|
+
type RoundingSettings,
|
|
6
|
+
type RoundingUnitMinutes,
|
|
7
|
+
} from './rounding'
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_ASSIGNMENT_GRACE_DAYS,
|
|
10
|
+
MAX_ASSIGNMENT_GRACE_DAYS,
|
|
11
|
+
buildDefaultTimeTrackingSettings,
|
|
12
|
+
listTimeTrackingSettingKeys,
|
|
13
|
+
normalizeTimeTrackingSettingsRecord,
|
|
14
|
+
registerTimeTrackingSettingKey,
|
|
15
|
+
timeTrackingSettingKeyIds,
|
|
16
|
+
type TimeTrackingSettingKeyDefinition,
|
|
17
|
+
type TimeTrackingSettingKeyInput,
|
|
18
|
+
type TimeTrackingSettingsRecord,
|
|
19
|
+
} from './settingKeys'
|
|
20
|
+
|
|
21
|
+
export type { RoundingDirection, RoundingSettings, RoundingUnitMinutes }
|
|
22
|
+
export type { TimeTrackingSettingKeyDefinition, TimeTrackingSettingKeyInput, TimeTrackingSettingsRecord }
|
|
23
|
+
export { DEFAULT_ASSIGNMENT_GRACE_DAYS, MAX_ASSIGNMENT_GRACE_DAYS, registerTimeTrackingSettingKey }
|
|
24
|
+
|
|
25
|
+
export const STAFF_TIME_TRACKING_MODULE_ID = 'staff.time_tracking'
|
|
26
|
+
|
|
27
|
+
export const TIME_TRACKING_ROUNDING_UNIT_MINUTES_KEY = 'rounding.unitMinutes'
|
|
28
|
+
export const TIME_TRACKING_ROUNDING_DIRECTION_KEY = 'rounding.direction'
|
|
29
|
+
export const TIME_TRACKING_DEFAULTS_BILLABLE_KEY = 'defaults.billable'
|
|
30
|
+
export const TIME_TRACKING_DEFAULTS_CHAIN_START_KEY = 'defaults.chainStartFromPreviousEnd'
|
|
31
|
+
export const TIME_TRACKING_TARGETS_DAILY_HOURS_KEY = 'targets.dailyHours'
|
|
32
|
+
export const TIME_TRACKING_WARNINGS_OVERLAP_KEY = 'warnings.overlap'
|
|
33
|
+
export const TIME_TRACKING_WARNINGS_RUNNING_TIMER_KEY = 'warnings.runningTimer'
|
|
34
|
+
export const TIME_TRACKING_ACCESS_ASSIGNMENT_GRACE_DAYS_KEY = 'access.assignmentGraceDays'
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The eight keys the module shipped. FROZEN — a stored config row is named after one
|
|
38
|
+
* of these, so none may be renamed or removed. The list is no longer the whole truth:
|
|
39
|
+
* `timeTrackingSettingKeyIds()` returns these plus every contributed key (EP-42).
|
|
40
|
+
*/
|
|
41
|
+
export const TIME_TRACKING_SETTING_KEYS = [
|
|
42
|
+
TIME_TRACKING_ROUNDING_UNIT_MINUTES_KEY,
|
|
43
|
+
TIME_TRACKING_ROUNDING_DIRECTION_KEY,
|
|
44
|
+
TIME_TRACKING_DEFAULTS_BILLABLE_KEY,
|
|
45
|
+
TIME_TRACKING_DEFAULTS_CHAIN_START_KEY,
|
|
46
|
+
TIME_TRACKING_TARGETS_DAILY_HOURS_KEY,
|
|
47
|
+
TIME_TRACKING_WARNINGS_OVERLAP_KEY,
|
|
48
|
+
TIME_TRACKING_WARNINGS_RUNNING_TIMER_KEY,
|
|
49
|
+
TIME_TRACKING_ACCESS_ASSIGNMENT_GRACE_DAYS_KEY,
|
|
50
|
+
] as const
|
|
51
|
+
|
|
52
|
+
export type TimeTrackingSettingKey = (typeof TIME_TRACKING_SETTING_KEYS)[number]
|
|
53
|
+
|
|
54
|
+
export type TimeTrackingEntryDefaults = {
|
|
55
|
+
billable: boolean
|
|
56
|
+
chainStartFromPreviousEnd: boolean
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type TimeTrackingTargets = {
|
|
60
|
+
dailyHours: number | null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type TimeTrackingWarnings = {
|
|
64
|
+
overlap: boolean
|
|
65
|
+
runningTimer: boolean
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type TimeTrackingAccess = {
|
|
69
|
+
assignmentGraceDays: number
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type TimeTrackingBuiltInSettings = {
|
|
73
|
+
rounding: RoundingSettings
|
|
74
|
+
defaults: TimeTrackingEntryDefaults
|
|
75
|
+
targets: TimeTrackingTargets
|
|
76
|
+
warnings: TimeTrackingWarnings
|
|
77
|
+
access: TimeTrackingAccess
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* The five built-in groups stay statically typed; a contributed group or key reaches
|
|
82
|
+
* a caller through the index signature and is read with `readTimeTrackingSettingValue`.
|
|
83
|
+
*/
|
|
84
|
+
export type TimeTrackingSettings = TimeTrackingBuiltInSettings & TimeTrackingSettingsRecord
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Settings are global per tenant (spec §10 fixes them there — no per-project or
|
|
88
|
+
* per-customer override), so the scope carries the tenant only and MUST be
|
|
89
|
+
* derived from the authenticated context, never from request input. A contributed
|
|
90
|
+
* key inherits exactly that scope.
|
|
91
|
+
*/
|
|
92
|
+
export type TimeTrackingSettingsScope = {
|
|
93
|
+
tenantId: string
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const DEFAULT_TIME_TRACKING_SETTINGS: TimeTrackingSettings =
|
|
97
|
+
buildDefaultTimeTrackingSettings() as TimeTrackingSettings
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Coerce an arbitrary (possibly partial or malformed) settings shape into the
|
|
101
|
+
* canonical one, filling every absent or invalid value from the registered defaults.
|
|
102
|
+
*/
|
|
103
|
+
export function normalizeTimeTrackingSettings(
|
|
104
|
+
input: Partial<TimeTrackingBuiltInSettings> | TimeTrackingSettingsRecord | StaffTimeTrackingSettingsInput | null | undefined,
|
|
105
|
+
): TimeTrackingSettings {
|
|
106
|
+
return normalizeTimeTrackingSettingsRecord(input) as TimeTrackingSettings
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Reads one registered key out of a normalized settings object by its `<group>.<key>` id. */
|
|
110
|
+
export function readTimeTrackingSettingValue(
|
|
111
|
+
settings: TimeTrackingSettings,
|
|
112
|
+
id: string,
|
|
113
|
+
): unknown {
|
|
114
|
+
const separator = id.indexOf('.')
|
|
115
|
+
if (separator <= 0) return undefined
|
|
116
|
+
const group = settings[id.slice(0, separator)]
|
|
117
|
+
if (!group || typeof group !== 'object') return undefined
|
|
118
|
+
return (group as Record<string, unknown>)[id.slice(separator + 1)]
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { listTimeTrackingSettingKeys, timeTrackingSettingKeyIds }
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolve the tenant's time tracking settings. Absent keys (and keys holding a
|
|
125
|
+
* value the schema no longer accepts) fall back to the registered default, so a
|
|
126
|
+
* tenant that never opened the settings screen still reads a complete record.
|
|
127
|
+
*/
|
|
128
|
+
export async function readTimeTrackingSettings(
|
|
129
|
+
configService: ModuleConfigService,
|
|
130
|
+
scope: TimeTrackingSettingsScope,
|
|
131
|
+
): Promise<TimeTrackingSettings> {
|
|
132
|
+
const configScope = { tenantId: scope.tenantId }
|
|
133
|
+
// `getRecord` rather than `getValue` so an explicitly stored `null`
|
|
134
|
+
// (`targets.dailyHours` = "no daily target") stays distinguishable from an
|
|
135
|
+
// absent row, which must fall back to the default.
|
|
136
|
+
const stored: TimeTrackingSettingsRecord = {}
|
|
137
|
+
for (const entry of listTimeTrackingSettingKeys()) {
|
|
138
|
+
const record = await configService.getRecord(STAFF_TIME_TRACKING_MODULE_ID, entry.id, configScope)
|
|
139
|
+
if (!record) continue
|
|
140
|
+
const group = stored[entry.group] ?? {}
|
|
141
|
+
group[entry.key] = record.value
|
|
142
|
+
stored[entry.group] = group
|
|
143
|
+
}
|
|
144
|
+
return normalizeTimeTrackingSettings(stored)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Persist the tenant's time tracking settings and return the stored shape.
|
|
149
|
+
*/
|
|
150
|
+
export async function writeTimeTrackingSettings(
|
|
151
|
+
configService: ModuleConfigService,
|
|
152
|
+
scope: TimeTrackingSettingsScope,
|
|
153
|
+
input: Partial<TimeTrackingBuiltInSettings> | TimeTrackingSettingsRecord | StaffTimeTrackingSettingsInput,
|
|
154
|
+
): Promise<TimeTrackingSettings> {
|
|
155
|
+
const settings = normalizeTimeTrackingSettings(input)
|
|
156
|
+
const configScope = { tenantId: scope.tenantId }
|
|
157
|
+
|
|
158
|
+
for (const entry of listTimeTrackingSettingKeys()) {
|
|
159
|
+
await configService.setValue(
|
|
160
|
+
STAFF_TIME_TRACKING_MODULE_ID,
|
|
161
|
+
entry.id,
|
|
162
|
+
readTimeTrackingSettingValue(settings, entry.id),
|
|
163
|
+
configScope,
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return settings
|
|
168
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders an id list into a raw-SQL `IN` clause with one placeholder per member.
|
|
3
|
+
*
|
|
4
|
+
* MikroORM does not bind parameters at the driver level: `AbstractSqlConnection.execute`
|
|
5
|
+
* calls `platform.formatQuery`, which interpolates each value through
|
|
6
|
+
* `BasePostgreSqlPlatform.escape`, and that renders a JavaScript array as a bare
|
|
7
|
+
* comma-separated list. `column = ANY(?)` therefore reaches PostgreSQL as
|
|
8
|
+
* `= ANY('a', 'b')` — or, for a single-element array, as the bare scalar, which fails
|
|
9
|
+
* with `malformed array literal`. The dashboards aggregation builder hit the same wall
|
|
10
|
+
* (#4669) and settled on one placeholder per member; this is that same fix, shared by
|
|
11
|
+
* the time-tracking raw queries.
|
|
12
|
+
*
|
|
13
|
+
* An empty list yields `IN (NULL)` rather than a dropped clause: a caller that narrowed
|
|
14
|
+
* to nothing must select nothing, never silently widen to every row.
|
|
15
|
+
*/
|
|
16
|
+
export type SqlInClause = { sql: string; params: unknown[] }
|
|
17
|
+
|
|
18
|
+
export function buildSqlInClause(column: string, values: readonly string[]): SqlInClause {
|
|
19
|
+
if (values.length === 0) return { sql: `${column} IN (NULL)`, params: [] }
|
|
20
|
+
const placeholders = values.map(() => '?').join(', ')
|
|
21
|
+
return { sql: `${column} IN (${placeholders})`, params: [...values] }
|
|
22
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EP-37 — the time-entry source registry.
|
|
3
|
+
*
|
|
4
|
+
* `staff_time_entries.source` used to be a four-value database enum, which made
|
|
5
|
+
* every import integration a core patch. It is now a plain text column whose
|
|
6
|
+
* accepted values are this registry, so a `jira`, `toggl` or `badge-terminal`
|
|
7
|
+
* source ships with its contributing module.
|
|
8
|
+
*
|
|
9
|
+
* `editable` is the flag the entry screens read: a source the user may still
|
|
10
|
+
* hand-correct (`manual`) versus one whose numbers belong to the system that
|
|
11
|
+
* produced them. It is advisory metadata, not an authorization decision — the
|
|
12
|
+
* lock rules stay with `locked_report_id` and the ACL features.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { extensionPoints } from '@open-mercato/core/modules/staff/extension-points'
|
|
16
|
+
import { createStrategyRegistry, BUILT_IN_STRATEGY_PRIORITY } from './registries/registry'
|
|
17
|
+
|
|
18
|
+
export const BUILT_IN_TIME_ENTRY_SOURCE_IDS = ['manual', 'timer', 'kiosk', 'mobile'] as const
|
|
19
|
+
|
|
20
|
+
export type BuiltInTimeEntrySource = (typeof BUILT_IN_TIME_ENTRY_SOURCE_IDS)[number]
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Widened from the original four-value union so a contributed id is assignable.
|
|
24
|
+
* The union arm keeps the four built-ins as completions.
|
|
25
|
+
*/
|
|
26
|
+
export type TimeEntrySource = BuiltInTimeEntrySource | (string & {})
|
|
27
|
+
|
|
28
|
+
export type TimeEntrySourceDefinition = {
|
|
29
|
+
id: string
|
|
30
|
+
labelKey: string
|
|
31
|
+
/** Lucide icon name the entry screens may render beside the row. */
|
|
32
|
+
icon: string
|
|
33
|
+
editable: boolean
|
|
34
|
+
priority?: number
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const TIME_ENTRY_SOURCE_REGISTRY_ID = extensionPoints.hosts.timeEntrySourceRegistry.spotId
|
|
38
|
+
|
|
39
|
+
export const DEFAULT_TIME_ENTRY_SOURCE: BuiltInTimeEntrySource = 'manual'
|
|
40
|
+
|
|
41
|
+
const registry = createStrategyRegistry<TimeEntrySourceDefinition>(TIME_ENTRY_SOURCE_REGISTRY_ID)
|
|
42
|
+
|
|
43
|
+
export function registerTimeEntrySource(source: TimeEntrySourceDefinition): () => void {
|
|
44
|
+
return registry.register(source)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function listTimeEntrySources(): TimeEntrySourceDefinition[] {
|
|
48
|
+
return registry.list()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function getTimeEntrySource(id: string | null | undefined): TimeEntrySourceDefinition | null {
|
|
52
|
+
return registry.get(id)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function hasTimeEntrySource(id: string | null | undefined): boolean {
|
|
56
|
+
return registry.has(id)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Built-ins first, in the order the module shipped them, then contributions. */
|
|
60
|
+
export function timeEntrySourceIds(): string[] {
|
|
61
|
+
const builtIn = BUILT_IN_TIME_ENTRY_SOURCE_IDS.filter((id) => registry.has(id))
|
|
62
|
+
const contributed = registry.ids().filter((id) => !builtIn.includes(id as BuiltInTimeEntrySource))
|
|
63
|
+
return [...builtIn, ...contributed]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The write-path guard the dropped database check constraint used to provide.
|
|
68
|
+
* An unknown id falls back to `manual` rather than rejecting the write, matching
|
|
69
|
+
* the column default the enum carried.
|
|
70
|
+
*/
|
|
71
|
+
export function normalizeTimeEntrySource(value: unknown): TimeEntrySource {
|
|
72
|
+
if (typeof value === 'string' && registry.has(value)) return value
|
|
73
|
+
return DEFAULT_TIME_ENTRY_SOURCE
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const builtInSources: readonly Omit<TimeEntrySourceDefinition, 'priority'>[] = [
|
|
77
|
+
{ id: 'manual', labelKey: 'staff.time_tracking.entries.source.manual', icon: 'PenLine', editable: true },
|
|
78
|
+
{ id: 'timer', labelKey: 'staff.time_tracking.entries.source.timer', icon: 'Timer', editable: true },
|
|
79
|
+
{ id: 'kiosk', labelKey: 'staff.time_tracking.entries.source.kiosk', icon: 'Monitor', editable: false },
|
|
80
|
+
{ id: 'mobile', labelKey: 'staff.time_tracking.entries.source.mobile', icon: 'Smartphone', editable: true },
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
for (const source of builtInSources) {
|
|
84
|
+
registry.registerBuiltIn({ ...source, priority: BUILT_IN_STRATEGY_PRIORITY })
|
|
85
|
+
}
|