@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.
Files changed (808) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_time_entry/index.js +14 -0
  3. package/dist/generated/entities/staff_time_entry/index.js.map +2 -2
  4. package/dist/generated/entities/staff_time_entry_tag/index.js +15 -0
  5. package/dist/generated/entities/staff_time_entry_tag/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +16 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +2 -2
  8. package/dist/generated/entities/staff_time_report/index.js +57 -0
  9. package/dist/generated/entities/staff_time_report/index.js.map +7 -0
  10. package/dist/generated/entities/staff_time_report_entry/index.js +27 -0
  11. package/dist/generated/entities/staff_time_report_entry/index.js.map +7 -0
  12. package/dist/generated/entities/staff_time_report_event/index.js +21 -0
  13. package/dist/generated/entities/staff_time_report_event/index.js.map +7 -0
  14. package/dist/generated/entities/staff_time_report_project/index.js +15 -0
  15. package/dist/generated/entities/staff_time_report_project/index.js.map +7 -0
  16. package/dist/generated/entities/staff_time_tag/index.js +21 -0
  17. package/dist/generated/entities/staff_time_tag/index.js.map +7 -0
  18. package/dist/generated/entities/staff_time_task/index.js +37 -0
  19. package/dist/generated/entities/staff_time_task/index.js.map +7 -0
  20. package/dist/generated/entities/staff_time_task_comment/index.js +21 -0
  21. package/dist/generated/entities/staff_time_task_comment/index.js.map +7 -0
  22. package/dist/generated/entities/staff_time_task_status/index.js +29 -0
  23. package/dist/generated/entities/staff_time_task_status/index.js.map +7 -0
  24. package/dist/generated/entities/staff_time_task_tag/index.js +15 -0
  25. package/dist/generated/entities/staff_time_task_tag/index.js.map +7 -0
  26. package/dist/generated/entities.ids.generated.js +11 -1
  27. package/dist/generated/entities.ids.generated.js.map +2 -2
  28. package/dist/generated/entity-fields-registry.js +149 -0
  29. package/dist/generated/entity-fields-registry.js.map +2 -2
  30. package/dist/helpers/integration/timesheetFixtures.js +7 -0
  31. package/dist/helpers/integration/timesheetFixtures.js.map +2 -2
  32. package/dist/modules/auth/cli.js +16 -0
  33. package/dist/modules/auth/cli.js.map +2 -2
  34. package/dist/modules/auth/lib/backendChrome.js +1 -0
  35. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  36. package/dist/modules/customer_accounts/lib/customerRoleAcls.js +44 -0
  37. package/dist/modules/customer_accounts/lib/customerRoleAcls.js.map +7 -0
  38. package/dist/modules/customer_accounts/setup.js +1 -28
  39. package/dist/modules/customer_accounts/setup.js.map +2 -2
  40. package/dist/modules/data_sync/api/options.js +2 -0
  41. package/dist/modules/data_sync/api/options.js.map +2 -2
  42. package/dist/modules/data_sync/backend/data-sync/page.js +39 -17
  43. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  44. package/dist/modules/data_sync/lib/start-controls.js +42 -0
  45. package/dist/modules/data_sync/lib/start-controls.js.map +7 -0
  46. package/dist/modules/staff/acl.js +9 -1
  47. package/dist/modules/staff/acl.js.map +2 -2
  48. package/dist/modules/staff/ai-agents.js +142 -0
  49. package/dist/modules/staff/ai-agents.js.map +7 -0
  50. package/dist/modules/staff/ai-tools/time-tracking-pack.js +348 -0
  51. package/dist/modules/staff/ai-tools/time-tracking-pack.js.map +7 -0
  52. package/dist/modules/staff/ai-tools/types.js +54 -0
  53. package/dist/modules/staff/ai-tools/types.js.map +7 -0
  54. package/dist/modules/staff/ai-tools.js +8 -0
  55. package/dist/modules/staff/ai-tools.js.map +7 -0
  56. package/dist/modules/staff/analytics.js +84 -1
  57. package/dist/modules/staff/analytics.js.map +2 -2
  58. package/dist/modules/staff/api/guards.js +37 -3
  59. package/dist/modules/staff/api/guards.js.map +2 -2
  60. package/dist/modules/staff/api/leave-requests/accept/route.js +1 -3
  61. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  62. package/dist/modules/staff/api/leave-requests/reject/route.js +1 -3
  63. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  64. package/dist/modules/staff/api/portal/time-reports/[id]/route.js +131 -0
  65. package/dist/modules/staff/api/portal/time-reports/[id]/route.js.map +7 -0
  66. package/dist/modules/staff/api/portal/time-reports/route.js +179 -0
  67. package/dist/modules/staff/api/portal/time-reports/route.js.map +7 -0
  68. package/dist/modules/staff/api/team-members/self/route.js +1 -3
  69. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  70. package/dist/modules/staff/api/team-members/tags/assign/route.js +1 -3
  71. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  72. package/dist/modules/staff/api/team-members/tags/unassign/route.js +1 -3
  73. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  74. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +174 -0
  75. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +7 -0
  76. package/dist/modules/staff/api/timesheets/access-requests/route.js +226 -0
  77. package/dist/modules/staff/api/timesheets/access-requests/route.js.map +7 -0
  78. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +15 -8
  79. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
  80. package/dist/modules/staff/api/timesheets/my-projects/route.js +13 -1
  81. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
  82. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js +42 -0
  83. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js.map +7 -0
  84. package/dist/modules/staff/api/timesheets/my-work/route.js +383 -0
  85. package/dist/modules/staff/api/timesheets/my-work/route.js.map +7 -0
  86. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +14 -2
  87. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
  88. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +168 -0
  89. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +7 -0
  90. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +246 -0
  91. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +7 -0
  92. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +183 -0
  93. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +7 -0
  94. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +164 -0
  95. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +7 -0
  96. package/dist/modules/staff/api/timesheets/reports/preview/route.js +360 -0
  97. package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +7 -0
  98. package/dist/modules/staff/api/timesheets/reports/route.js +316 -0
  99. package/dist/modules/staff/api/timesheets/reports/route.js.map +7 -0
  100. package/dist/modules/staff/api/timesheets/reports/shared.js +63 -0
  101. package/dist/modules/staff/api/timesheets/reports/shared.js.map +7 -0
  102. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +164 -0
  103. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +7 -0
  104. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js +168 -0
  105. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js.map +7 -0
  106. package/dist/modules/staff/api/timesheets/settings/route.js +199 -0
  107. package/dist/modules/staff/api/timesheets/settings/route.js.map +7 -0
  108. package/dist/modules/staff/api/timesheets/tags/access.js +76 -0
  109. package/dist/modules/staff/api/timesheets/tags/access.js.map +7 -0
  110. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +235 -0
  111. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +7 -0
  112. package/dist/modules/staff/api/timesheets/tags/route.js +160 -0
  113. package/dist/modules/staff/api/timesheets/tags/route.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +233 -0
  115. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/task-statuses/route.js +188 -0
  117. package/dist/modules/staff/api/timesheets/task-statuses/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +399 -0
  119. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +210 -0
  121. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +7 -0
  122. package/dist/modules/staff/api/timesheets/tasks/route.js +333 -0
  123. package/dist/modules/staff/api/timesheets/tasks/route.js.map +7 -0
  124. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +228 -0
  125. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +7 -0
  126. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +29 -10
  127. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
  128. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +31 -18
  129. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
  130. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +21 -7
  131. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
  132. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +27 -7
  133. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
  134. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +215 -32
  135. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
  136. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +378 -0
  137. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +7 -0
  138. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +340 -0
  139. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +7 -0
  140. package/dist/modules/staff/api/timesheets/time-entries/route.js +238 -26
  141. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  142. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +23 -8
  143. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
  144. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +209 -0
  145. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +7 -0
  146. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +59 -2
  147. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
  148. package/dist/modules/staff/api/timesheets/time-projects/route.js +264 -22
  149. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
  150. package/dist/modules/staff/backend/staff/time-tracking/board/page.js +110 -0
  151. package/dist/modules/staff/backend/staff/time-tracking/board/page.js.map +7 -0
  152. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js +18 -0
  153. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js.map +7 -0
  154. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +981 -0
  155. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +7 -0
  156. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js +18 -0
  157. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js.map +7 -0
  158. package/dist/modules/staff/backend/staff/time-tracking/page.js +583 -0
  159. package/dist/modules/staff/backend/staff/time-tracking/page.js.map +7 -0
  160. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js +15 -0
  161. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js.map +7 -0
  162. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js +65 -0
  163. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js.map +7 -0
  164. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js +16 -0
  165. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js.map +7 -0
  166. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +229 -0
  167. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +7 -0
  168. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js +16 -0
  169. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js.map +7 -0
  170. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +1014 -0
  171. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +7 -0
  172. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js +16 -0
  173. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js.map +7 -0
  174. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js +97 -0
  175. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js.map +7 -0
  176. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js +16 -0
  177. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js.map +7 -0
  178. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js +1040 -0
  179. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js.map +7 -0
  180. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js +19 -0
  181. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js.map +7 -0
  182. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +353 -0
  183. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +7 -0
  184. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +457 -0
  185. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +7 -0
  186. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js +16 -0
  187. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js.map +7 -0
  188. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js +697 -0
  189. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js.map +7 -0
  190. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js +16 -0
  191. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js.map +7 -0
  192. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js +174 -0
  193. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js.map +7 -0
  194. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js +18 -0
  195. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js.map +7 -0
  196. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +546 -0
  197. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +7 -0
  198. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js +18 -0
  199. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js.map +7 -0
  200. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js +710 -0
  201. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js.map +7 -0
  202. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js +646 -0
  203. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js.map +7 -0
  204. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js +18 -0
  205. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js.map +7 -0
  206. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -793
  207. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  208. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +2 -7
  209. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +2 -2
  210. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +5 -136
  211. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +2 -2
  212. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +1 -7
  213. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +2 -2
  214. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +5 -445
  215. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +3 -3
  216. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +1 -7
  217. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +2 -2
  218. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +4 -76
  219. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +2 -2
  220. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +1 -7
  221. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +2 -2
  222. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -613
  223. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  224. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +2 -17
  225. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +2 -2
  226. package/dist/modules/staff/ce.js +40 -0
  227. package/dist/modules/staff/ce.js.map +2 -2
  228. package/dist/modules/staff/cli.js +166 -1
  229. package/dist/modules/staff/cli.js.map +2 -2
  230. package/dist/modules/staff/commands/index.js +5 -0
  231. package/dist/modules/staff/commands/index.js.map +2 -2
  232. package/dist/modules/staff/commands/timesheets-entries.js +569 -21
  233. package/dist/modules/staff/commands/timesheets-entries.js.map +3 -3
  234. package/dist/modules/staff/commands/timesheets-projects.js +450 -7
  235. package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
  236. package/dist/modules/staff/commands/timesheets-reports.js +1036 -0
  237. package/dist/modules/staff/commands/timesheets-reports.js.map +7 -0
  238. package/dist/modules/staff/commands/timesheets-tags.js +1015 -0
  239. package/dist/modules/staff/commands/timesheets-tags.js.map +7 -0
  240. package/dist/modules/staff/commands/timesheets-task-comments.js +438 -0
  241. package/dist/modules/staff/commands/timesheets-task-comments.js.map +7 -0
  242. package/dist/modules/staff/commands/timesheets-task-statuses.js +723 -0
  243. package/dist/modules/staff/commands/timesheets-task-statuses.js.map +7 -0
  244. package/dist/modules/staff/commands/timesheets-tasks.js +834 -0
  245. package/dist/modules/staff/commands/timesheets-tasks.js.map +7 -0
  246. package/dist/modules/staff/data/enrichers.js +426 -12
  247. package/dist/modules/staff/data/enrichers.js.map +2 -2
  248. package/dist/modules/staff/data/entities.js +552 -3
  249. package/dist/modules/staff/data/entities.js.map +2 -2
  250. package/dist/modules/staff/data/extensions.js +41 -0
  251. package/dist/modules/staff/data/extensions.js.map +7 -0
  252. package/dist/modules/staff/data/validators.js +254 -9
  253. package/dist/modules/staff/data/validators.js.map +2 -2
  254. package/dist/modules/staff/di.js +42 -1
  255. package/dist/modules/staff/di.js.map +2 -2
  256. package/dist/modules/staff/events.js +84 -6
  257. package/dist/modules/staff/events.js.map +2 -2
  258. package/dist/modules/staff/events.payloads.js +158 -0
  259. package/dist/modules/staff/events.payloads.js.map +7 -0
  260. package/dist/modules/staff/extension-points.js +261 -0
  261. package/dist/modules/staff/extension-points.js.map +7 -0
  262. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +138 -0
  263. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +7 -0
  264. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js +12 -0
  265. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js.map +7 -0
  266. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +133 -0
  267. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +7 -0
  268. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js +19 -0
  269. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js.map +7 -0
  270. package/dist/modules/staff/lib/crud.js +11 -1
  271. package/dist/modules/staff/lib/crud.js.map +2 -2
  272. package/dist/modules/staff/lib/time-tracking/access.js +92 -0
  273. package/dist/modules/staff/lib/time-tracking/access.js.map +7 -0
  274. package/dist/modules/staff/lib/time-tracking/billability.js +39 -0
  275. package/dist/modules/staff/lib/time-tracking/billability.js.map +7 -0
  276. package/dist/modules/staff/lib/time-tracking/capacity.js +68 -0
  277. package/dist/modules/staff/lib/time-tracking/capacity.js.map +7 -0
  278. package/dist/modules/staff/lib/time-tracking/componentContracts.js +15 -0
  279. package/dist/modules/staff/lib/time-tracking/componentContracts.js.map +7 -0
  280. package/dist/modules/staff/lib/time-tracking/cost.js +82 -0
  281. package/dist/modules/staff/lib/time-tracking/cost.js.map +7 -0
  282. package/dist/modules/staff/lib/time-tracking/duration.js +55 -0
  283. package/dist/modules/staff/lib/time-tracking/duration.js.map +7 -0
  284. package/dist/modules/staff/lib/time-tracking/featureAccess.js +41 -0
  285. package/dist/modules/staff/lib/time-tracking/featureAccess.js.map +7 -0
  286. package/dist/modules/staff/lib/time-tracking/interval.js +72 -0
  287. package/dist/modules/staff/lib/time-tracking/interval.js.map +7 -0
  288. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js +88 -0
  289. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js.map +7 -0
  290. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js +10 -0
  291. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js.map +7 -0
  292. package/dist/modules/staff/lib/time-tracking/overlap.js +87 -0
  293. package/dist/modules/staff/lib/time-tracking/overlap.js.map +7 -0
  294. package/dist/modules/staff/lib/time-tracking/portalRecipients.js +27 -0
  295. package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +7 -0
  296. package/dist/modules/staff/lib/time-tracking/portalReports.js +16 -0
  297. package/dist/modules/staff/lib/time-tracking/portalReports.js.map +7 -0
  298. package/dist/modules/staff/lib/time-tracking/projectCode.js +135 -0
  299. package/dist/modules/staff/lib/time-tracking/projectCode.js.map +7 -0
  300. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js +187 -0
  301. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js.map +7 -0
  302. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js +80 -0
  303. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js.map +7 -0
  304. package/dist/modules/staff/lib/time-tracking/recalculations.js +56 -0
  305. package/dist/modules/staff/lib/time-tracking/recalculations.js.map +7 -0
  306. package/dist/modules/staff/lib/time-tracking/registries/invoke.js +63 -0
  307. package/dist/modules/staff/lib/time-tracking/registries/invoke.js.map +7 -0
  308. package/dist/modules/staff/lib/time-tracking/registries/registry.js +62 -0
  309. package/dist/modules/staff/lib/time-tracking/registries/registry.js.map +7 -0
  310. package/dist/modules/staff/lib/time-tracking/registries/scope.js +21 -0
  311. package/dist/modules/staff/lib/time-tracking/registries/scope.js.map +7 -0
  312. package/dist/modules/staff/lib/time-tracking/rollup.js +34 -0
  313. package/dist/modules/staff/lib/time-tracking/rollup.js.map +7 -0
  314. package/dist/modules/staff/lib/time-tracking/rounding.js +66 -0
  315. package/dist/modules/staff/lib/time-tracking/rounding.js.map +7 -0
  316. package/dist/modules/staff/lib/time-tracking/roundingImpact.js +39 -0
  317. package/dist/modules/staff/lib/time-tracking/roundingImpact.js.map +7 -0
  318. package/dist/modules/staff/lib/time-tracking/settingKeys.js +214 -0
  319. package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +7 -0
  320. package/dist/modules/staff/lib/time-tracking/settings.js +87 -0
  321. package/dist/modules/staff/lib/time-tracking/settings.js.map +7 -0
  322. package/dist/modules/staff/lib/time-tracking/sqlInClause.js +9 -0
  323. package/dist/modules/staff/lib/time-tracking/sqlInClause.js.map +7 -0
  324. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js +48 -0
  325. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js.map +7 -0
  326. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +283 -0
  327. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +7 -0
  328. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js +324 -0
  329. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js.map +7 -0
  330. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js +121 -0
  331. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js.map +7 -0
  332. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js +188 -0
  333. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js.map +7 -0
  334. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js +89 -0
  335. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js.map +7 -0
  336. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +855 -0
  337. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +7 -0
  338. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +360 -0
  339. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +7 -0
  340. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js +259 -0
  341. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js.map +7 -0
  342. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js +238 -0
  343. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js.map +7 -0
  344. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +130 -0
  345. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +7 -0
  346. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js +98 -0
  347. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js.map +7 -0
  348. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js +27 -0
  349. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js.map +7 -0
  350. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js +166 -0
  351. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js.map +7 -0
  352. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js +295 -0
  353. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js.map +7 -0
  354. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +212 -0
  355. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +7 -0
  356. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js +729 -0
  357. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js.map +7 -0
  358. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +217 -0
  359. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +7 -0
  360. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js +158 -0
  361. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js.map +7 -0
  362. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +224 -0
  363. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +7 -0
  364. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +93 -0
  365. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +7 -0
  366. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +1196 -0
  367. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +7 -0
  368. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +176 -0
  369. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +7 -0
  370. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js +307 -0
  371. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js.map +7 -0
  372. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js +284 -0
  373. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js.map +7 -0
  374. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js +73 -0
  375. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js.map +7 -0
  376. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js +1499 -0
  377. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js.map +7 -0
  378. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js +95 -0
  379. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js.map +7 -0
  380. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js +188 -0
  381. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js.map +7 -0
  382. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js +61 -0
  383. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js.map +7 -0
  384. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js +45 -0
  385. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js.map +7 -0
  386. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +176 -0
  387. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +7 -0
  388. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +82 -0
  389. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +7 -0
  390. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js +5 -0
  391. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js.map +7 -0
  392. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +152 -0
  393. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +7 -0
  394. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js +92 -0
  395. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js.map +7 -0
  396. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +111 -0
  397. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +7 -0
  398. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js +243 -0
  399. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js.map +7 -0
  400. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js +151 -0
  401. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js.map +7 -0
  402. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +105 -0
  403. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +7 -0
  404. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js +132 -0
  405. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js.map +7 -0
  406. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js +205 -0
  407. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js.map +7 -0
  408. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js +53 -0
  409. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js.map +7 -0
  410. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js +77 -0
  411. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js.map +7 -0
  412. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js +151 -0
  413. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js.map +7 -0
  414. package/dist/modules/staff/lib/timeTrackingSeeds.js +809 -0
  415. package/dist/modules/staff/lib/timeTrackingSeeds.js.map +7 -0
  416. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js +2 -3
  417. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js.map +2 -2
  418. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js +152 -0
  419. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js.map +7 -0
  420. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js +36 -0
  421. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js.map +7 -0
  422. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js +66 -0
  423. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js.map +7 -0
  424. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js +78 -0
  425. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js.map +7 -0
  426. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js +81 -0
  427. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js.map +7 -0
  428. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js +44 -0
  429. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js.map +7 -0
  430. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js +169 -0
  431. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js.map +7 -0
  432. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js +22 -0
  433. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js.map +7 -0
  434. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +51 -1
  435. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +2 -2
  436. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js +70 -0
  437. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js.map +7 -0
  438. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +63 -0
  439. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +7 -0
  440. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +170 -0
  441. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +7 -0
  442. package/dist/modules/staff/lib/timesheets-reports/pdf.js +205 -0
  443. package/dist/modules/staff/lib/timesheets-reports/pdf.js.map +7 -0
  444. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js +68 -0
  445. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js.map +7 -0
  446. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js +135 -0
  447. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js.map +7 -0
  448. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js +48 -0
  449. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js.map +7 -0
  450. package/dist/modules/staff/lib/timesheets-reports/reportExport.js +262 -0
  451. package/dist/modules/staff/lib/timesheets-reports/reportExport.js.map +7 -0
  452. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js +34 -0
  453. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js.map +7 -0
  454. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js +79 -0
  455. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js.map +7 -0
  456. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js +11 -0
  457. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js.map +7 -0
  458. package/dist/modules/staff/lib/timesheets-reports/reportReference.js +83 -0
  459. package/dist/modules/staff/lib/timesheets-reports/reportReference.js.map +7 -0
  460. package/dist/modules/staff/lib/timesheets-reports/reportRows.js +42 -0
  461. package/dist/modules/staff/lib/timesheets-reports/reportRows.js.map +7 -0
  462. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js +107 -0
  463. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js.map +7 -0
  464. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js +289 -0
  465. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js.map +7 -0
  466. package/dist/modules/staff/lib/timesheets-reports/xlsx.js +145 -0
  467. package/dist/modules/staff/lib/timesheets-reports/xlsx.js.map +7 -0
  468. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js +116 -0
  469. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js.map +7 -0
  470. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js +50 -0
  471. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js.map +7 -0
  472. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js +27 -0
  473. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js.map +7 -0
  474. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js +65 -0
  475. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js.map +7 -0
  476. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js +31 -0
  477. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js.map +7 -0
  478. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js +31 -0
  479. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js.map +7 -0
  480. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js +17 -0
  481. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js.map +7 -0
  482. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js +51 -0
  483. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js.map +7 -0
  484. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +11 -4
  485. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +2 -2
  486. package/dist/modules/staff/lib/timesheets-ui/ListView.js +369 -111
  487. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
  488. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +47 -2
  489. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +2 -2
  490. package/dist/modules/staff/migrations/Migration20260813073131_staff.js +79 -0
  491. package/dist/modules/staff/migrations/Migration20260813073131_staff.js.map +7 -0
  492. package/dist/modules/staff/migrations/Migration20260824143357_staff.js +15 -0
  493. package/dist/modules/staff/migrations/Migration20260824143357_staff.js.map +7 -0
  494. package/dist/modules/staff/notifications.client.js +16 -0
  495. package/dist/modules/staff/notifications.client.js.map +7 -0
  496. package/dist/modules/staff/notifications.handlers.js +80 -0
  497. package/dist/modules/staff/notifications.handlers.js.map +7 -0
  498. package/dist/modules/staff/notifications.js +168 -0
  499. package/dist/modules/staff/notifications.js.map +2 -2
  500. package/dist/modules/staff/search.js +159 -1
  501. package/dist/modules/staff/search.js.map +2 -2
  502. package/dist/modules/staff/setup.js +20 -1
  503. package/dist/modules/staff/setup.js.map +2 -2
  504. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js +68 -0
  505. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js.map +7 -0
  506. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js +149 -0
  507. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js.map +7 -0
  508. package/dist/modules/staff/subscribers/time-report-approved-notification.js +78 -0
  509. package/dist/modules/staff/subscribers/time-report-approved-notification.js.map +7 -0
  510. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js +78 -0
  511. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js.map +7 -0
  512. package/dist/modules/staff/translations.js +4 -1
  513. package/dist/modules/staff/translations.js.map +2 -2
  514. package/dist/modules/staff/widgets/components.js +7 -0
  515. package/dist/modules/staff/widgets/components.js.map +7 -0
  516. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +5 -4
  517. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +2 -2
  518. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js +135 -0
  519. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js.map +7 -0
  520. package/dist/modules/staff/widgets/notifications/index.js +5 -0
  521. package/dist/modules/staff/widgets/notifications/index.js.map +7 -0
  522. package/dist/modules/staff/workers/timesheets-reapply-rounding.js +43 -0
  523. package/dist/modules/staff/workers/timesheets-reapply-rounding.js.map +7 -0
  524. package/generated/entities/staff_time_entry/index.ts +7 -0
  525. package/generated/entities/staff_time_entry_tag/index.ts +6 -0
  526. package/generated/entities/staff_time_project/index.ts +8 -0
  527. package/generated/entities/staff_time_report/index.ts +27 -0
  528. package/generated/entities/staff_time_report_entry/index.ts +12 -0
  529. package/generated/entities/staff_time_report_event/index.ts +9 -0
  530. package/generated/entities/staff_time_report_project/index.ts +6 -0
  531. package/generated/entities/staff_time_tag/index.ts +9 -0
  532. package/generated/entities/staff_time_task/index.ts +17 -0
  533. package/generated/entities/staff_time_task_comment/index.ts +9 -0
  534. package/generated/entities/staff_time_task_status/index.ts +13 -0
  535. package/generated/entities/staff_time_task_tag/index.ts +6 -0
  536. package/generated/entities.ids.generated.ts +11 -1
  537. package/generated/entity-fields-registry.ts +149 -0
  538. package/package.json +7 -7
  539. package/src/helpers/integration/timesheetFixtures.ts +31 -1
  540. package/src/modules/auth/README.md +1 -1
  541. package/src/modules/auth/cli.ts +35 -1
  542. package/src/modules/auth/i18n/de.json +7 -0
  543. package/src/modules/auth/i18n/en.json +7 -0
  544. package/src/modules/auth/i18n/es.json +7 -0
  545. package/src/modules/auth/i18n/ko.json +7 -0
  546. package/src/modules/auth/i18n/pl.json +7 -0
  547. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  548. package/src/modules/customer_accounts/lib/customerRoleAcls.ts +79 -0
  549. package/src/modules/customer_accounts/setup.ts +1 -45
  550. package/src/modules/data_sync/AGENTS.md +34 -0
  551. package/src/modules/data_sync/api/options.ts +2 -0
  552. package/src/modules/data_sync/backend/data-sync/page.tsx +82 -33
  553. package/src/modules/data_sync/i18n/de.json +1 -0
  554. package/src/modules/data_sync/i18n/en.json +1 -0
  555. package/src/modules/data_sync/i18n/es.json +1 -0
  556. package/src/modules/data_sync/i18n/ko.json +1 -0
  557. package/src/modules/data_sync/i18n/pl.json +1 -0
  558. package/src/modules/data_sync/lib/adapter.ts +45 -0
  559. package/src/modules/data_sync/lib/start-controls.ts +89 -0
  560. package/src/modules/staff/AGENTS.md +769 -1
  561. package/src/modules/staff/acl.ts +9 -0
  562. package/src/modules/staff/ai-agents.ts +189 -0
  563. package/src/modules/staff/ai-tools/time-tracking-pack.ts +494 -0
  564. package/src/modules/staff/ai-tools/types.ts +82 -0
  565. package/src/modules/staff/ai-tools.ts +13 -0
  566. package/src/modules/staff/analytics.ts +113 -0
  567. package/src/modules/staff/api/guards.ts +85 -3
  568. package/src/modules/staff/api/leave-requests/accept/route.ts +0 -2
  569. package/src/modules/staff/api/leave-requests/reject/route.ts +0 -2
  570. package/src/modules/staff/api/portal/time-reports/[id]/route.ts +182 -0
  571. package/src/modules/staff/api/portal/time-reports/route.ts +270 -0
  572. package/src/modules/staff/api/team-members/self/route.ts +0 -2
  573. package/src/modules/staff/api/team-members/tags/assign/route.ts +0 -2
  574. package/src/modules/staff/api/team-members/tags/unassign/route.ts +0 -2
  575. package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +292 -0
  576. package/src/modules/staff/api/timesheets/access-requests/route.ts +299 -0
  577. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +15 -7
  578. package/src/modules/staff/api/timesheets/my-projects/route.ts +14 -1
  579. package/src/modules/staff/api/timesheets/my-work/myWorkAggregate.ts +90 -0
  580. package/src/modules/staff/api/timesheets/my-work/route.ts +475 -0
  581. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +15 -2
  582. package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +203 -0
  583. package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +315 -0
  584. package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +220 -0
  585. package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +208 -0
  586. package/src/modules/staff/api/timesheets/reports/preview/route.ts +449 -0
  587. package/src/modules/staff/api/timesheets/reports/route.ts +386 -0
  588. package/src/modules/staff/api/timesheets/reports/shared.ts +121 -0
  589. package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +205 -0
  590. package/src/modules/staff/api/timesheets/settings/rounding-impact/route.ts +226 -0
  591. package/src/modules/staff/api/timesheets/settings/route.ts +242 -0
  592. package/src/modules/staff/api/timesheets/tags/access.ts +134 -0
  593. package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +290 -0
  594. package/src/modules/staff/api/timesheets/tags/route.ts +177 -0
  595. package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +294 -0
  596. package/src/modules/staff/api/timesheets/task-statuses/route.ts +232 -0
  597. package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +532 -0
  598. package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +271 -0
  599. package/src/modules/staff/api/timesheets/tasks/route.ts +443 -0
  600. package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +306 -0
  601. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +32 -10
  602. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +32 -17
  603. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +27 -6
  604. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +36 -6
  605. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +331 -34
  606. package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +533 -0
  607. package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +457 -0
  608. package/src/modules/staff/api/timesheets/time-entries/route.ts +378 -24
  609. package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +31 -9
  610. package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +246 -0
  611. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +62 -2
  612. package/src/modules/staff/api/timesheets/time-projects/route.ts +397 -22
  613. package/src/modules/staff/backend/staff/time-tracking/board/page.meta.ts +14 -0
  614. package/src/modules/staff/backend/staff/time-tracking/board/page.tsx +151 -0
  615. package/src/modules/staff/backend/staff/time-tracking/entries/page.meta.ts +14 -0
  616. package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +1229 -0
  617. package/src/modules/staff/backend/staff/time-tracking/page.meta.ts +11 -0
  618. package/src/modules/staff/backend/staff/time-tracking/page.tsx +823 -0
  619. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.ts +12 -0
  620. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.tsx +81 -0
  621. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.ts +12 -0
  622. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +275 -0
  623. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.ts +12 -0
  624. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +1420 -0
  625. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.meta.ts +12 -0
  626. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.tsx +109 -0
  627. package/src/modules/staff/backend/staff/time-tracking/projects/page.meta.ts +15 -0
  628. package/src/modules/staff/backend/staff/time-tracking/projects/page.tsx +1254 -0
  629. package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +466 -0
  630. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.ts +12 -0
  631. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +632 -0
  632. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.meta.ts +12 -0
  633. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.tsx +867 -0
  634. package/src/modules/staff/backend/staff/time-tracking/reports/page.meta.ts +14 -0
  635. package/src/modules/staff/backend/staff/time-tracking/reports/page.tsx +246 -0
  636. package/src/modules/staff/backend/staff/time-tracking/settings/page.meta.ts +14 -0
  637. package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +701 -0
  638. package/src/modules/staff/backend/staff/time-tracking/timesheet/GridView.tsx +953 -0
  639. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.meta.ts +14 -0
  640. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.tsx +800 -0
  641. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +6 -6
  642. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1010
  643. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +0 -6
  644. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +4 -158
  645. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +0 -6
  646. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -609
  647. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +0 -6
  648. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +3 -89
  649. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +2 -19
  650. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +3 -778
  651. package/src/modules/staff/ce.ts +63 -0
  652. package/src/modules/staff/cli.ts +207 -1
  653. package/src/modules/staff/commands/index.ts +5 -0
  654. package/src/modules/staff/commands/timesheets-entries.ts +1006 -28
  655. package/src/modules/staff/commands/timesheets-projects.ts +593 -7
  656. package/src/modules/staff/commands/timesheets-reports.ts +1329 -0
  657. package/src/modules/staff/commands/timesheets-tags.ts +1315 -0
  658. package/src/modules/staff/commands/timesheets-task-comments.ts +583 -0
  659. package/src/modules/staff/commands/timesheets-task-statuses.ts +889 -0
  660. package/src/modules/staff/commands/timesheets-tasks.ts +1121 -0
  661. package/src/modules/staff/data/enrichers.ts +675 -10
  662. package/src/modules/staff/data/entities.ts +494 -2
  663. package/src/modules/staff/data/extensions.ts +68 -0
  664. package/src/modules/staff/data/validators.ts +348 -3
  665. package/src/modules/staff/di.ts +96 -0
  666. package/src/modules/staff/events.payloads.ts +268 -0
  667. package/src/modules/staff/events.ts +87 -5
  668. package/src/modules/staff/extension-points.ts +308 -0
  669. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.ts +10 -0
  670. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +225 -0
  671. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.ts +17 -0
  672. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +182 -0
  673. package/src/modules/staff/i18n/de.json +899 -0
  674. package/src/modules/staff/i18n/en.json +899 -0
  675. package/src/modules/staff/i18n/es.json +899 -0
  676. package/src/modules/staff/i18n/ko.json +899 -0
  677. package/src/modules/staff/i18n/pl.json +899 -0
  678. package/src/modules/staff/lib/crud.ts +14 -3
  679. package/src/modules/staff/lib/time-tracking/access.ts +155 -0
  680. package/src/modules/staff/lib/time-tracking/billability.ts +68 -0
  681. package/src/modules/staff/lib/time-tracking/capacity.ts +124 -0
  682. package/src/modules/staff/lib/time-tracking/componentContracts.ts +26 -0
  683. package/src/modules/staff/lib/time-tracking/cost.ts +144 -0
  684. package/src/modules/staff/lib/time-tracking/duration.ts +68 -0
  685. package/src/modules/staff/lib/time-tracking/featureAccess.ts +115 -0
  686. package/src/modules/staff/lib/time-tracking/interval.ts +90 -0
  687. package/src/modules/staff/lib/time-tracking/migrateProjectCodes.ts +161 -0
  688. package/src/modules/staff/lib/time-tracking/moneyVisibility.ts +37 -0
  689. package/src/modules/staff/lib/time-tracking/overlap.ts +159 -0
  690. package/src/modules/staff/lib/time-tracking/portalRecipients.ts +76 -0
  691. package/src/modules/staff/lib/time-tracking/portalReports.ts +31 -0
  692. package/src/modules/staff/lib/time-tracking/projectCode.ts +221 -0
  693. package/src/modules/staff/lib/time-tracking/reapplyRounding.ts +313 -0
  694. package/src/modules/staff/lib/time-tracking/recalculationRunner.ts +118 -0
  695. package/src/modules/staff/lib/time-tracking/recalculations.ts +135 -0
  696. package/src/modules/staff/lib/time-tracking/registries/invoke.ts +122 -0
  697. package/src/modules/staff/lib/time-tracking/registries/registry.ts +124 -0
  698. package/src/modules/staff/lib/time-tracking/registries/scope.ts +56 -0
  699. package/src/modules/staff/lib/time-tracking/rollup.ts +59 -0
  700. package/src/modules/staff/lib/time-tracking/rounding.ts +126 -0
  701. package/src/modules/staff/lib/time-tracking/roundingImpact.ts +75 -0
  702. package/src/modules/staff/lib/time-tracking/settingKeys.ts +274 -0
  703. package/src/modules/staff/lib/time-tracking/settings.ts +168 -0
  704. package/src/modules/staff/lib/time-tracking/sqlInClause.ts +22 -0
  705. package/src/modules/staff/lib/time-tracking/timeEntrySources.ts +85 -0
  706. package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +360 -0
  707. package/src/modules/staff/lib/time-tracking-ui/CustomerPicker.tsx +427 -0
  708. package/src/modules/staff/lib/time-tracking-ui/DurationInput.tsx +192 -0
  709. package/src/modules/staff/lib/time-tracking-ui/EntryDetailsFields.tsx +224 -0
  710. package/src/modules/staff/lib/time-tracking-ui/EntryFilterBar.tsx +144 -0
  711. package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +1065 -0
  712. package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +435 -0
  713. package/src/modules/staff/lib/time-tracking-ui/KanbanColumn.tsx +316 -0
  714. package/src/modules/staff/lib/time-tracking-ui/NewTaskDialog.tsx +291 -0
  715. package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +162 -0
  716. package/src/modules/staff/lib/time-tracking-ui/PeriodSelector.tsx +149 -0
  717. package/src/modules/staff/lib/time-tracking-ui/PhasePlaceholder.tsx +31 -0
  718. package/src/modules/staff/lib/time-tracking-ui/ProjectCodeField.tsx +230 -0
  719. package/src/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.tsx +432 -0
  720. package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +323 -0
  721. package/src/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.tsx +930 -0
  722. package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +357 -0
  723. package/src/modules/staff/lib/time-tracking-ui/TagPicker.tsx +195 -0
  724. package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +243 -0
  725. package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +137 -0
  726. package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +1405 -0
  727. package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +260 -0
  728. package/src/modules/staff/lib/time-tracking-ui/TaskPicker.tsx +435 -0
  729. package/src/modules/staff/lib/time-tracking-ui/TaskQuickLog.tsx +296 -0
  730. package/src/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.tsx +97 -0
  731. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDialog.tsx +1929 -0
  732. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.tsx +126 -0
  733. package/src/modules/staff/lib/time-tracking-ui/TimesheetCalendar.tsx +265 -0
  734. package/src/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.tsx +78 -0
  735. package/src/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.tsx +70 -0
  736. package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +231 -0
  737. package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +128 -0
  738. package/src/modules/staff/lib/time-tracking-ui/boardSummary.ts +20 -0
  739. package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +228 -0
  740. package/src/modules/staff/lib/time-tracking-ui/projectTeamAssignment.ts +143 -0
  741. package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +194 -0
  742. package/src/modules/staff/lib/time-tracking-ui/timeEntryDialogState.ts +400 -0
  743. package/src/modules/staff/lib/time-tracking-ui/timeEntryListData.ts +271 -0
  744. package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +168 -0
  745. package/src/modules/staff/lib/time-tracking-ui/timesheetData.ts +225 -0
  746. package/src/modules/staff/lib/time-tracking-ui/timesheetPeriod.ts +278 -0
  747. package/src/modules/staff/lib/time-tracking-ui/timesheetTargets.ts +93 -0
  748. package/src/modules/staff/lib/time-tracking-ui/useBoardFilters.ts +107 -0
  749. package/src/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.ts +245 -0
  750. package/src/modules/staff/lib/timeTrackingSeeds.ts +1037 -0
  751. package/src/modules/staff/lib/timesheets/timeEntryCacheInvalidation.ts +11 -10
  752. package/src/modules/staff/lib/timesheets/timeEntryDecoration.ts +256 -0
  753. package/src/modules/staff/lib/timesheets-projects/budgetBurn.ts +60 -0
  754. package/src/modules/staff/lib/timesheets-projects/budgetThreshold.ts +135 -0
  755. package/src/modules/staff/lib/timesheets-projects/budgetThresholdState.ts +137 -0
  756. package/src/modules/staff/lib/timesheets-projects/computeProjectFinancials.ts +142 -0
  757. package/src/modules/staff/lib/timesheets-projects/reportSelection.ts +82 -0
  758. package/src/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.tsx +237 -0
  759. package/src/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.tsx +33 -0
  760. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +56 -1
  761. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.tsx +90 -0
  762. package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +125 -0
  763. package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +251 -0
  764. package/src/modules/staff/lib/timesheets-reports/pdf.ts +263 -0
  765. package/src/modules/staff/lib/timesheets-reports/reportApprovalPolicies.ts +137 -0
  766. package/src/modules/staff/lib/timesheets-reports/reportConfigData.ts +247 -0
  767. package/src/modules/staff/lib/timesheets-reports/reportConfigState.ts +89 -0
  768. package/src/modules/staff/lib/timesheets-reports/reportExport.ts +373 -0
  769. package/src/modules/staff/lib/timesheets-reports/reportExportFormats.ts +71 -0
  770. package/src/modules/staff/lib/timesheets-reports/reportGroupings.ts +153 -0
  771. package/src/modules/staff/lib/timesheets-reports/reportLabels.ts +23 -0
  772. package/src/modules/staff/lib/timesheets-reports/reportReference.ts +146 -0
  773. package/src/modules/staff/lib/timesheets-reports/reportRows.ts +89 -0
  774. package/src/modules/staff/lib/timesheets-reports/reportSheetData.ts +196 -0
  775. package/src/modules/staff/lib/timesheets-reports/reportTotals.ts +544 -0
  776. package/src/modules/staff/lib/timesheets-reports/xlsx.ts +207 -0
  777. package/src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts +238 -0
  778. package/src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts +90 -0
  779. package/src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts +43 -0
  780. package/src/modules/staff/lib/timesheets-tasks/statusPositions.ts +132 -0
  781. package/src/modules/staff/lib/timesheets-tasks/statusSlug.ts +43 -0
  782. package/src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts +99 -0
  783. package/src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts +42 -0
  784. package/src/modules/staff/lib/timesheets-tasks/taskReference.ts +108 -0
  785. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +18 -4
  786. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +504 -149
  787. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +50 -2
  788. package/src/modules/staff/migrations/.snapshot-open-mercato.json +3244 -228
  789. package/src/modules/staff/migrations/Migration20260813073131_staff.ts +94 -0
  790. package/src/modules/staff/migrations/Migration20260824143357_staff.ts +17 -0
  791. package/src/modules/staff/notifications.client.ts +16 -0
  792. package/src/modules/staff/notifications.handlers.ts +88 -0
  793. package/src/modules/staff/notifications.ts +163 -0
  794. package/src/modules/staff/search.ts +191 -1
  795. package/src/modules/staff/setup.ts +22 -0
  796. package/src/modules/staff/subscribers/time-project-access-requested-notification.ts +95 -0
  797. package/src/modules/staff/subscribers/time-project-budget-threshold-notification.ts +226 -0
  798. package/src/modules/staff/subscribers/time-report-approved-notification.ts +116 -0
  799. package/src/modules/staff/subscribers/time-report-portal-broadcast.ts +120 -0
  800. package/src/modules/staff/translations.ts +17 -0
  801. package/src/modules/staff/widgets/components.ts +34 -0
  802. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +6 -5
  803. package/src/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.tsx +138 -0
  804. package/src/modules/staff/widgets/notifications/index.ts +1 -0
  805. package/src/modules/staff/workers/timesheets-reapply-rounding.ts +59 -0
  806. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +0 -123
  807. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +0 -7
  808. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +0 -138
@@ -0,0 +1,316 @@
1
+ import { z } from "zod";
2
+ import { makeCrudRoute } from "@open-mercato/shared/lib/crud/factory";
3
+ import { staffTimeReportCrudEvents } from "../../../lib/crud.js";
4
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
+ import { resolveCrudRecordId, parseScopedCommandInput } from "@open-mercato/shared/lib/api/scoped";
6
+ import { escapeLikePattern } from "@open-mercato/shared/lib/db/escapeLikePattern";
7
+ import { createLogger } from "@open-mercato/shared/lib/logger";
8
+ import { StaffTimeReport, StaffTimeReportProject } from "../../../data/entities.js";
9
+ import { staffTimeReportCreateSchema, staffTimeReportUpdateSchema } from "../../../data/validators.js";
10
+ import { staffTimeReportCommandIds } from "../../../commands/timesheets-reports.js";
11
+ import { resolveFeatureAccess } from "../../../lib/time-tracking/featureAccess.js";
12
+ import { MANAGE_PROJECTS_FEATURE, resolveProjectAccess } from "../../../lib/time-tracking/access.js";
13
+ import { readTimeTrackingSettings } from "../../../lib/time-tracking/settings.js";
14
+ import { sanitizeSearchTerm } from "../../helpers.js";
15
+ import { createStaffCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from "../../openapi.js";
16
+ const logger = createLogger("staff").child({ component: "api/timesheets/reports" });
17
+ const F = {
18
+ id: "id",
19
+ tenant_id: "tenant_id",
20
+ organization_id: "organization_id",
21
+ customer_id: "customer_id",
22
+ customer_snapshot: "customer_snapshot",
23
+ reference: "reference",
24
+ title: "title",
25
+ period_kind: "period_kind",
26
+ period_from: "period_from",
27
+ period_to: "period_to",
28
+ currency_code: "currency_code",
29
+ grouping: "grouping",
30
+ nonbillable_mode: "nonbillable_mode",
31
+ include_already_reported: "include_already_reported",
32
+ show_rates: "show_rates",
33
+ rounding_unit_minutes: "rounding_unit_minutes",
34
+ rounding_direction: "rounding_direction",
35
+ status: "status",
36
+ total_billable_minutes: "total_billable_minutes",
37
+ total_nonbillable_minutes: "total_nonbillable_minutes",
38
+ total_amount: "total_amount",
39
+ closed_at: "closed_at",
40
+ closed_by_user_id: "closed_by_user_id",
41
+ created_by_user_id: "created_by_user_id",
42
+ created_at: "created_at",
43
+ updated_at: "updated_at"
44
+ };
45
+ const routeMetadata = {
46
+ GET: { requireAuth: true, requireFeatures: ["staff.timesheets.reports.view"] },
47
+ POST: { requireAuth: true, requireFeatures: ["staff.timesheets.reports.manage"] },
48
+ PUT: { requireAuth: true, requireFeatures: ["staff.timesheets.reports.manage"] },
49
+ DELETE: { requireAuth: true, requireFeatures: ["staff.timesheets.reports.manage"] }
50
+ };
51
+ const metadata = routeMetadata;
52
+ const rawBodySchema = z.object({}).passthrough();
53
+ const listSchema = z.object({
54
+ page: z.coerce.number().min(1).default(1),
55
+ pageSize: z.coerce.number().min(1).max(100).default(50),
56
+ q: z.string().optional(),
57
+ id: z.string().optional(),
58
+ ids: z.string().optional(),
59
+ customerId: z.string().uuid().optional(),
60
+ status: z.enum(["draft", "closed"]).optional(),
61
+ sortField: z.string().optional(),
62
+ sortDir: z.enum(["asc", "desc"]).optional()
63
+ }).passthrough();
64
+ const IMPOSSIBLE_ID = "00000000-0000-0000-0000-000000000000";
65
+ const DENIED_ACCESS = { canManageAll: false, projectIds: [], staffMemberId: null };
66
+ const accessByRequest = /* @__PURE__ */ new WeakMap();
67
+ async function resolveAssignmentGraceDays(container, tenantId) {
68
+ try {
69
+ const configService = container.resolve("moduleConfigService");
70
+ const settings = await readTimeTrackingSettings(configService, { tenantId });
71
+ return settings.access.assignmentGraceDays;
72
+ } catch {
73
+ return null;
74
+ }
75
+ }
76
+ async function loadProjectAccess(container, userId, tenantId, organizationId) {
77
+ if (!tenantId || !organizationId) return { ...DENIED_ACCESS };
78
+ const scope = { tenantId, organizationId };
79
+ try {
80
+ const access = await resolveFeatureAccess(container, userId, [MANAGE_PROJECTS_FEATURE], scope);
81
+ const em = container.resolve("em");
82
+ return await resolveProjectAccess({
83
+ em: em.fork(),
84
+ userId,
85
+ tenantId,
86
+ organizationId,
87
+ canManageAll: access.allowed,
88
+ userFeatures: access.grantedFeatures,
89
+ assignmentGraceDays: await resolveAssignmentGraceDays(container, tenantId)
90
+ });
91
+ } catch (err) {
92
+ logger.error("staff.timesheets.reports access resolution failed", { err });
93
+ return { ...DENIED_ACCESS };
94
+ }
95
+ }
96
+ async function resolveListProjectAccess(ctx) {
97
+ const tenantId = ctx.auth?.tenantId ?? null;
98
+ const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
99
+ const load = () => loadProjectAccess(ctx.container, ctx.auth?.sub ?? null, tenantId, organizationId);
100
+ const request = ctx.request;
101
+ if (!request) return load();
102
+ const cached = accessByRequest.get(request);
103
+ if (cached) return cached;
104
+ const pending = load();
105
+ accessByRequest.set(request, pending);
106
+ return pending;
107
+ }
108
+ function splitIdList(value) {
109
+ if (typeof value !== "string" || value.trim().length === 0) return null;
110
+ const ids = value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
111
+ return ids.length > 0 ? ids : [];
112
+ }
113
+ async function reportIdsForProjects(ctx, projectIds) {
114
+ if (projectIds.length === 0) return [];
115
+ const tenantId = ctx.auth?.tenantId ?? null;
116
+ const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null;
117
+ if (!tenantId || !organizationId) return [];
118
+ const em = ctx.container.resolve("em").fork();
119
+ const rows = await em.find(StaffTimeReportProject, {
120
+ timeProjectId: { $in: [...projectIds] },
121
+ tenantId,
122
+ organizationId
123
+ });
124
+ return Array.from(new Set(rows.map((row) => row.reportId)));
125
+ }
126
+ async function buildReportListFilters(query, ctx) {
127
+ const filters = {};
128
+ let narrowIds = null;
129
+ for (const raw of [query.ids, query.id]) {
130
+ const parsed = splitIdList(raw);
131
+ if (parsed === null) continue;
132
+ narrowIds = narrowIds ? narrowIds.filter((id) => parsed.includes(id)) : parsed;
133
+ }
134
+ const access = await resolveListProjectAccess(ctx);
135
+ if (!access.canManageAll) {
136
+ const allowed = await reportIdsForProjects(ctx, access.projectIds);
137
+ narrowIds = narrowIds ? narrowIds.filter((id) => allowed.includes(id)) : allowed;
138
+ if (narrowIds.length === 0) {
139
+ filters[F.id] = { $in: [IMPOSSIBLE_ID] };
140
+ return filters;
141
+ }
142
+ }
143
+ if (narrowIds !== null) {
144
+ if (narrowIds.length === 0) {
145
+ filters[F.id] = { $in: [IMPOSSIBLE_ID] };
146
+ return filters;
147
+ }
148
+ filters[F.id] = { $in: narrowIds };
149
+ }
150
+ if (typeof query.customerId === "string" && query.customerId.trim().length > 0) {
151
+ filters[F.customer_id] = query.customerId.trim();
152
+ }
153
+ if (typeof query.status === "string" && query.status.length > 0) {
154
+ filters[F.status] = query.status;
155
+ }
156
+ const term = sanitizeSearchTerm(query.q);
157
+ if (term) {
158
+ filters[F.title] = { $ilike: `%${escapeLikePattern(term)}%` };
159
+ }
160
+ return filters;
161
+ }
162
+ const reportListFields = [
163
+ F.id,
164
+ F.organization_id,
165
+ F.tenant_id,
166
+ F.customer_id,
167
+ F.customer_snapshot,
168
+ F.reference,
169
+ F.title,
170
+ F.period_kind,
171
+ F.period_from,
172
+ F.period_to,
173
+ F.currency_code,
174
+ F.grouping,
175
+ F.nonbillable_mode,
176
+ F.include_already_reported,
177
+ F.show_rates,
178
+ F.rounding_unit_minutes,
179
+ F.rounding_direction,
180
+ F.status,
181
+ F.total_billable_minutes,
182
+ F.total_nonbillable_minutes,
183
+ F.total_amount,
184
+ F.closed_at,
185
+ F.closed_by_user_id,
186
+ F.created_by_user_id,
187
+ F.created_at,
188
+ F.updated_at
189
+ ];
190
+ const crud = makeCrudRoute({
191
+ metadata: routeMetadata,
192
+ orm: {
193
+ entity: StaffTimeReport,
194
+ idField: "id",
195
+ orgField: "organizationId",
196
+ tenantField: "tenantId",
197
+ softDeleteField: "deletedAt"
198
+ },
199
+ events: staffTimeReportCrudEvents,
200
+ enrichers: { entityId: "staff:staff_time_report" },
201
+ indexer: { entityType: "staff:staff_time_report" },
202
+ list: {
203
+ schema: listSchema,
204
+ entityId: "staff:staff_time_report",
205
+ fields: [...reportListFields],
206
+ defaultSort: { field: F.created_at, dir: "desc" },
207
+ tiebreakSortField: F.id,
208
+ sortFieldMap: {
209
+ createdAt: F.created_at,
210
+ updatedAt: F.updated_at,
211
+ reference: F.reference,
212
+ title: F.title,
213
+ periodFrom: F.period_from,
214
+ periodTo: F.period_to,
215
+ status: F.status,
216
+ totalAmount: F.total_amount
217
+ },
218
+ buildFilters: buildReportListFilters
219
+ },
220
+ actions: {
221
+ create: {
222
+ commandId: staffTimeReportCommandIds.create,
223
+ schema: rawBodySchema,
224
+ mapInput: async ({ raw, ctx }) => {
225
+ const { translate } = await resolveTranslations();
226
+ return parseScopedCommandInput(staffTimeReportCreateSchema, raw ?? {}, ctx, translate);
227
+ },
228
+ response: ({ result }) => ({ id: result?.reportId ?? null }),
229
+ status: 201
230
+ },
231
+ update: {
232
+ commandId: staffTimeReportCommandIds.update,
233
+ schema: rawBodySchema,
234
+ mapInput: async ({ raw, ctx }) => {
235
+ const { translate } = await resolveTranslations();
236
+ return parseScopedCommandInput(staffTimeReportUpdateSchema, raw ?? {}, ctx, translate);
237
+ },
238
+ response: () => ({ ok: true })
239
+ },
240
+ delete: {
241
+ commandId: staffTimeReportCommandIds.delete,
242
+ schema: rawBodySchema,
243
+ mapInput: async ({ parsed, ctx }) => {
244
+ const { translate } = await resolveTranslations();
245
+ const id = resolveCrudRecordId(parsed, ctx, translate);
246
+ return { id };
247
+ },
248
+ response: () => ({ ok: true })
249
+ }
250
+ }
251
+ });
252
+ const GET = crud.GET;
253
+ const POST = crud.POST;
254
+ const PUT = crud.PUT;
255
+ const DELETE = crud.DELETE;
256
+ const reportListItemSchema = z.object({
257
+ id: z.string().uuid().nullable().optional(),
258
+ organization_id: z.string().uuid().nullable().optional(),
259
+ tenant_id: z.string().uuid().nullable().optional(),
260
+ customer_id: z.string().uuid().nullable().optional(),
261
+ customer_snapshot: z.record(z.string(), z.unknown()).nullable().optional(),
262
+ reference: z.string().nullable().optional(),
263
+ title: z.string().nullable().optional(),
264
+ period_kind: z.string().nullable().optional(),
265
+ period_from: z.string().nullable().optional(),
266
+ period_to: z.string().nullable().optional(),
267
+ currency_code: z.string().nullable().optional(),
268
+ grouping: z.string().nullable().optional(),
269
+ nonbillable_mode: z.string().nullable().optional(),
270
+ include_already_reported: z.boolean().nullable().optional(),
271
+ show_rates: z.boolean().nullable().optional(),
272
+ rounding_unit_minutes: z.number().int().nullable().optional(),
273
+ rounding_direction: z.string().nullable().optional(),
274
+ status: z.string().nullable().optional(),
275
+ total_billable_minutes: z.number().int().nullable().optional(),
276
+ total_nonbillable_minutes: z.number().int().nullable().optional(),
277
+ total_amount: z.union([z.string(), z.number()]).nullable().optional(),
278
+ closed_at: z.string().nullable().optional(),
279
+ closed_by_user_id: z.string().uuid().nullable().optional(),
280
+ created_by_user_id: z.string().uuid().nullable().optional(),
281
+ created_at: z.string().nullable().optional(),
282
+ updated_at: z.string().nullable().optional()
283
+ });
284
+ const openApi = createStaffCrudOpenApi({
285
+ resourceName: "TimeReport",
286
+ pluralName: "Time Reports",
287
+ querySchema: listSchema,
288
+ listResponseSchema: createPagedListResponseSchema(reportListItemSchema),
289
+ create: {
290
+ schema: staffTimeReportCreateSchema,
291
+ description: "Creates a draft customer report and allocates its RAP-<year>-<seq> reference. Every selected project must belong to `customerId` and the projects must agree on a currency; a mismatch is refused with 422 report_currency_conflict naming the offenders."
292
+ },
293
+ update: {
294
+ schema: staffTimeReportUpdateSchema,
295
+ responseSchema: defaultOkResponseSchema,
296
+ description: "Updates a draft report. A closed report is refused with 409 report_closed \u2014 unlock it first. Replacing `timeProjectIds` re-asserts the single-customer and single-currency rules."
297
+ },
298
+ del: {
299
+ schema: z.object({ id: z.string().uuid() }),
300
+ responseSchema: defaultOkResponseSchema,
301
+ description: "Soft-deletes a draft report. A closed report is refused with 409 report_closed, because deleting it would strand the entries it froze."
302
+ }
303
+ });
304
+ export {
305
+ DELETE,
306
+ GET,
307
+ POST,
308
+ PUT,
309
+ buildReportListFilters,
310
+ metadata,
311
+ openApi,
312
+ reportListFields,
313
+ reportListItemSchema,
314
+ resolveListProjectAccess
315
+ };
316
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/staff/api/timesheets/reports/route.ts"],
4
+ "sourcesContent": ["/**\n * Customer reports \u2014 the collection behind screens 13, 14 and 15.\n *\n * Two things beyond plain CRUD:\n *\n * 1. **Project access is intersected into the list.** `reports.view` is a Team\n * Leader feature and a Team Leader normally also holds\n * `staff.timesheets.projects.manage`, so the common path is unrestricted.\n * A caller granted `reports.view` WITHOUT `projects.manage` is nonetheless\n * narrowed to reports that include at least one project they are a member\n * of \u2014 the same fail-closed shape the tasks and projects routes use, so a\n * future grant can never turn this route into a customer-list oracle.\n * 2. **Writes go through the report commands**, which own the single-customer\n * and single-currency assertions (risk R2) and the `RAP-<year>-<seq>`\n * allocation. The factory's command path is also the mutation-guard wiring,\n * so this file deliberately does not call `runRouteMutationGuards` itself.\n */\n\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { staffTimeReportCrudEvents } from '../../../lib/crud'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveCrudRecordId, parseScopedCommandInput } from '@open-mercato/shared/lib/api/scoped'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport type { ModuleConfigService } from '@open-mercato/core/modules/configs/lib/module-config-service'\nimport { StaffTimeReport, StaffTimeReportProject } from '../../../data/entities'\nimport { staffTimeReportCreateSchema, staffTimeReportUpdateSchema } from '../../../data/validators'\nimport { staffTimeReportCommandIds } from '../../../commands/timesheets-reports'\nimport { resolveFeatureAccess } from '../../../lib/time-tracking/featureAccess'\nimport { MANAGE_PROJECTS_FEATURE, resolveProjectAccess, type ProjectAccess } from '../../../lib/time-tracking/access'\nimport { readTimeTrackingSettings } from '../../../lib/time-tracking/settings'\nimport { sanitizeSearchTerm } from '../../helpers'\nimport { createStaffCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from '../../openapi'\n\nconst logger = createLogger('staff').child({ component: 'api/timesheets/reports' })\n\nconst F = {\n id: 'id',\n tenant_id: 'tenant_id',\n organization_id: 'organization_id',\n customer_id: 'customer_id',\n customer_snapshot: 'customer_snapshot',\n reference: 'reference',\n title: 'title',\n period_kind: 'period_kind',\n period_from: 'period_from',\n period_to: 'period_to',\n currency_code: 'currency_code',\n grouping: 'grouping',\n nonbillable_mode: 'nonbillable_mode',\n include_already_reported: 'include_already_reported',\n show_rates: 'show_rates',\n rounding_unit_minutes: 'rounding_unit_minutes',\n rounding_direction: 'rounding_direction',\n status: 'status',\n total_billable_minutes: 'total_billable_minutes',\n total_nonbillable_minutes: 'total_nonbillable_minutes',\n total_amount: 'total_amount',\n closed_at: 'closed_at',\n closed_by_user_id: 'closed_by_user_id',\n created_by_user_id: 'created_by_user_id',\n created_at: 'created_at',\n updated_at: 'updated_at',\n} as const\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['staff.timesheets.reports.view'] },\n POST: { requireAuth: true, requireFeatures: ['staff.timesheets.reports.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['staff.timesheets.reports.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['staff.timesheets.reports.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n q: z.string().optional(),\n id: z.string().optional(),\n ids: z.string().optional(),\n customerId: z.string().uuid().optional(),\n status: z.enum(['draft', 'closed']).optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype ReportListQuery = z.infer<typeof listSchema>\n\nconst IMPOSSIBLE_ID = '00000000-0000-0000-0000-000000000000'\n\nconst DENIED_ACCESS: ProjectAccess = { canManageAll: false, projectIds: [], staffMemberId: null }\n\ntype RbacServiceLike = {\n getGrantedFeatures?: (\n userId: string,\n options: { tenantId: string | null; organizationId: string | null },\n ) => Promise<string[]>\n}\n\ntype ContainerLike = { resolve: (name: string) => unknown }\n\nconst accessByRequest = new WeakMap<Request, Promise<ProjectAccess>>()\n\nasync function resolveAssignmentGraceDays(container: ContainerLike, tenantId: string): Promise<number | null> {\n try {\n const configService = container.resolve('moduleConfigService') as ModuleConfigService\n const settings = await readTimeTrackingSettings(configService, { tenantId })\n return settings.access.assignmentGraceDays\n } catch {\n return null\n }\n}\n\nasync function loadProjectAccess(\n container: ContainerLike,\n userId: string | null,\n tenantId: string | null,\n organizationId: string | null,\n): Promise<ProjectAccess> {\n if (!tenantId || !organizationId) return { ...DENIED_ACCESS }\n const scope = { tenantId, organizationId }\n try {\n // One lookup, one authority, and a failure that says so. The previous\n // `catch \u2192 []` could not tell \"denied\" from \"could not ask\", so an RBAC\n // hiccup silently demoted a manager to their own memberships.\n const access = await resolveFeatureAccess(container, userId, [MANAGE_PROJECTS_FEATURE], scope)\n const em = container.resolve('em') as EntityManager\n return await resolveProjectAccess({\n em: em.fork(),\n userId,\n tenantId,\n organizationId,\n canManageAll: access.allowed,\n userFeatures: access.grantedFeatures,\n assignmentGraceDays: await resolveAssignmentGraceDays(container, tenantId),\n })\n } catch (err) {\n logger.error('staff.timesheets.reports access resolution failed', { err })\n return { ...DENIED_ACCESS }\n }\n}\n\nexport async function resolveListProjectAccess(ctx: CrudCtx): Promise<ProjectAccess> {\n const tenantId = ctx.auth?.tenantId ?? null\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n const load = () => loadProjectAccess(ctx.container, ctx.auth?.sub ?? null, tenantId, organizationId)\n const request = ctx.request\n if (!request) return load()\n const cached = accessByRequest.get(request)\n if (cached) return cached\n const pending = load()\n accessByRequest.set(request, pending)\n return pending\n}\n\nfunction splitIdList(value: unknown): string[] | null {\n if (typeof value !== 'string' || value.trim().length === 0) return null\n const ids = value\n .split(',')\n .map((entry) => entry.trim())\n .filter((entry) => entry.length > 0)\n return ids.length > 0 ? ids : []\n}\n\n/**\n * Reports the caller may see when they are not a project manager: those whose\n * selection touches at least one project they are an active member of.\n */\nasync function reportIdsForProjects(\n ctx: CrudCtx,\n projectIds: readonly string[],\n): Promise<string[]> {\n if (projectIds.length === 0) return []\n const tenantId = ctx.auth?.tenantId ?? null\n const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null\n if (!tenantId || !organizationId) return []\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const rows = await em.find(StaffTimeReportProject, {\n timeProjectId: { $in: [...projectIds] },\n tenantId,\n organizationId,\n })\n return Array.from(new Set(rows.map((row) => row.reportId)))\n}\n\nexport async function buildReportListFilters(\n query: ReportListQuery,\n ctx: CrudCtx,\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {}\n\n let narrowIds: string[] | null = null\n for (const raw of [query.ids, query.id]) {\n const parsed = splitIdList(raw)\n if (parsed === null) continue\n narrowIds = narrowIds ? narrowIds.filter((id) => parsed.includes(id)) : parsed\n }\n\n const access = await resolveListProjectAccess(ctx)\n if (!access.canManageAll) {\n const allowed = await reportIdsForProjects(ctx, access.projectIds)\n narrowIds = narrowIds ? narrowIds.filter((id) => allowed.includes(id)) : allowed\n if (narrowIds.length === 0) {\n filters[F.id] = { $in: [IMPOSSIBLE_ID] }\n return filters\n }\n }\n\n if (narrowIds !== null) {\n if (narrowIds.length === 0) {\n filters[F.id] = { $in: [IMPOSSIBLE_ID] }\n return filters\n }\n filters[F.id] = { $in: narrowIds }\n }\n\n if (typeof query.customerId === 'string' && query.customerId.trim().length > 0) {\n filters[F.customer_id] = query.customerId.trim()\n }\n if (typeof query.status === 'string' && query.status.length > 0) {\n filters[F.status] = query.status\n }\n\n const term = sanitizeSearchTerm(query.q)\n if (term) {\n filters[F.title] = { $ilike: `%${escapeLikePattern(term)}%` }\n }\n\n return filters\n}\n\nexport const reportListFields = [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.customer_id,\n F.customer_snapshot,\n F.reference,\n F.title,\n F.period_kind,\n F.period_from,\n F.period_to,\n F.currency_code,\n F.grouping,\n F.nonbillable_mode,\n F.include_already_reported,\n F.show_rates,\n F.rounding_unit_minutes,\n F.rounding_direction,\n F.status,\n F.total_billable_minutes,\n F.total_nonbillable_minutes,\n F.total_amount,\n F.closed_at,\n F.closed_by_user_id,\n F.created_by_user_id,\n F.created_at,\n F.updated_at,\n] as const\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: StaffTimeReport,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n events: staffTimeReportCrudEvents,\n enrichers: { entityId: 'staff:staff_time_report' },\n indexer: { entityType: 'staff:staff_time_report' },\n list: {\n schema: listSchema,\n entityId: 'staff:staff_time_report',\n fields: [...reportListFields],\n defaultSort: { field: F.created_at, dir: 'desc' },\n tiebreakSortField: F.id,\n sortFieldMap: {\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n reference: F.reference,\n title: F.title,\n periodFrom: F.period_from,\n periodTo: F.period_to,\n status: F.status,\n totalAmount: F.total_amount,\n },\n buildFilters: buildReportListFilters,\n },\n actions: {\n create: {\n commandId: staffTimeReportCommandIds.create,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(staffTimeReportCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.reportId ?? null }),\n status: 201,\n },\n update: {\n commandId: staffTimeReportCommandIds.update,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(staffTimeReportUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: staffTimeReportCommandIds.delete,\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nexport const reportListItemSchema = z.object({\n id: z.string().uuid().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n customer_id: z.string().uuid().nullable().optional(),\n customer_snapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n reference: z.string().nullable().optional(),\n title: z.string().nullable().optional(),\n period_kind: z.string().nullable().optional(),\n period_from: z.string().nullable().optional(),\n period_to: z.string().nullable().optional(),\n currency_code: z.string().nullable().optional(),\n grouping: z.string().nullable().optional(),\n nonbillable_mode: z.string().nullable().optional(),\n include_already_reported: z.boolean().nullable().optional(),\n show_rates: z.boolean().nullable().optional(),\n rounding_unit_minutes: z.number().int().nullable().optional(),\n rounding_direction: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n total_billable_minutes: z.number().int().nullable().optional(),\n total_nonbillable_minutes: z.number().int().nullable().optional(),\n total_amount: z.union([z.string(), z.number()]).nullable().optional(),\n closed_at: z.string().nullable().optional(),\n closed_by_user_id: z.string().uuid().nullable().optional(),\n created_by_user_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createStaffCrudOpenApi({\n resourceName: 'TimeReport',\n pluralName: 'Time Reports',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(reportListItemSchema),\n create: {\n schema: staffTimeReportCreateSchema,\n description:\n 'Creates a draft customer report and allocates its RAP-<year>-<seq> reference. Every selected project must belong to `customerId` and the projects must agree on a currency; a mismatch is refused with 422 report_currency_conflict naming the offenders.',\n },\n update: {\n schema: staffTimeReportUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description:\n 'Updates a draft report. A closed report is refused with 409 report_closed \u2014 unlock it first. Replacing `timeProjectIds` re-asserts the single-customer and single-currency rules.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description:\n 'Soft-deletes a draft report. A closed report is refused with 409 report_closed, because deleting it would strand the entries it froze.',\n },\n})\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,63 @@
1
+ import { RATES_FEATURE } from "../../../lib/time-tracking/moneyVisibility.js";
2
+ import { resolveFeatureAccess } from "../../../lib/time-tracking/featureAccess.js";
3
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
4
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
5
+ import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
6
+ import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
7
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
8
+ import { reportSheetLabels } from "../../../lib/timesheets-reports/reportLabels.js";
9
+ const MAX_SHEET_ROWS = 500;
10
+ function extractReportIdFromUrl(url, segment) {
11
+ if (!url) return null;
12
+ try {
13
+ const pathname = new URL(url).pathname;
14
+ const match = pathname.match(new RegExp(`/reports/([^/]+)/${segment}`));
15
+ return match?.[1] ?? null;
16
+ } catch {
17
+ return null;
18
+ }
19
+ }
20
+ async function resolveReportRequestContext(req, options) {
21
+ const container = await createRequestContainer();
22
+ const auth = await getAuthFromRequest(req);
23
+ const { translate } = await resolveTranslations();
24
+ if (!auth) {
25
+ throw new CrudHttpError(401, { error: translate("staff.errors.unauthorized", "Unauthorized") });
26
+ }
27
+ const organizationScope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
28
+ const tenantId = organizationScope?.tenantId ?? auth.tenantId ?? null;
29
+ const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null;
30
+ if (!tenantId || !organizationId) {
31
+ throw new CrudHttpError(400, {
32
+ error: translate("staff.errors.missingScope", "Missing tenant or organization scope.")
33
+ });
34
+ }
35
+ const reportId = extractReportIdFromUrl(req.url, options.segment);
36
+ if (!reportId) {
37
+ throw new CrudHttpError(400, {
38
+ error: translate("staff.time_tracking.reports.errors.idRequired", "Report id is required.")
39
+ });
40
+ }
41
+ const ratesAccess = await resolveFeatureAccess(container, auth.sub ?? null, [RATES_FEATURE], {
42
+ tenantId,
43
+ organizationId
44
+ });
45
+ return {
46
+ container,
47
+ auth,
48
+ organizationScope,
49
+ tenantId,
50
+ organizationId,
51
+ reportId,
52
+ translate,
53
+ grantedFeatures: ratesAccess.grantedFeatures,
54
+ canSeeMoney: ratesAccess.allowed
55
+ };
56
+ }
57
+ export {
58
+ MAX_SHEET_ROWS,
59
+ extractReportIdFromUrl,
60
+ reportSheetLabels,
61
+ resolveReportRequestContext
62
+ };
63
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/staff/api/timesheets/reports/shared.ts"],
4
+ "sourcesContent": ["/**\n * Shared boilerplate for the hand-written report sub-routes (`sheet`, `close`,\n * `unlock`, `export`).\n *\n * Four routes needing the same six lines of auth, scope, id extraction and\n * granted-feature resolution is exactly the situation where one of them\n * eventually forgets the tenant filter. Resolving it in one place makes that\n * impossible rather than unlikely.\n */\n\nimport { RATES_FEATURE } from '../../../lib/time-tracking/moneyVisibility'\nimport { resolveFeatureAccess } from '../../../lib/time-tracking/featureAccess'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { reportSheetLabels } from '../../../lib/timesheets-reports/reportLabels'\n\nexport { reportSheetLabels }\n\n/**\n * Cap on the raw rows a sheet response carries. A report covering a quarter of a\n * ten-person team can run into the thousands, and the screen paginates anyway;\n * the response says when it truncated rather than quietly serving a short list.\n */\nexport const MAX_SHEET_ROWS = 500\n\nexport type Translate = (key: string, fallback: string) => string\n\nexport type ReportRequestContext = {\n container: Awaited<ReturnType<typeof createRequestContainer>>\n auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>\n organizationScope: Awaited<ReturnType<typeof resolveOrganizationScopeForRequest>>\n tenantId: string\n organizationId: string\n reportId: string\n translate: Translate\n /**\n * The caller's grants, for the plumbing that takes a list: the approval\n * policies, the interceptor context and the mutation-guard registry. Always an\n * array, never `null` \u2014 a nullable grant list is what let \"RBAC could not\n * answer\" read as \"no restriction\" on these routes.\n *\n * Empty means the same thing whether RBAC answered \"nothing\" or could not\n * answer at all, and every consumer treats it the same fail-closed way: an\n * approval policy that requires a feature refuses, a feature-gated interceptor\n * does not run, and a feature-gated guard does not run. Authorization never\n * rests on it \u2014 `canSeeMoney` and each route's own `resolveFeatureAccess` gate\n * are the decisions, and both fail closed on their own. `resolveFeatureAccess`\n * logs a grant list it could not read, so an outage is visible to operators\n * without a flag here that no caller can act on.\n */\n grantedFeatures: string[]\n /** Fail-closed `staff.timesheets.rates.view` decision \u2014 never re-derive it. */\n canSeeMoney: boolean\n}\n\nexport function extractReportIdFromUrl(url: string | undefined, segment: string): string | null {\n if (!url) return null\n try {\n const pathname = new URL(url).pathname\n const match = pathname.match(new RegExp(`/reports/([^/]+)/${segment}`))\n return match?.[1] ?? null\n } catch {\n return null\n }\n}\n\nexport async function resolveReportRequestContext(\n req: Request,\n options: { segment: string },\n): Promise<ReportRequestContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth) {\n throw new CrudHttpError(401, { error: translate('staff.errors.unauthorized', 'Unauthorized') })\n }\n\n const organizationScope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const tenantId = organizationScope?.tenantId ?? auth.tenantId ?? null\n const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null\n if (!tenantId || !organizationId) {\n throw new CrudHttpError(400, {\n error: translate('staff.errors.missingScope', 'Missing tenant or organization scope.'),\n })\n }\n\n const reportId = extractReportIdFromUrl(req.url, options.segment)\n if (!reportId) {\n throw new CrudHttpError(400, {\n error: translate('staff.time_tracking.reports.errors.idRequired', 'Report id is required.'),\n })\n }\n\n // One lookup, through the module's single RBAC authority, answering both\n // questions the four routes ask: may this caller see money, and what is the\n // grant list the plumbing wants. Decided here, once, so no route re-derives it\n // and none can pick the other failure direction.\n //\n // `resolveFeatureAccess` fails closed on every path \u2014 an unresolvable service,\n // a service that cannot answer, a call that throws \u2014 so an RBAC outage hides\n // rates and costs instead of handing them to a plain report viewer.\n const ratesAccess = await resolveFeatureAccess(container, auth.sub ?? null, [RATES_FEATURE], {\n tenantId,\n organizationId,\n })\n\n return {\n container,\n auth,\n organizationScope,\n tenantId,\n organizationId,\n reportId,\n translate,\n grantedFeatures: ratesAccess.grantedFeatures,\n canSeeMoney: ratesAccess.allowed,\n }\n}\n"],
5
+ "mappings": "AAUA,SAAS,qBAAqB;AAC9B,SAAS,4BAA4B;AACrC,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AACnD,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAS3B,MAAM,iBAAiB;AAgCvB,SAAS,uBAAuB,KAAyB,SAAgC;AAC9F,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,UAAM,WAAW,IAAI,IAAI,GAAG,EAAE;AAC9B,UAAM,QAAQ,SAAS,MAAM,IAAI,OAAO,oBAAoB,OAAO,EAAE,CAAC;AACtE,WAAO,QAAQ,CAAC,KAAK;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,4BACpB,KACA,SAC+B;AAC/B,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,QAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,6BAA6B,cAAc,EAAE,CAAC;AAAA,EAChG;AAEA,QAAM,oBAAoB,MAAM,mCAAmC,EAAE,WAAW,MAAM,SAAS,IAAI,CAAC;AACpG,QAAM,WAAW,mBAAmB,YAAY,KAAK,YAAY;AACjE,QAAM,iBAAiB,mBAAmB,cAAc,KAAK,SAAS;AACtE,MAAI,CAAC,YAAY,CAAC,gBAAgB;AAChC,UAAM,IAAI,cAAc,KAAK;AAAA,MAC3B,OAAO,UAAU,6BAA6B,uCAAuC;AAAA,IACvF,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,uBAAuB,IAAI,KAAK,QAAQ,OAAO;AAChE,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,cAAc,KAAK;AAAA,MAC3B,OAAO,UAAU,iDAAiD,wBAAwB;AAAA,IAC5F,CAAC;AAAA,EACH;AAUA,QAAM,cAAc,MAAM,qBAAqB,WAAW,KAAK,OAAO,MAAM,CAAC,aAAa,GAAG;AAAA,IAC3F;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB,YAAY;AAAA,IAC7B,aAAa,YAAY;AAAA,EAC3B;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,164 @@
1
+ import { NextResponse } from "next/server";
2
+ import { resolveFeatureAccess } from "../../../../lib/time-tracking/featureAccess.js";
3
+ import { z } from "zod";
4
+ import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
+ import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
6
+ import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
7
+ import { CrudHttpError, forbidden, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
8
+ import { runRouteMutationGuards } from "@open-mercato/shared/lib/crud/route-mutation-guard";
9
+ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
10
+ import { createLogger } from "@open-mercato/shared/lib/logger";
11
+ import { emitStaffEvent } from "../../../../events.js";
12
+ import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
13
+ import { STAFF_TIME_TRACKING_RESOURCE_KINDS } from "../../../guards.js";
14
+ import { runTimesheetInterceptors } from "../../_shared/withTimesheetInterceptors.js";
15
+ import {
16
+ STAFF_TIME_REAPPLY_ROUNDING_JOB_TYPE,
17
+ STAFF_TIME_REAPPLY_ROUNDING_QUEUE,
18
+ countReapplyRoundingCandidates,
19
+ getStaffQueue
20
+ } from "../../../../lib/time-tracking/reapplyRounding.js";
21
+ const logger = createLogger("staff").child({ component: "api/timesheets/settings/reapply-rounding" });
22
+ const MANAGE_FEATURE = "staff.timesheets.settings.manage";
23
+ const RESOURCE_KIND = STAFF_TIME_TRACKING_RESOURCE_KINDS.settings;
24
+ const RESOURCE_ID = "time_tracking";
25
+ const metadata = {
26
+ POST: { requireAuth: true, requireFeatures: [MANAGE_FEATURE] }
27
+ };
28
+ const responseSchema = z.object({
29
+ ok: z.boolean(),
30
+ progressJobId: z.string().uuid().nullable(),
31
+ /** Entries eligible for restatement — locked ones are not among them. */
32
+ candidateCount: z.number().int()
33
+ });
34
+ async function POST(req) {
35
+ try {
36
+ const container = await createRequestContainer();
37
+ const auth = await getAuthFromRequest(req);
38
+ const { translate } = await resolveTranslations();
39
+ if (!auth) {
40
+ throw new CrudHttpError(401, { error: translate("staff.errors.unauthorized", "Unauthorized") });
41
+ }
42
+ const organizationScope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
43
+ const tenantId = organizationScope?.tenantId ?? auth.tenantId ?? null;
44
+ if (!tenantId) {
45
+ throw new CrudHttpError(400, {
46
+ error: translate("staff.errors.missingScope", "Missing tenant or organization scope.")
47
+ });
48
+ }
49
+ const actorId = typeof auth.sub === "string" && auth.sub.trim().length > 0 ? auth.sub : "system";
50
+ const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null;
51
+ const access = await resolveFeatureAccess(container, actorId, [MANAGE_FEATURE], { tenantId, organizationId });
52
+ if (!access.allowed) {
53
+ throw forbidden(translate("staff.errors.forbidden", "Forbidden"));
54
+ }
55
+ const grantedFeatures = access.grantedFeatures;
56
+ const interceptors = await runTimesheetInterceptors({
57
+ request: req,
58
+ method: "POST",
59
+ scope: {
60
+ container,
61
+ userId: actorId,
62
+ tenantId,
63
+ organizationId,
64
+ userFeatures: grantedFeatures,
65
+ tenantGlobal: true
66
+ },
67
+ body: await readJsonSafe(req, {})
68
+ });
69
+ if (!interceptors.ok) return interceptors.response;
70
+ const { session } = interceptors;
71
+ const guardResult = await runRouteMutationGuards({
72
+ container,
73
+ req,
74
+ auth: {
75
+ userId: actorId,
76
+ tenantId,
77
+ organizationId,
78
+ userFeatures: grantedFeatures
79
+ },
80
+ input: {
81
+ resourceKind: RESOURCE_KIND,
82
+ resourceId: RESOURCE_ID,
83
+ operation: "update",
84
+ mutationPayload: { action: "reapply-rounding" }
85
+ }
86
+ });
87
+ if (!guardResult.ok) return guardResult.response;
88
+ const scope = {
89
+ tenantId,
90
+ // `filterIds === null` means the caller may act across every organization of
91
+ // the tenant, which is what a tenant-global rule is about; anything narrower
92
+ // restates only what the caller can already see.
93
+ organizationIds: organizationScope?.filterIds ?? (organizationId ? [organizationId] : null),
94
+ userId: actorId
95
+ };
96
+ const em = container.resolve("em");
97
+ const candidateCount = await countReapplyRoundingCandidates(em.fork(), scope);
98
+ if (candidateCount === 0) {
99
+ await guardResult.runAfterSuccess();
100
+ return session.respond(200, responseSchema.parse({ ok: true, progressJobId: null, candidateCount: 0 }));
101
+ }
102
+ const progressService = container.resolve("progressService");
103
+ const progressJob = await progressService.createJob(
104
+ {
105
+ jobType: STAFF_TIME_REAPPLY_ROUNDING_JOB_TYPE,
106
+ name: translate("staff.time_tracking.settings.retro.jobName", "Reapply rounding to existing entries"),
107
+ description: translate(
108
+ "staff.time_tracking.settings.retro.jobDescription",
109
+ "Recomputing rounded time on existing entries. Locked entries are not changed."
110
+ ),
111
+ totalCount: candidateCount,
112
+ cancellable: true,
113
+ meta: { source: "staff.timesheets.settings.reapply-rounding" }
114
+ },
115
+ { tenantId, organizationId, userId: actorId }
116
+ );
117
+ const queue = getStaffQueue(STAFF_TIME_REAPPLY_ROUNDING_QUEUE);
118
+ await queue.enqueue({ progressJobId: progressJob.id, scope });
119
+ await guardResult.runAfterSuccess();
120
+ void emitStaffEvent("staff.timesheets.time_tracking.rounding_reapplied", {
121
+ tenantId,
122
+ organizationId,
123
+ progressJobId: progressJob.id,
124
+ candidateCount
125
+ }, { persistent: true }).catch((err) => {
126
+ logger.error("staff.timesheets emit time_tracking.rounding_reapplied failed", { err });
127
+ });
128
+ return session.respond(202, responseSchema.parse({ ok: true, progressJobId: progressJob.id, candidateCount }));
129
+ } catch (err) {
130
+ if (isCrudHttpError(err)) {
131
+ return NextResponse.json(err.body, { status: err.status });
132
+ }
133
+ logger.error("staff.timesheets.settings.reapply-rounding failed", { err });
134
+ const { translate } = await resolveTranslations();
135
+ return NextResponse.json(
136
+ { error: translate("staff.errors.internal", "Internal server error") },
137
+ { status: 500 }
138
+ );
139
+ }
140
+ }
141
+ const openApi = {
142
+ tag: "Staff",
143
+ summary: "Reapply the rounding rule to existing entries",
144
+ methods: {
145
+ POST: {
146
+ summary: "Queue a retroactive rounding job",
147
+ description: "Enqueues a `ProgressJob` that recomputes `rounded_minutes` on existing time entries under the tenant\u2019s current rounding rule. Entries locked into a closed report are excluded \u2014 a billed amount is never restated. Returns `202` with `progressJobId`, or `200` with a null job id when there is nothing to restate.",
148
+ responses: [
149
+ { status: 200, description: "Nothing to restate", schema: responseSchema },
150
+ { status: 202, description: "Job queued", schema: responseSchema },
151
+ { status: 400, description: "Missing scope", schema: z.object({ error: z.string() }) },
152
+ { status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) },
153
+ { status: 403, description: "Missing staff.timesheets.settings.manage" },
154
+ { status: 500, description: "Queueing failure", schema: z.object({ error: z.string() }) }
155
+ ]
156
+ }
157
+ }
158
+ };
159
+ export {
160
+ POST,
161
+ metadata,
162
+ openApi
163
+ };
164
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts"],
4
+ "sourcesContent": ["/**\n * `POST /api/staff/timesheets/settings/reapply-rounding` \u2014 screen 16 note 3 (T7.3).\n *\n * The mockup draws retroactive rounding as a switch. It is implemented as an\n * **action**, because the two are not the same promise: a switch that rewrites\n * `rounded_minutes` across a tenant's history when the settings form is saved\n * changes invoiced amounts as a side effect of an unrelated save. This endpoint\n * makes it something a person does, once, on purpose, with a progress bar and a\n * final count.\n *\n * It enqueues; it does not do the work. Restating a tenant's entries is exactly the\n * long-running job the progress module exists for, so the response is a `202` with\n * a `progressJobId` that the top bar picks up on its own.\n *\n * Locked entries are never touched \u2014 the candidate query excludes them and the\n * command excludes them again, independently.\n */\n\nimport { NextResponse } from 'next/server'\nimport { resolveFeatureAccess } from '../../../../lib/time-tracking/featureAccess'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { CrudHttpError, forbidden, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { runRouteMutationGuards } from '@open-mercato/shared/lib/crud/route-mutation-guard'\nimport { authorizeFeatures } from '@open-mercato/shared/security/featurePolicy'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { emitStaffEvent } from '../../../../events'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { ProgressService } from '../../../../../progress/lib/progressService'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { STAFF_TIME_TRACKING_RESOURCE_KINDS } from '../../../guards'\nimport { runTimesheetInterceptors } from '../../_shared/withTimesheetInterceptors'\nimport {\n STAFF_TIME_REAPPLY_ROUNDING_JOB_TYPE,\n STAFF_TIME_REAPPLY_ROUNDING_QUEUE,\n countReapplyRoundingCandidates,\n getStaffQueue,\n type ReapplyRoundingScope,\n} from '../../../../lib/time-tracking/reapplyRounding'\n\nconst logger = createLogger('staff').child({ component: 'api/timesheets/settings/reapply-rounding' })\n\nconst MANAGE_FEATURE = 'staff.timesheets.settings.manage'\nconst RESOURCE_KIND = STAFF_TIME_TRACKING_RESOURCE_KINDS.settings\nconst RESOURCE_ID = 'time_tracking'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: [MANAGE_FEATURE] },\n}\n\nconst responseSchema = z.object({\n ok: z.boolean(),\n progressJobId: z.string().uuid().nullable(),\n /** Entries eligible for restatement \u2014 locked ones are not among them. */\n candidateCount: z.number().int(),\n})\n\nexport async function POST(req: Request) {\n try {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n if (!auth) {\n throw new CrudHttpError(401, { error: translate('staff.errors.unauthorized', 'Unauthorized') })\n }\n\n const organizationScope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const tenantId = organizationScope?.tenantId ?? auth.tenantId ?? null\n if (!tenantId) {\n throw new CrudHttpError(400, {\n error: translate('staff.errors.missingScope', 'Missing tenant or organization scope.'),\n })\n }\n\n const actorId = typeof auth.sub === 'string' && auth.sub.trim().length > 0 ? auth.sub : 'system'\n const organizationId = organizationScope?.selectedId ?? auth.orgId ?? null\n\n // One lookup through the module's single RBAC authority: the decision is\n // checked unconditionally and fails closed, and the grant list the plumbing\n // takes comes from the same answer instead of a second, nullable read.\n const access = await resolveFeatureAccess(container, actorId, [MANAGE_FEATURE], { tenantId, organizationId })\n if (!access.allowed) {\n throw forbidden(translate('staff.errors.forbidden', 'Forbidden'))\n }\n const grantedFeatures = access.grantedFeatures\n\n const interceptors = await runTimesheetInterceptors({\n request: req,\n method: 'POST',\n scope: {\n container,\n userId: actorId,\n tenantId,\n organizationId,\n userFeatures: grantedFeatures,\n tenantGlobal: true,\n },\n body: await readJsonSafe<Record<string, unknown>>(req, {}),\n })\n if (!interceptors.ok) return interceptors.response\n const { session } = interceptors\n\n const guardResult = await runRouteMutationGuards({\n container,\n req,\n auth: {\n userId: actorId,\n tenantId,\n organizationId,\n userFeatures: grantedFeatures,\n },\n input: {\n resourceKind: RESOURCE_KIND,\n resourceId: RESOURCE_ID,\n operation: 'update',\n mutationPayload: { action: 'reapply-rounding' },\n },\n })\n if (!guardResult.ok) return guardResult.response\n\n const scope: ReapplyRoundingScope = {\n tenantId,\n // `filterIds === null` means the caller may act across every organization of\n // the tenant, which is what a tenant-global rule is about; anything narrower\n // restates only what the caller can already see.\n organizationIds: organizationScope?.filterIds ?? (organizationId ? [organizationId] : null),\n userId: actorId,\n }\n\n const em = container.resolve('em') as EntityManager\n const candidateCount = await countReapplyRoundingCandidates(em.fork(), scope)\n if (candidateCount === 0) {\n // Nothing to restate: no job, no progress bar, no queue traffic. The caller\n // gets an honest zero rather than a job that completes instantly.\n await guardResult.runAfterSuccess()\n return session.respond(200, responseSchema.parse({ ok: true, progressJobId: null, candidateCount: 0 }))\n }\n\n const progressService = container.resolve('progressService') as ProgressService\n const progressJob = await progressService.createJob(\n {\n jobType: STAFF_TIME_REAPPLY_ROUNDING_JOB_TYPE,\n name: translate('staff.time_tracking.settings.retro.jobName', 'Reapply rounding to existing entries'),\n description: translate(\n 'staff.time_tracking.settings.retro.jobDescription',\n 'Recomputing rounded time on existing entries. Locked entries are not changed.',\n ),\n totalCount: candidateCount,\n cancellable: true,\n meta: { source: 'staff.timesheets.settings.reapply-rounding' },\n },\n { tenantId, organizationId, userId: actorId },\n )\n\n const queue = getStaffQueue(STAFF_TIME_REAPPLY_ROUNDING_QUEUE)\n await queue.enqueue({ progressJobId: progressJob.id, scope })\n\n await guardResult.runAfterSuccess()\n\n void emitStaffEvent('staff.timesheets.time_tracking.rounding_reapplied', {\n tenantId,\n organizationId,\n progressJobId: progressJob.id,\n candidateCount,\n }, { persistent: true }).catch((err) => {\n logger.error('staff.timesheets emit time_tracking.rounding_reapplied failed', { err })\n })\n\n return session.respond(202, responseSchema.parse({ ok: true, progressJobId: progressJob.id, candidateCount }))\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n logger.error('staff.timesheets.settings.reapply-rounding failed', { err })\n const { translate } = await resolveTranslations()\n return NextResponse.json(\n { error: translate('staff.errors.internal', 'Internal server error') },\n { status: 500 },\n )\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Staff',\n summary: 'Reapply the rounding rule to existing entries',\n methods: {\n POST: {\n summary: 'Queue a retroactive rounding job',\n description:\n 'Enqueues a `ProgressJob` that recomputes `rounded_minutes` on existing time entries under the tenant\u2019s current rounding rule. Entries locked into a closed report are excluded \u2014 a billed amount is never restated. Returns `202` with `progressJobId`, or `200` with a null job id when there is nothing to restate.',\n responses: [\n { status: 200, description: 'Nothing to restate', schema: responseSchema },\n { status: 202, description: 'Job queued', schema: responseSchema },\n { status: 400, description: 'Missing scope', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Missing staff.timesheets.settings.manage' },\n { status: 500, description: 'Queueing failure', schema: z.object({ error: z.string() }) },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }