@open-mercato/core 0.7.1-develop.7178.1.ab93fbaf4e → 0.7.1-develop.7179.1.e8c03264b6

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 (792) 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/staff/acl.js +9 -1
  41. package/dist/modules/staff/acl.js.map +2 -2
  42. package/dist/modules/staff/ai-agents.js +142 -0
  43. package/dist/modules/staff/ai-agents.js.map +7 -0
  44. package/dist/modules/staff/ai-tools/time-tracking-pack.js +348 -0
  45. package/dist/modules/staff/ai-tools/time-tracking-pack.js.map +7 -0
  46. package/dist/modules/staff/ai-tools/types.js +54 -0
  47. package/dist/modules/staff/ai-tools/types.js.map +7 -0
  48. package/dist/modules/staff/ai-tools.js +8 -0
  49. package/dist/modules/staff/ai-tools.js.map +7 -0
  50. package/dist/modules/staff/analytics.js +84 -1
  51. package/dist/modules/staff/analytics.js.map +2 -2
  52. package/dist/modules/staff/api/guards.js +37 -3
  53. package/dist/modules/staff/api/guards.js.map +2 -2
  54. package/dist/modules/staff/api/leave-requests/accept/route.js +1 -3
  55. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  56. package/dist/modules/staff/api/leave-requests/reject/route.js +1 -3
  57. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  58. package/dist/modules/staff/api/portal/time-reports/[id]/route.js +131 -0
  59. package/dist/modules/staff/api/portal/time-reports/[id]/route.js.map +7 -0
  60. package/dist/modules/staff/api/portal/time-reports/route.js +179 -0
  61. package/dist/modules/staff/api/portal/time-reports/route.js.map +7 -0
  62. package/dist/modules/staff/api/team-members/self/route.js +1 -3
  63. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  64. package/dist/modules/staff/api/team-members/tags/assign/route.js +1 -3
  65. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  66. package/dist/modules/staff/api/team-members/tags/unassign/route.js +1 -3
  67. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  68. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js +174 -0
  69. package/dist/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.js.map +7 -0
  70. package/dist/modules/staff/api/timesheets/access-requests/route.js +226 -0
  71. package/dist/modules/staff/api/timesheets/access-requests/route.js.map +7 -0
  72. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +15 -8
  73. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
  74. package/dist/modules/staff/api/timesheets/my-projects/route.js +13 -1
  75. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
  76. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js +42 -0
  77. package/dist/modules/staff/api/timesheets/my-work/myWorkAggregate.js.map +7 -0
  78. package/dist/modules/staff/api/timesheets/my-work/route.js +383 -0
  79. package/dist/modules/staff/api/timesheets/my-work/route.js.map +7 -0
  80. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +14 -2
  81. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
  82. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js +168 -0
  83. package/dist/modules/staff/api/timesheets/reports/[id]/close/route.js.map +7 -0
  84. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js +246 -0
  85. package/dist/modules/staff/api/timesheets/reports/[id]/export/route.js.map +7 -0
  86. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js +183 -0
  87. package/dist/modules/staff/api/timesheets/reports/[id]/sheet/route.js.map +7 -0
  88. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js +164 -0
  89. package/dist/modules/staff/api/timesheets/reports/[id]/unlock/route.js.map +7 -0
  90. package/dist/modules/staff/api/timesheets/reports/preview/route.js +360 -0
  91. package/dist/modules/staff/api/timesheets/reports/preview/route.js.map +7 -0
  92. package/dist/modules/staff/api/timesheets/reports/route.js +316 -0
  93. package/dist/modules/staff/api/timesheets/reports/route.js.map +7 -0
  94. package/dist/modules/staff/api/timesheets/reports/shared.js +63 -0
  95. package/dist/modules/staff/api/timesheets/reports/shared.js.map +7 -0
  96. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js +164 -0
  97. package/dist/modules/staff/api/timesheets/settings/reapply-rounding/route.js.map +7 -0
  98. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js +168 -0
  99. package/dist/modules/staff/api/timesheets/settings/rounding-impact/route.js.map +7 -0
  100. package/dist/modules/staff/api/timesheets/settings/route.js +199 -0
  101. package/dist/modules/staff/api/timesheets/settings/route.js.map +7 -0
  102. package/dist/modules/staff/api/timesheets/tags/access.js +76 -0
  103. package/dist/modules/staff/api/timesheets/tags/access.js.map +7 -0
  104. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js +235 -0
  105. package/dist/modules/staff/api/timesheets/tags/entry-assignments/route.js.map +7 -0
  106. package/dist/modules/staff/api/timesheets/tags/route.js +160 -0
  107. package/dist/modules/staff/api/timesheets/tags/route.js.map +7 -0
  108. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js +233 -0
  109. package/dist/modules/staff/api/timesheets/tags/task-assignments/route.js.map +7 -0
  110. package/dist/modules/staff/api/timesheets/task-statuses/route.js +188 -0
  111. package/dist/modules/staff/api/timesheets/task-statuses/route.js.map +7 -0
  112. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +399 -0
  113. package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js +210 -0
  115. package/dist/modules/staff/api/timesheets/tasks/[id]/status/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/tasks/route.js +333 -0
  117. package/dist/modules/staff/api/timesheets/tasks/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js +228 -0
  119. package/dist/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +29 -10
  121. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +2 -2
  122. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +31 -18
  123. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
  124. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +21 -7
  125. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
  126. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +27 -7
  127. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
  128. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +215 -32
  129. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
  130. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js +378 -0
  131. package/dist/modules/staff/api/timesheets/time-entries/copy-day/route.js.map +7 -0
  132. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js +340 -0
  133. package/dist/modules/staff/api/timesheets/time-entries/overlaps/route.js.map +7 -0
  134. package/dist/modules/staff/api/timesheets/time-entries/route.js +238 -26
  135. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +2 -2
  136. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +23 -8
  137. package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
  138. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js +209 -0
  139. package/dist/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.js.map +7 -0
  140. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +59 -2
  141. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
  142. package/dist/modules/staff/api/timesheets/time-projects/route.js +264 -22
  143. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
  144. package/dist/modules/staff/backend/staff/time-tracking/board/page.js +110 -0
  145. package/dist/modules/staff/backend/staff/time-tracking/board/page.js.map +7 -0
  146. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js +18 -0
  147. package/dist/modules/staff/backend/staff/time-tracking/board/page.meta.js.map +7 -0
  148. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js +981 -0
  149. package/dist/modules/staff/backend/staff/time-tracking/entries/page.js.map +7 -0
  150. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js +18 -0
  151. package/dist/modules/staff/backend/staff/time-tracking/entries/page.meta.js.map +7 -0
  152. package/dist/modules/staff/backend/staff/time-tracking/page.js +583 -0
  153. package/dist/modules/staff/backend/staff/time-tracking/page.js.map +7 -0
  154. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js +15 -0
  155. package/dist/modules/staff/backend/staff/time-tracking/page.meta.js.map +7 -0
  156. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js +65 -0
  157. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.js.map +7 -0
  158. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js +16 -0
  159. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.js.map +7 -0
  160. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +229 -0
  161. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +7 -0
  162. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js +16 -0
  163. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.js.map +7 -0
  164. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +1014 -0
  165. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +7 -0
  166. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js +16 -0
  167. package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.js.map +7 -0
  168. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js +97 -0
  169. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.js.map +7 -0
  170. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js +16 -0
  171. package/dist/modules/staff/backend/staff/time-tracking/projects/create/page.meta.js.map +7 -0
  172. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js +1040 -0
  173. package/dist/modules/staff/backend/staff/time-tracking/projects/page.js.map +7 -0
  174. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js +19 -0
  175. package/dist/modules/staff/backend/staff/time-tracking/projects/page.meta.js.map +7 -0
  176. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +353 -0
  177. package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +7 -0
  178. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js +457 -0
  179. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.js.map +7 -0
  180. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js +16 -0
  181. package/dist/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.js.map +7 -0
  182. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js +697 -0
  183. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.js.map +7 -0
  184. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js +16 -0
  185. package/dist/modules/staff/backend/staff/time-tracking/reports/create/page.meta.js.map +7 -0
  186. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js +174 -0
  187. package/dist/modules/staff/backend/staff/time-tracking/reports/page.js.map +7 -0
  188. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js +18 -0
  189. package/dist/modules/staff/backend/staff/time-tracking/reports/page.meta.js.map +7 -0
  190. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +546 -0
  191. package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +7 -0
  192. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js +18 -0
  193. package/dist/modules/staff/backend/staff/time-tracking/settings/page.meta.js.map +7 -0
  194. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js +710 -0
  195. package/dist/modules/staff/backend/staff/time-tracking/timesheet/GridView.js.map +7 -0
  196. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js +646 -0
  197. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.js.map +7 -0
  198. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js +18 -0
  199. package/dist/modules/staff/backend/staff/time-tracking/timesheet/page.meta.js.map +7 -0
  200. package/dist/modules/staff/backend/staff/timesheets/page.js +4 -793
  201. package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
  202. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +2 -7
  203. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +2 -2
  204. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +5 -136
  205. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +2 -2
  206. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +1 -7
  207. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +2 -2
  208. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +5 -445
  209. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +3 -3
  210. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +1 -7
  211. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +2 -2
  212. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +4 -76
  213. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +2 -2
  214. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +1 -7
  215. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +2 -2
  216. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -613
  217. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  218. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +2 -17
  219. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +2 -2
  220. package/dist/modules/staff/ce.js +40 -0
  221. package/dist/modules/staff/ce.js.map +2 -2
  222. package/dist/modules/staff/cli.js +166 -1
  223. package/dist/modules/staff/cli.js.map +2 -2
  224. package/dist/modules/staff/commands/index.js +5 -0
  225. package/dist/modules/staff/commands/index.js.map +2 -2
  226. package/dist/modules/staff/commands/timesheets-entries.js +569 -21
  227. package/dist/modules/staff/commands/timesheets-entries.js.map +3 -3
  228. package/dist/modules/staff/commands/timesheets-projects.js +450 -7
  229. package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
  230. package/dist/modules/staff/commands/timesheets-reports.js +1036 -0
  231. package/dist/modules/staff/commands/timesheets-reports.js.map +7 -0
  232. package/dist/modules/staff/commands/timesheets-tags.js +1015 -0
  233. package/dist/modules/staff/commands/timesheets-tags.js.map +7 -0
  234. package/dist/modules/staff/commands/timesheets-task-comments.js +438 -0
  235. package/dist/modules/staff/commands/timesheets-task-comments.js.map +7 -0
  236. package/dist/modules/staff/commands/timesheets-task-statuses.js +723 -0
  237. package/dist/modules/staff/commands/timesheets-task-statuses.js.map +7 -0
  238. package/dist/modules/staff/commands/timesheets-tasks.js +834 -0
  239. package/dist/modules/staff/commands/timesheets-tasks.js.map +7 -0
  240. package/dist/modules/staff/data/enrichers.js +426 -12
  241. package/dist/modules/staff/data/enrichers.js.map +2 -2
  242. package/dist/modules/staff/data/entities.js +552 -3
  243. package/dist/modules/staff/data/entities.js.map +2 -2
  244. package/dist/modules/staff/data/extensions.js +41 -0
  245. package/dist/modules/staff/data/extensions.js.map +7 -0
  246. package/dist/modules/staff/data/validators.js +254 -9
  247. package/dist/modules/staff/data/validators.js.map +2 -2
  248. package/dist/modules/staff/di.js +42 -1
  249. package/dist/modules/staff/di.js.map +2 -2
  250. package/dist/modules/staff/events.js +84 -6
  251. package/dist/modules/staff/events.js.map +2 -2
  252. package/dist/modules/staff/events.payloads.js +158 -0
  253. package/dist/modules/staff/events.payloads.js.map +7 -0
  254. package/dist/modules/staff/extension-points.js +261 -0
  255. package/dist/modules/staff/extension-points.js.map +7 -0
  256. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js +138 -0
  257. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.js.map +7 -0
  258. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js +12 -0
  259. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.js.map +7 -0
  260. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js +133 -0
  261. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.js.map +7 -0
  262. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js +19 -0
  263. package/dist/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.js.map +7 -0
  264. package/dist/modules/staff/lib/crud.js +11 -1
  265. package/dist/modules/staff/lib/crud.js.map +2 -2
  266. package/dist/modules/staff/lib/time-tracking/access.js +92 -0
  267. package/dist/modules/staff/lib/time-tracking/access.js.map +7 -0
  268. package/dist/modules/staff/lib/time-tracking/billability.js +39 -0
  269. package/dist/modules/staff/lib/time-tracking/billability.js.map +7 -0
  270. package/dist/modules/staff/lib/time-tracking/capacity.js +68 -0
  271. package/dist/modules/staff/lib/time-tracking/capacity.js.map +7 -0
  272. package/dist/modules/staff/lib/time-tracking/componentContracts.js +15 -0
  273. package/dist/modules/staff/lib/time-tracking/componentContracts.js.map +7 -0
  274. package/dist/modules/staff/lib/time-tracking/cost.js +82 -0
  275. package/dist/modules/staff/lib/time-tracking/cost.js.map +7 -0
  276. package/dist/modules/staff/lib/time-tracking/duration.js +55 -0
  277. package/dist/modules/staff/lib/time-tracking/duration.js.map +7 -0
  278. package/dist/modules/staff/lib/time-tracking/featureAccess.js +41 -0
  279. package/dist/modules/staff/lib/time-tracking/featureAccess.js.map +7 -0
  280. package/dist/modules/staff/lib/time-tracking/interval.js +72 -0
  281. package/dist/modules/staff/lib/time-tracking/interval.js.map +7 -0
  282. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js +88 -0
  283. package/dist/modules/staff/lib/time-tracking/migrateProjectCodes.js.map +7 -0
  284. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js +10 -0
  285. package/dist/modules/staff/lib/time-tracking/moneyVisibility.js.map +7 -0
  286. package/dist/modules/staff/lib/time-tracking/overlap.js +87 -0
  287. package/dist/modules/staff/lib/time-tracking/overlap.js.map +7 -0
  288. package/dist/modules/staff/lib/time-tracking/portalRecipients.js +27 -0
  289. package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +7 -0
  290. package/dist/modules/staff/lib/time-tracking/portalReports.js +16 -0
  291. package/dist/modules/staff/lib/time-tracking/portalReports.js.map +7 -0
  292. package/dist/modules/staff/lib/time-tracking/projectCode.js +135 -0
  293. package/dist/modules/staff/lib/time-tracking/projectCode.js.map +7 -0
  294. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js +187 -0
  295. package/dist/modules/staff/lib/time-tracking/reapplyRounding.js.map +7 -0
  296. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js +80 -0
  297. package/dist/modules/staff/lib/time-tracking/recalculationRunner.js.map +7 -0
  298. package/dist/modules/staff/lib/time-tracking/recalculations.js +56 -0
  299. package/dist/modules/staff/lib/time-tracking/recalculations.js.map +7 -0
  300. package/dist/modules/staff/lib/time-tracking/registries/invoke.js +63 -0
  301. package/dist/modules/staff/lib/time-tracking/registries/invoke.js.map +7 -0
  302. package/dist/modules/staff/lib/time-tracking/registries/registry.js +62 -0
  303. package/dist/modules/staff/lib/time-tracking/registries/registry.js.map +7 -0
  304. package/dist/modules/staff/lib/time-tracking/registries/scope.js +21 -0
  305. package/dist/modules/staff/lib/time-tracking/registries/scope.js.map +7 -0
  306. package/dist/modules/staff/lib/time-tracking/rollup.js +34 -0
  307. package/dist/modules/staff/lib/time-tracking/rollup.js.map +7 -0
  308. package/dist/modules/staff/lib/time-tracking/rounding.js +66 -0
  309. package/dist/modules/staff/lib/time-tracking/rounding.js.map +7 -0
  310. package/dist/modules/staff/lib/time-tracking/roundingImpact.js +39 -0
  311. package/dist/modules/staff/lib/time-tracking/roundingImpact.js.map +7 -0
  312. package/dist/modules/staff/lib/time-tracking/settingKeys.js +214 -0
  313. package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +7 -0
  314. package/dist/modules/staff/lib/time-tracking/settings.js +87 -0
  315. package/dist/modules/staff/lib/time-tracking/settings.js.map +7 -0
  316. package/dist/modules/staff/lib/time-tracking/sqlInClause.js +9 -0
  317. package/dist/modules/staff/lib/time-tracking/sqlInClause.js.map +7 -0
  318. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js +48 -0
  319. package/dist/modules/staff/lib/time-tracking/timeEntrySources.js.map +7 -0
  320. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +283 -0
  321. package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +7 -0
  322. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js +324 -0
  323. package/dist/modules/staff/lib/time-tracking-ui/CustomerPicker.js.map +7 -0
  324. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js +121 -0
  325. package/dist/modules/staff/lib/time-tracking-ui/DurationInput.js.map +7 -0
  326. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js +188 -0
  327. package/dist/modules/staff/lib/time-tracking-ui/EntryDetailsFields.js.map +7 -0
  328. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js +89 -0
  329. package/dist/modules/staff/lib/time-tracking-ui/EntryFilterBar.js.map +7 -0
  330. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +855 -0
  331. package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +7 -0
  332. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +360 -0
  333. package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +7 -0
  334. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js +259 -0
  335. package/dist/modules/staff/lib/time-tracking-ui/KanbanColumn.js.map +7 -0
  336. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js +238 -0
  337. package/dist/modules/staff/lib/time-tracking-ui/NewTaskDialog.js.map +7 -0
  338. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js +130 -0
  339. package/dist/modules/staff/lib/time-tracking-ui/NoProjectAccess.js.map +7 -0
  340. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js +98 -0
  341. package/dist/modules/staff/lib/time-tracking-ui/PeriodSelector.js.map +7 -0
  342. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js +27 -0
  343. package/dist/modules/staff/lib/time-tracking-ui/PhasePlaceholder.js.map +7 -0
  344. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js +166 -0
  345. package/dist/modules/staff/lib/time-tracking-ui/ProjectCodeField.js.map +7 -0
  346. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js +295 -0
  347. package/dist/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.js.map +7 -0
  348. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +212 -0
  349. package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +7 -0
  350. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js +729 -0
  351. package/dist/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.js.map +7 -0
  352. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js +217 -0
  353. package/dist/modules/staff/lib/time-tracking-ui/ReportSheet.js.map +7 -0
  354. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js +158 -0
  355. package/dist/modules/staff/lib/time-tracking-ui/TagPicker.js.map +7 -0
  356. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +224 -0
  357. package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +7 -0
  358. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +93 -0
  359. package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +7 -0
  360. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +1196 -0
  361. package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +7 -0
  362. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js +176 -0
  363. package/dist/modules/staff/lib/time-tracking-ui/TaskListView.js.map +7 -0
  364. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js +307 -0
  365. package/dist/modules/staff/lib/time-tracking-ui/TaskPicker.js.map +7 -0
  366. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js +284 -0
  367. package/dist/modules/staff/lib/time-tracking-ui/TaskQuickLog.js.map +7 -0
  368. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js +73 -0
  369. package/dist/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.js.map +7 -0
  370. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js +1499 -0
  371. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDialog.js.map +7 -0
  372. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js +95 -0
  373. package/dist/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.js.map +7 -0
  374. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js +188 -0
  375. package/dist/modules/staff/lib/time-tracking-ui/TimesheetCalendar.js.map +7 -0
  376. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js +61 -0
  377. package/dist/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.js.map +7 -0
  378. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js +45 -0
  379. package/dist/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.js.map +7 -0
  380. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +176 -0
  381. package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +7 -0
  382. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +82 -0
  383. package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +7 -0
  384. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js +5 -0
  385. package/dist/modules/staff/lib/time-tracking-ui/boardSummary.js.map +7 -0
  386. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +152 -0
  387. package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +7 -0
  388. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js +92 -0
  389. package/dist/modules/staff/lib/time-tracking-ui/projectTeamAssignment.js.map +7 -0
  390. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +111 -0
  391. package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +7 -0
  392. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js +243 -0
  393. package/dist/modules/staff/lib/time-tracking-ui/timeEntryDialogState.js.map +7 -0
  394. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js +151 -0
  395. package/dist/modules/staff/lib/time-tracking-ui/timeEntryListData.js.map +7 -0
  396. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +105 -0
  397. package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +7 -0
  398. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js +132 -0
  399. package/dist/modules/staff/lib/time-tracking-ui/timesheetData.js.map +7 -0
  400. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js +205 -0
  401. package/dist/modules/staff/lib/time-tracking-ui/timesheetPeriod.js.map +7 -0
  402. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js +53 -0
  403. package/dist/modules/staff/lib/time-tracking-ui/timesheetTargets.js.map +7 -0
  404. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js +77 -0
  405. package/dist/modules/staff/lib/time-tracking-ui/useBoardFilters.js.map +7 -0
  406. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js +151 -0
  407. package/dist/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.js.map +7 -0
  408. package/dist/modules/staff/lib/timeTrackingSeeds.js +809 -0
  409. package/dist/modules/staff/lib/timeTrackingSeeds.js.map +7 -0
  410. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js +2 -3
  411. package/dist/modules/staff/lib/timesheets/timeEntryCacheInvalidation.js.map +2 -2
  412. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js +152 -0
  413. package/dist/modules/staff/lib/timesheets/timeEntryDecoration.js.map +7 -0
  414. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js +36 -0
  415. package/dist/modules/staff/lib/timesheets-projects/budgetBurn.js.map +7 -0
  416. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js +66 -0
  417. package/dist/modules/staff/lib/timesheets-projects/budgetThreshold.js.map +7 -0
  418. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js +78 -0
  419. package/dist/modules/staff/lib/timesheets-projects/budgetThresholdState.js.map +7 -0
  420. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js +81 -0
  421. package/dist/modules/staff/lib/timesheets-projects/computeProjectFinancials.js.map +7 -0
  422. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js +44 -0
  423. package/dist/modules/staff/lib/timesheets-projects/reportSelection.js.map +7 -0
  424. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js +169 -0
  425. package/dist/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.js.map +7 -0
  426. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js +22 -0
  427. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.js.map +7 -0
  428. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +51 -1
  429. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +2 -2
  430. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js +70 -0
  431. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.js.map +7 -0
  432. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js +63 -0
  433. package/dist/modules/staff/lib/timesheets-reports/buildReportSheet.js.map +7 -0
  434. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js +170 -0
  435. package/dist/modules/staff/lib/timesheets-reports/loadReportData.js.map +7 -0
  436. package/dist/modules/staff/lib/timesheets-reports/pdf.js +205 -0
  437. package/dist/modules/staff/lib/timesheets-reports/pdf.js.map +7 -0
  438. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js +68 -0
  439. package/dist/modules/staff/lib/timesheets-reports/reportApprovalPolicies.js.map +7 -0
  440. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js +135 -0
  441. package/dist/modules/staff/lib/timesheets-reports/reportConfigData.js.map +7 -0
  442. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js +48 -0
  443. package/dist/modules/staff/lib/timesheets-reports/reportConfigState.js.map +7 -0
  444. package/dist/modules/staff/lib/timesheets-reports/reportExport.js +262 -0
  445. package/dist/modules/staff/lib/timesheets-reports/reportExport.js.map +7 -0
  446. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js +34 -0
  447. package/dist/modules/staff/lib/timesheets-reports/reportExportFormats.js.map +7 -0
  448. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js +79 -0
  449. package/dist/modules/staff/lib/timesheets-reports/reportGroupings.js.map +7 -0
  450. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js +11 -0
  451. package/dist/modules/staff/lib/timesheets-reports/reportLabels.js.map +7 -0
  452. package/dist/modules/staff/lib/timesheets-reports/reportReference.js +83 -0
  453. package/dist/modules/staff/lib/timesheets-reports/reportReference.js.map +7 -0
  454. package/dist/modules/staff/lib/timesheets-reports/reportRows.js +42 -0
  455. package/dist/modules/staff/lib/timesheets-reports/reportRows.js.map +7 -0
  456. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js +107 -0
  457. package/dist/modules/staff/lib/timesheets-reports/reportSheetData.js.map +7 -0
  458. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js +289 -0
  459. package/dist/modules/staff/lib/timesheets-reports/reportTotals.js.map +7 -0
  460. package/dist/modules/staff/lib/timesheets-reports/xlsx.js +145 -0
  461. package/dist/modules/staff/lib/timesheets-reports/xlsx.js.map +7 -0
  462. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js +116 -0
  463. package/dist/modules/staff/lib/timesheets-tasks/computeTaskRollups.js.map +7 -0
  464. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js +50 -0
  465. package/dist/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.js.map +7 -0
  466. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js +27 -0
  467. package/dist/modules/staff/lib/timesheets-tasks/seedProjectStatuses.js.map +7 -0
  468. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js +65 -0
  469. package/dist/modules/staff/lib/timesheets-tasks/statusPositions.js.map +7 -0
  470. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js +31 -0
  471. package/dist/modules/staff/lib/timesheets-tasks/statusSlug.js.map +7 -0
  472. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js +31 -0
  473. package/dist/modules/staff/lib/timesheets-tasks/taskHierarchy.js.map +7 -0
  474. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js +17 -0
  475. package/dist/modules/staff/lib/timesheets-tasks/taskHoursTotals.js.map +7 -0
  476. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js +51 -0
  477. package/dist/modules/staff/lib/timesheets-tasks/taskReference.js.map +7 -0
  478. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +11 -4
  479. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +2 -2
  480. package/dist/modules/staff/lib/timesheets-ui/ListView.js +369 -111
  481. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +2 -2
  482. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +47 -2
  483. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +2 -2
  484. package/dist/modules/staff/migrations/Migration20260813073131_staff.js +79 -0
  485. package/dist/modules/staff/migrations/Migration20260813073131_staff.js.map +7 -0
  486. package/dist/modules/staff/migrations/Migration20260824143357_staff.js +15 -0
  487. package/dist/modules/staff/migrations/Migration20260824143357_staff.js.map +7 -0
  488. package/dist/modules/staff/notifications.client.js +16 -0
  489. package/dist/modules/staff/notifications.client.js.map +7 -0
  490. package/dist/modules/staff/notifications.handlers.js +80 -0
  491. package/dist/modules/staff/notifications.handlers.js.map +7 -0
  492. package/dist/modules/staff/notifications.js +168 -0
  493. package/dist/modules/staff/notifications.js.map +2 -2
  494. package/dist/modules/staff/search.js +159 -1
  495. package/dist/modules/staff/search.js.map +2 -2
  496. package/dist/modules/staff/setup.js +20 -1
  497. package/dist/modules/staff/setup.js.map +2 -2
  498. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js +68 -0
  499. package/dist/modules/staff/subscribers/time-project-access-requested-notification.js.map +7 -0
  500. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js +149 -0
  501. package/dist/modules/staff/subscribers/time-project-budget-threshold-notification.js.map +7 -0
  502. package/dist/modules/staff/subscribers/time-report-approved-notification.js +78 -0
  503. package/dist/modules/staff/subscribers/time-report-approved-notification.js.map +7 -0
  504. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js +78 -0
  505. package/dist/modules/staff/subscribers/time-report-portal-broadcast.js.map +7 -0
  506. package/dist/modules/staff/translations.js +4 -1
  507. package/dist/modules/staff/translations.js.map +2 -2
  508. package/dist/modules/staff/widgets/components.js +7 -0
  509. package/dist/modules/staff/widgets/components.js.map +7 -0
  510. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +5 -4
  511. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +2 -2
  512. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js +135 -0
  513. package/dist/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.js.map +7 -0
  514. package/dist/modules/staff/widgets/notifications/index.js +5 -0
  515. package/dist/modules/staff/widgets/notifications/index.js.map +7 -0
  516. package/dist/modules/staff/workers/timesheets-reapply-rounding.js +43 -0
  517. package/dist/modules/staff/workers/timesheets-reapply-rounding.js.map +7 -0
  518. package/generated/entities/staff_time_entry/index.ts +7 -0
  519. package/generated/entities/staff_time_entry_tag/index.ts +6 -0
  520. package/generated/entities/staff_time_project/index.ts +8 -0
  521. package/generated/entities/staff_time_report/index.ts +27 -0
  522. package/generated/entities/staff_time_report_entry/index.ts +12 -0
  523. package/generated/entities/staff_time_report_event/index.ts +9 -0
  524. package/generated/entities/staff_time_report_project/index.ts +6 -0
  525. package/generated/entities/staff_time_tag/index.ts +9 -0
  526. package/generated/entities/staff_time_task/index.ts +17 -0
  527. package/generated/entities/staff_time_task_comment/index.ts +9 -0
  528. package/generated/entities/staff_time_task_status/index.ts +13 -0
  529. package/generated/entities/staff_time_task_tag/index.ts +6 -0
  530. package/generated/entities.ids.generated.ts +11 -1
  531. package/generated/entity-fields-registry.ts +149 -0
  532. package/package.json +7 -7
  533. package/src/helpers/integration/timesheetFixtures.ts +31 -1
  534. package/src/modules/auth/README.md +1 -1
  535. package/src/modules/auth/cli.ts +35 -1
  536. package/src/modules/auth/i18n/de.json +7 -0
  537. package/src/modules/auth/i18n/en.json +7 -0
  538. package/src/modules/auth/i18n/es.json +7 -0
  539. package/src/modules/auth/i18n/ko.json +7 -0
  540. package/src/modules/auth/i18n/pl.json +7 -0
  541. package/src/modules/auth/lib/backendChrome.tsx +1 -0
  542. package/src/modules/customer_accounts/lib/customerRoleAcls.ts +79 -0
  543. package/src/modules/customer_accounts/setup.ts +1 -45
  544. package/src/modules/staff/AGENTS.md +769 -1
  545. package/src/modules/staff/acl.ts +9 -0
  546. package/src/modules/staff/ai-agents.ts +189 -0
  547. package/src/modules/staff/ai-tools/time-tracking-pack.ts +494 -0
  548. package/src/modules/staff/ai-tools/types.ts +82 -0
  549. package/src/modules/staff/ai-tools.ts +13 -0
  550. package/src/modules/staff/analytics.ts +113 -0
  551. package/src/modules/staff/api/guards.ts +85 -3
  552. package/src/modules/staff/api/leave-requests/accept/route.ts +0 -2
  553. package/src/modules/staff/api/leave-requests/reject/route.ts +0 -2
  554. package/src/modules/staff/api/portal/time-reports/[id]/route.ts +182 -0
  555. package/src/modules/staff/api/portal/time-reports/route.ts +270 -0
  556. package/src/modules/staff/api/team-members/self/route.ts +0 -2
  557. package/src/modules/staff/api/team-members/tags/assign/route.ts +0 -2
  558. package/src/modules/staff/api/team-members/tags/unassign/route.ts +0 -2
  559. package/src/modules/staff/api/timesheets/_shared/withTimesheetInterceptors.ts +292 -0
  560. package/src/modules/staff/api/timesheets/access-requests/route.ts +299 -0
  561. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +15 -7
  562. package/src/modules/staff/api/timesheets/my-projects/route.ts +14 -1
  563. package/src/modules/staff/api/timesheets/my-work/myWorkAggregate.ts +90 -0
  564. package/src/modules/staff/api/timesheets/my-work/route.ts +475 -0
  565. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +15 -2
  566. package/src/modules/staff/api/timesheets/reports/[id]/close/route.ts +203 -0
  567. package/src/modules/staff/api/timesheets/reports/[id]/export/route.ts +315 -0
  568. package/src/modules/staff/api/timesheets/reports/[id]/sheet/route.ts +220 -0
  569. package/src/modules/staff/api/timesheets/reports/[id]/unlock/route.ts +208 -0
  570. package/src/modules/staff/api/timesheets/reports/preview/route.ts +449 -0
  571. package/src/modules/staff/api/timesheets/reports/route.ts +386 -0
  572. package/src/modules/staff/api/timesheets/reports/shared.ts +121 -0
  573. package/src/modules/staff/api/timesheets/settings/reapply-rounding/route.ts +205 -0
  574. package/src/modules/staff/api/timesheets/settings/rounding-impact/route.ts +226 -0
  575. package/src/modules/staff/api/timesheets/settings/route.ts +242 -0
  576. package/src/modules/staff/api/timesheets/tags/access.ts +134 -0
  577. package/src/modules/staff/api/timesheets/tags/entry-assignments/route.ts +290 -0
  578. package/src/modules/staff/api/timesheets/tags/route.ts +177 -0
  579. package/src/modules/staff/api/timesheets/tags/task-assignments/route.ts +294 -0
  580. package/src/modules/staff/api/timesheets/task-statuses/route.ts +232 -0
  581. package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +532 -0
  582. package/src/modules/staff/api/timesheets/tasks/[id]/status/route.ts +271 -0
  583. package/src/modules/staff/api/timesheets/tasks/route.ts +443 -0
  584. package/src/modules/staff/api/timesheets/time-entries/[id]/duplicate/route.ts +306 -0
  585. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +32 -10
  586. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +32 -17
  587. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +27 -6
  588. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +36 -6
  589. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +331 -34
  590. package/src/modules/staff/api/timesheets/time-entries/copy-day/route.ts +533 -0
  591. package/src/modules/staff/api/timesheets/time-entries/overlaps/route.ts +457 -0
  592. package/src/modules/staff/api/timesheets/time-entries/route.ts +378 -24
  593. package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +31 -9
  594. package/src/modules/staff/api/timesheets/time-projects/[id]/change-currency/route.ts +246 -0
  595. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +62 -2
  596. package/src/modules/staff/api/timesheets/time-projects/route.ts +397 -22
  597. package/src/modules/staff/backend/staff/time-tracking/board/page.meta.ts +14 -0
  598. package/src/modules/staff/backend/staff/time-tracking/board/page.tsx +151 -0
  599. package/src/modules/staff/backend/staff/time-tracking/entries/page.meta.ts +14 -0
  600. package/src/modules/staff/backend/staff/time-tracking/entries/page.tsx +1229 -0
  601. package/src/modules/staff/backend/staff/time-tracking/page.meta.ts +11 -0
  602. package/src/modules/staff/backend/staff/time-tracking/page.tsx +823 -0
  603. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.meta.ts +12 -0
  604. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/board/page.tsx +81 -0
  605. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.meta.ts +12 -0
  606. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +275 -0
  607. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.meta.ts +12 -0
  608. package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +1420 -0
  609. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.meta.ts +12 -0
  610. package/src/modules/staff/backend/staff/time-tracking/projects/create/page.tsx +109 -0
  611. package/src/modules/staff/backend/staff/time-tracking/projects/page.meta.ts +15 -0
  612. package/src/modules/staff/backend/staff/time-tracking/projects/page.tsx +1254 -0
  613. package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +466 -0
  614. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.meta.ts +12 -0
  615. package/src/modules/staff/backend/staff/time-tracking/reports/[id]/page.tsx +632 -0
  616. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.meta.ts +12 -0
  617. package/src/modules/staff/backend/staff/time-tracking/reports/create/page.tsx +867 -0
  618. package/src/modules/staff/backend/staff/time-tracking/reports/page.meta.ts +14 -0
  619. package/src/modules/staff/backend/staff/time-tracking/reports/page.tsx +246 -0
  620. package/src/modules/staff/backend/staff/time-tracking/settings/page.meta.ts +14 -0
  621. package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +701 -0
  622. package/src/modules/staff/backend/staff/time-tracking/timesheet/GridView.tsx +953 -0
  623. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.meta.ts +14 -0
  624. package/src/modules/staff/backend/staff/time-tracking/timesheet/page.tsx +800 -0
  625. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +6 -6
  626. package/src/modules/staff/backend/staff/timesheets/page.tsx +12 -1010
  627. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +0 -6
  628. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +4 -158
  629. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +0 -6
  630. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -609
  631. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +0 -6
  632. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +3 -89
  633. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +2 -19
  634. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +3 -778
  635. package/src/modules/staff/ce.ts +63 -0
  636. package/src/modules/staff/cli.ts +207 -1
  637. package/src/modules/staff/commands/index.ts +5 -0
  638. package/src/modules/staff/commands/timesheets-entries.ts +1006 -28
  639. package/src/modules/staff/commands/timesheets-projects.ts +593 -7
  640. package/src/modules/staff/commands/timesheets-reports.ts +1329 -0
  641. package/src/modules/staff/commands/timesheets-tags.ts +1315 -0
  642. package/src/modules/staff/commands/timesheets-task-comments.ts +583 -0
  643. package/src/modules/staff/commands/timesheets-task-statuses.ts +889 -0
  644. package/src/modules/staff/commands/timesheets-tasks.ts +1121 -0
  645. package/src/modules/staff/data/enrichers.ts +675 -10
  646. package/src/modules/staff/data/entities.ts +494 -2
  647. package/src/modules/staff/data/extensions.ts +68 -0
  648. package/src/modules/staff/data/validators.ts +348 -3
  649. package/src/modules/staff/di.ts +96 -0
  650. package/src/modules/staff/events.payloads.ts +268 -0
  651. package/src/modules/staff/events.ts +87 -5
  652. package/src/modules/staff/extension-points.ts +308 -0
  653. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.meta.ts +10 -0
  654. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/[id]/page.tsx +225 -0
  655. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.meta.ts +17 -0
  656. package/src/modules/staff/frontend/[orgSlug]/portal/time-reports/page.tsx +182 -0
  657. package/src/modules/staff/i18n/de.json +899 -0
  658. package/src/modules/staff/i18n/en.json +899 -0
  659. package/src/modules/staff/i18n/es.json +899 -0
  660. package/src/modules/staff/i18n/ko.json +899 -0
  661. package/src/modules/staff/i18n/pl.json +899 -0
  662. package/src/modules/staff/lib/crud.ts +14 -3
  663. package/src/modules/staff/lib/time-tracking/access.ts +155 -0
  664. package/src/modules/staff/lib/time-tracking/billability.ts +68 -0
  665. package/src/modules/staff/lib/time-tracking/capacity.ts +124 -0
  666. package/src/modules/staff/lib/time-tracking/componentContracts.ts +26 -0
  667. package/src/modules/staff/lib/time-tracking/cost.ts +144 -0
  668. package/src/modules/staff/lib/time-tracking/duration.ts +68 -0
  669. package/src/modules/staff/lib/time-tracking/featureAccess.ts +115 -0
  670. package/src/modules/staff/lib/time-tracking/interval.ts +90 -0
  671. package/src/modules/staff/lib/time-tracking/migrateProjectCodes.ts +161 -0
  672. package/src/modules/staff/lib/time-tracking/moneyVisibility.ts +37 -0
  673. package/src/modules/staff/lib/time-tracking/overlap.ts +159 -0
  674. package/src/modules/staff/lib/time-tracking/portalRecipients.ts +76 -0
  675. package/src/modules/staff/lib/time-tracking/portalReports.ts +31 -0
  676. package/src/modules/staff/lib/time-tracking/projectCode.ts +221 -0
  677. package/src/modules/staff/lib/time-tracking/reapplyRounding.ts +313 -0
  678. package/src/modules/staff/lib/time-tracking/recalculationRunner.ts +118 -0
  679. package/src/modules/staff/lib/time-tracking/recalculations.ts +135 -0
  680. package/src/modules/staff/lib/time-tracking/registries/invoke.ts +122 -0
  681. package/src/modules/staff/lib/time-tracking/registries/registry.ts +124 -0
  682. package/src/modules/staff/lib/time-tracking/registries/scope.ts +56 -0
  683. package/src/modules/staff/lib/time-tracking/rollup.ts +59 -0
  684. package/src/modules/staff/lib/time-tracking/rounding.ts +126 -0
  685. package/src/modules/staff/lib/time-tracking/roundingImpact.ts +75 -0
  686. package/src/modules/staff/lib/time-tracking/settingKeys.ts +274 -0
  687. package/src/modules/staff/lib/time-tracking/settings.ts +168 -0
  688. package/src/modules/staff/lib/time-tracking/sqlInClause.ts +22 -0
  689. package/src/modules/staff/lib/time-tracking/timeEntrySources.ts +85 -0
  690. package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +360 -0
  691. package/src/modules/staff/lib/time-tracking-ui/CustomerPicker.tsx +427 -0
  692. package/src/modules/staff/lib/time-tracking-ui/DurationInput.tsx +192 -0
  693. package/src/modules/staff/lib/time-tracking-ui/EntryDetailsFields.tsx +224 -0
  694. package/src/modules/staff/lib/time-tracking-ui/EntryFilterBar.tsx +144 -0
  695. package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +1065 -0
  696. package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +435 -0
  697. package/src/modules/staff/lib/time-tracking-ui/KanbanColumn.tsx +316 -0
  698. package/src/modules/staff/lib/time-tracking-ui/NewTaskDialog.tsx +291 -0
  699. package/src/modules/staff/lib/time-tracking-ui/NoProjectAccess.tsx +162 -0
  700. package/src/modules/staff/lib/time-tracking-ui/PeriodSelector.tsx +149 -0
  701. package/src/modules/staff/lib/time-tracking-ui/PhasePlaceholder.tsx +31 -0
  702. package/src/modules/staff/lib/time-tracking-ui/ProjectCodeField.tsx +230 -0
  703. package/src/modules/staff/lib/time-tracking-ui/ProjectCurrencyField.tsx +432 -0
  704. package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +323 -0
  705. package/src/modules/staff/lib/time-tracking-ui/ProjectTeamDrawer.tsx +930 -0
  706. package/src/modules/staff/lib/time-tracking-ui/ReportSheet.tsx +357 -0
  707. package/src/modules/staff/lib/time-tracking-ui/TagPicker.tsx +195 -0
  708. package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +243 -0
  709. package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +137 -0
  710. package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +1405 -0
  711. package/src/modules/staff/lib/time-tracking-ui/TaskListView.tsx +260 -0
  712. package/src/modules/staff/lib/time-tracking-ui/TaskPicker.tsx +435 -0
  713. package/src/modules/staff/lib/time-tracking-ui/TaskQuickLog.tsx +296 -0
  714. package/src/modules/staff/lib/time-tracking-ui/TimeEntriesSummaryFooter.tsx +97 -0
  715. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDialog.tsx +1929 -0
  716. package/src/modules/staff/lib/time-tracking-ui/TimeEntryDurationCell.tsx +126 -0
  717. package/src/modules/staff/lib/time-tracking-ui/TimesheetCalendar.tsx +265 -0
  718. package/src/modules/staff/lib/time-tracking-ui/TimesheetPeriodFooter.tsx +78 -0
  719. package/src/modules/staff/lib/time-tracking-ui/TimesheetViewSwitch.tsx +70 -0
  720. package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +231 -0
  721. package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +128 -0
  722. package/src/modules/staff/lib/time-tracking-ui/boardSummary.ts +20 -0
  723. package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +228 -0
  724. package/src/modules/staff/lib/time-tracking-ui/projectTeamAssignment.ts +143 -0
  725. package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +194 -0
  726. package/src/modules/staff/lib/time-tracking-ui/timeEntryDialogState.ts +400 -0
  727. package/src/modules/staff/lib/time-tracking-ui/timeEntryListData.ts +271 -0
  728. package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +168 -0
  729. package/src/modules/staff/lib/time-tracking-ui/timesheetData.ts +225 -0
  730. package/src/modules/staff/lib/time-tracking-ui/timesheetPeriod.ts +278 -0
  731. package/src/modules/staff/lib/time-tracking-ui/timesheetTargets.ts +93 -0
  732. package/src/modules/staff/lib/time-tracking-ui/useBoardFilters.ts +107 -0
  733. package/src/modules/staff/lib/time-tracking-ui/useTimesheetPreferences.ts +245 -0
  734. package/src/modules/staff/lib/timeTrackingSeeds.ts +1037 -0
  735. package/src/modules/staff/lib/timesheets/timeEntryCacheInvalidation.ts +11 -10
  736. package/src/modules/staff/lib/timesheets/timeEntryDecoration.ts +256 -0
  737. package/src/modules/staff/lib/timesheets-projects/budgetBurn.ts +60 -0
  738. package/src/modules/staff/lib/timesheets-projects/budgetThreshold.ts +135 -0
  739. package/src/modules/staff/lib/timesheets-projects/budgetThresholdState.ts +137 -0
  740. package/src/modules/staff/lib/timesheets-projects/computeProjectFinancials.ts +142 -0
  741. package/src/modules/staff/lib/timesheets-projects/reportSelection.ts +82 -0
  742. package/src/modules/staff/lib/timesheets-projects-ui/AssignMembersDialog.tsx +237 -0
  743. package/src/modules/staff/lib/timesheets-projects-ui/ProjectBudgetCell.tsx +33 -0
  744. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +56 -1
  745. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsBulkActionsBar.tsx +90 -0
  746. package/src/modules/staff/lib/timesheets-reports/buildReportSheet.ts +125 -0
  747. package/src/modules/staff/lib/timesheets-reports/loadReportData.ts +251 -0
  748. package/src/modules/staff/lib/timesheets-reports/pdf.ts +263 -0
  749. package/src/modules/staff/lib/timesheets-reports/reportApprovalPolicies.ts +137 -0
  750. package/src/modules/staff/lib/timesheets-reports/reportConfigData.ts +247 -0
  751. package/src/modules/staff/lib/timesheets-reports/reportConfigState.ts +89 -0
  752. package/src/modules/staff/lib/timesheets-reports/reportExport.ts +373 -0
  753. package/src/modules/staff/lib/timesheets-reports/reportExportFormats.ts +71 -0
  754. package/src/modules/staff/lib/timesheets-reports/reportGroupings.ts +153 -0
  755. package/src/modules/staff/lib/timesheets-reports/reportLabels.ts +23 -0
  756. package/src/modules/staff/lib/timesheets-reports/reportReference.ts +146 -0
  757. package/src/modules/staff/lib/timesheets-reports/reportRows.ts +89 -0
  758. package/src/modules/staff/lib/timesheets-reports/reportSheetData.ts +196 -0
  759. package/src/modules/staff/lib/timesheets-reports/reportTotals.ts +544 -0
  760. package/src/modules/staff/lib/timesheets-reports/xlsx.ts +207 -0
  761. package/src/modules/staff/lib/timesheets-tasks/computeTaskRollups.ts +238 -0
  762. package/src/modules/staff/lib/timesheets-tasks/defaultStatusTemplate.ts +90 -0
  763. package/src/modules/staff/lib/timesheets-tasks/seedProjectStatuses.ts +43 -0
  764. package/src/modules/staff/lib/timesheets-tasks/statusPositions.ts +132 -0
  765. package/src/modules/staff/lib/timesheets-tasks/statusSlug.ts +43 -0
  766. package/src/modules/staff/lib/timesheets-tasks/taskHierarchy.ts +99 -0
  767. package/src/modules/staff/lib/timesheets-tasks/taskHoursTotals.ts +42 -0
  768. package/src/modules/staff/lib/timesheets-tasks/taskReference.ts +108 -0
  769. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +18 -4
  770. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +504 -149
  771. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +50 -2
  772. package/src/modules/staff/migrations/.snapshot-open-mercato.json +3244 -228
  773. package/src/modules/staff/migrations/Migration20260813073131_staff.ts +94 -0
  774. package/src/modules/staff/migrations/Migration20260824143357_staff.ts +17 -0
  775. package/src/modules/staff/notifications.client.ts +16 -0
  776. package/src/modules/staff/notifications.handlers.ts +88 -0
  777. package/src/modules/staff/notifications.ts +163 -0
  778. package/src/modules/staff/search.ts +191 -1
  779. package/src/modules/staff/setup.ts +22 -0
  780. package/src/modules/staff/subscribers/time-project-access-requested-notification.ts +95 -0
  781. package/src/modules/staff/subscribers/time-project-budget-threshold-notification.ts +226 -0
  782. package/src/modules/staff/subscribers/time-report-approved-notification.ts +116 -0
  783. package/src/modules/staff/subscribers/time-report-portal-broadcast.ts +120 -0
  784. package/src/modules/staff/translations.ts +17 -0
  785. package/src/modules/staff/widgets/components.ts +34 -0
  786. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +6 -5
  787. package/src/modules/staff/widgets/notifications/TimeProjectAccessRequestedRenderer.tsx +138 -0
  788. package/src/modules/staff/widgets/notifications/index.ts +1 -0
  789. package/src/modules/staff/workers/timesheets-reapply-rounding.ts +59 -0
  790. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +0 -123
  791. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +0 -7
  792. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +0 -138
@@ -0,0 +1,221 @@
1
+ /**
2
+ * EP-39 — the project code generator provider.
3
+ *
4
+ * `deriveProjectCode` keeps its signature and its meaning; the three-letter
5
+ * initials rule plus the collision counter now live in the built-in generator
6
+ * `staff.time_tracking.project_code.initials`, which `deriveProjectCode`
7
+ * delegates to. A contributed generator outranks it only when the caller passes
8
+ * a complete tenant + organization scope.
9
+ *
10
+ * Two runtime call sites exist and both are client-side —
11
+ * `lib/time-tracking-ui/ProjectCodeField.tsx` derives the suggestion as the user
12
+ * types a project name and again when the field is reset. Neither has a tenant
13
+ * id to hand, so both resolve the built-in today.
14
+ * `lib/time-tracking/migrateProjectCodes.ts` uses `deriveProjectCodeBase`, not
15
+ * this function.
16
+ */
17
+
18
+ import { extensionPoints } from '@open-mercato/core/modules/staff/extension-points'
19
+ import { createStrategyRegistry, BUILT_IN_STRATEGY_PRIORITY } from './registries/registry'
20
+ import { selectScopedStrategy, type ScopedResolverContext } from './registries/scope'
21
+ import { runStrategy } from './registries/invoke'
22
+
23
+ export const PROJECT_CODE_MAX_LENGTH = 20
24
+
25
+ /**
26
+ * The length a derived code aims for. Task references quote it on every card,
27
+ * drawer title and picker row (`ADS-21`), so a code that reads like a sentence
28
+ * makes the reference unusable as the thing people say to each other.
29
+ *
30
+ * It is a target, not a ceiling: a collision extends the code rather than
31
+ * mangling it, and a hand-typed code is still allowed up to
32
+ * `PROJECT_CODE_MAX_LENGTH`, because the person naming a project knows better
33
+ * than the transliterator does.
34
+ */
35
+ export const PROJECT_CODE_TARGET_LENGTH = 3
36
+
37
+ export const PROJECT_CODE_FALLBACK = 'PRJ'
38
+
39
+ const WORD_BOUNDARY_BUDGET = PROJECT_CODE_MAX_LENGTH - 1
40
+
41
+ const COMBINING_MARK_START = 0x300
42
+ const COMBINING_MARK_END = 0x36f
43
+ const ASCII_END = 0x7f
44
+
45
+ const SPECIAL_CHARACTERS: Record<string, string> = {
46
+ 'ł': 'l',
47
+ 'Ł': 'L',
48
+ 'đ': 'd',
49
+ 'Đ': 'D',
50
+ 'ð': 'd',
51
+ 'Ð': 'D',
52
+ 'ø': 'o',
53
+ 'Ø': 'O',
54
+ 'æ': 'ae',
55
+ 'Æ': 'AE',
56
+ 'œ': 'oe',
57
+ 'Œ': 'OE',
58
+ 'ß': 'ss',
59
+ 'þ': 'th',
60
+ 'Þ': 'TH',
61
+ }
62
+
63
+ function transliterate(value: string): string {
64
+ let result = ''
65
+ for (const character of value.normalize('NFD')) {
66
+ const code = character.codePointAt(0) ?? 0
67
+ if (code >= COMBINING_MARK_START && code <= COMBINING_MARK_END) continue
68
+ if (code <= ASCII_END) {
69
+ result += character
70
+ continue
71
+ }
72
+ result += SPECIAL_CHARACTERS[character] ?? character
73
+ }
74
+ return result
75
+ }
76
+
77
+ export function slugifyProjectName(name: string): string {
78
+ return transliterate(typeof name === 'string' ? name : '')
79
+ .toUpperCase()
80
+ .replace(/[^A-Z0-9]+/g, '-')
81
+ .replace(/^-+|-+$/g, '')
82
+ }
83
+
84
+ function truncateAtWordBoundary(slug: string, budget: number): string {
85
+ if (budget <= 0) return ''
86
+ if (slug.length <= budget) return slug
87
+ let result = ''
88
+ for (const word of slug.split('-')) {
89
+ const next = result ? `${result}-${word}` : word
90
+ if (next.length > budget) break
91
+ result = next
92
+ }
93
+ if (!result) result = slug.slice(0, budget)
94
+ return result.replace(/-+$/g, '')
95
+ }
96
+
97
+ /**
98
+ * The three letters a name reduces to.
99
+ *
100
+ * A multi-word name gives its initials — `Ergo Hestia Korpo` reads as `EHK`,
101
+ * which a person recognises, where the first three characters (`ERG`) do not.
102
+ * A single word gives its first three letters, so `Apollo` is `APO` and a name
103
+ * already at or under three characters (`HBH`) is left exactly as it is.
104
+ */
105
+ export function deriveProjectCodeBase(name: string): string {
106
+ const slug = slugifyProjectName(name)
107
+ if (!slug) return PROJECT_CODE_FALLBACK
108
+ const words = slug.split('-').filter((word) => word.length > 0)
109
+ if (words.length === 0) return PROJECT_CODE_FALLBACK
110
+
111
+ const initials = words.map((word) => word[0]).join('')
112
+ const base = words.length >= PROJECT_CODE_TARGET_LENGTH
113
+ ? initials.slice(0, PROJECT_CODE_TARGET_LENGTH)
114
+ : words.join('').slice(0, PROJECT_CODE_TARGET_LENGTH)
115
+
116
+ return base || PROJECT_CODE_FALLBACK
117
+ }
118
+
119
+ /**
120
+ * Three letters is roughly 17,500 combinations and derived codes cluster hard —
121
+ * `Apollo`, `Aponia` and `Apex` all want `APO` — so a collision is the normal
122
+ * case rather than the exception, and the rule for resolving one has to be
123
+ * boring and predictable. The counter extends the code (`APO` → `APO2`) instead
124
+ * of substituting a letter, because a fourth character is still readable while
125
+ * `APQ` is a different project as far as anybody reading it is concerned.
126
+ */
127
+ function deriveInitialsCode(name: string, taken: Set<string>): string {
128
+ const base = deriveProjectCodeBase(name)
129
+ const reserved = new Set(Array.from(taken ?? []).map((value) => String(value).toUpperCase()))
130
+ if (!reserved.has(base)) return base
131
+
132
+ for (let counter = 2; counter < 10000; counter += 1) {
133
+ const candidate = `${base}${counter}`
134
+ if (candidate.length > PROJECT_CODE_MAX_LENGTH) break
135
+ if (!reserved.has(candidate)) return candidate
136
+ }
137
+
138
+ // Every short candidate is taken. Fall back to the long form rather than
139
+ // failing the save — a save that refuses to happen is worse than a long code.
140
+ const longBase =
141
+ truncateAtWordBoundary(slugifyProjectName(name), WORD_BOUNDARY_BUDGET) || PROJECT_CODE_FALLBACK
142
+ if (!reserved.has(longBase)) return longBase
143
+ for (let counter = 2; counter < 10000; counter += 1) {
144
+ const suffix = `-${counter}`
145
+ const stem =
146
+ truncateAtWordBoundary(longBase, PROJECT_CODE_MAX_LENGTH - suffix.length) || PROJECT_CODE_FALLBACK
147
+ const candidate = `${stem}${suffix}`
148
+ if (!reserved.has(candidate)) return candidate
149
+ }
150
+ return longBase
151
+ }
152
+
153
+ export type ProjectCodeContext = ScopedResolverContext & {
154
+ customerId?: string | null
155
+ timeProjectId?: string | null
156
+ }
157
+
158
+ export type ProjectCodeGenerator = {
159
+ id: string
160
+ priority?: number
161
+ generate(name: string, taken: Set<string>, ctx: ProjectCodeContext): string
162
+ }
163
+
164
+ export const PROJECT_CODE_GENERATOR_REGISTRY_ID = extensionPoints.hosts.projectCodeGeneratorRegistry.spotId
165
+
166
+ export const BUILT_IN_PROJECT_CODE_GENERATOR_ID = 'staff.time_tracking.project_code.initials'
167
+
168
+ const generatorRegistry = createStrategyRegistry<ProjectCodeGenerator>(PROJECT_CODE_GENERATOR_REGISTRY_ID)
169
+
170
+ export function registerProjectCodeGenerator(generator: ProjectCodeGenerator): () => void {
171
+ return generatorRegistry.register(generator)
172
+ }
173
+
174
+ export function listProjectCodeGenerators(): ProjectCodeGenerator[] {
175
+ return generatorRegistry.list()
176
+ }
177
+
178
+ export function getProjectCodeGenerator(id: string | null | undefined): ProjectCodeGenerator | null {
179
+ return generatorRegistry.get(id)
180
+ }
181
+
182
+ const builtInProjectCodeGenerator: ProjectCodeGenerator = generatorRegistry.registerBuiltIn({
183
+ id: BUILT_IN_PROJECT_CODE_GENERATOR_ID,
184
+ priority: BUILT_IN_STRATEGY_PRIORITY,
185
+ generate: (name, taken) => deriveInitialsCode(name, taken),
186
+ })
187
+
188
+ export function resolveProjectCodeGenerator(
189
+ ctx?: ScopedResolverContext | null,
190
+ ): ProjectCodeGenerator {
191
+ return selectScopedStrategy(generatorRegistry.list(), builtInProjectCodeGenerator, ctx)
192
+ }
193
+
194
+ /**
195
+ * The code lands in a column with a length limit and is quoted on every task
196
+ * reference, so a generator that throws or answers with a blank, an over-long or a
197
+ * non-string value falls back to the module's own initials rule. A save that refuses
198
+ * to happen, or a project whose reference is unreadable, is worse than a code the
199
+ * contributor did not choose.
200
+ */
201
+ export function deriveProjectCode(
202
+ name: string,
203
+ taken: Set<string> = new Set(),
204
+ ctx?: ProjectCodeContext | null,
205
+ ): string {
206
+ const generator = resolveProjectCodeGenerator(ctx)
207
+ const reserved = taken ?? new Set<string>()
208
+ const builtIn = () => deriveInitialsCode(name, reserved)
209
+ if (generator === builtInProjectCodeGenerator) return builtIn()
210
+
211
+ const answer = runStrategy(
212
+ PROJECT_CODE_GENERATOR_REGISTRY_ID,
213
+ generator.id,
214
+ () => generator.generate(name, reserved, ctx ?? {}) as unknown,
215
+ () => null,
216
+ )
217
+ if (typeof answer !== 'string') return builtIn()
218
+ const trimmed = answer.trim()
219
+ if (!trimmed || trimmed.length > PROJECT_CODE_MAX_LENGTH) return builtIn()
220
+ return trimmed
221
+ }
@@ -0,0 +1,313 @@
1
+ /**
2
+ * Retroactive rounding, the long-running half (T7.3 / screen 16 note 3).
3
+ *
4
+ * "Apply the new rounding rule to entries that already exist" is a tenant-wide
5
+ * rewrite of a billing-relevant column, so it is a `ProgressJob` driven by a queue
6
+ * worker rather than a request that has to finish before a response — and, just as
7
+ * importantly, an action somebody deliberately takes rather than a passive toggle
8
+ * that rewrites history when the settings form is saved.
9
+ *
10
+ * What this file owns:
11
+ *
12
+ * * **Candidate selection.** Only entries that are not deleted and not locked into
13
+ * a closed report are ever selected. The command re-asserts the same condition in
14
+ * its own WHERE clause, so a locked entry is excluded twice, independently.
15
+ * * **Batching and progress.** Ids are paged with a stable `id > cursor` cursor and
16
+ * handed to the command in batches, grouped by organization because a command
17
+ * call is scoped to exactly one. Progress is reported per batch, and a cancel
18
+ * request is honoured between batches.
19
+ * * **Side-effect suppression.** Batches run with `bulkImport.skipEvents` /
20
+ * `skipNotifications`: the query index still refreshes per entry, but a
21
+ * thousand-entry restatement does not emit a thousand `time_entry.updated`
22
+ * events (which would, among other things, re-evaluate every project budget
23
+ * threshold a thousand times).
24
+ */
25
+
26
+ import type { AwilixContainer } from 'awilix'
27
+ import type { EntityManager } from '@mikro-orm/postgresql'
28
+ import type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
29
+ import { createModuleQueue, type Queue } from '@open-mercato/queue'
30
+ import { createLogger } from '@open-mercato/shared/lib/logger'
31
+ import { buildSqlInClause } from './sqlInClause'
32
+ import {
33
+ BUILT_IN_RECALCULATION_ID,
34
+ registerTimeTrackingRecalculation,
35
+ } from './recalculations'
36
+ import { BUILT_IN_STRATEGY_PRIORITY } from './registries/registry'
37
+ import type { ProgressService, ProgressServiceContext } from '../../../progress/lib/progressService'
38
+ import {
39
+ staffTimeEntryCommandIds,
40
+ type StaffTimeEntryReapplyRoundingResult,
41
+ } from '../../commands/timesheets-entries'
42
+
43
+ const logger = createLogger('staff').child({ component: 'time-tracking/reapply-rounding' })
44
+
45
+ export const STAFF_TIME_REAPPLY_ROUNDING_QUEUE = 'staff-time-reapply-rounding'
46
+ export const STAFF_TIME_REAPPLY_ROUNDING_JOB_TYPE = 'staff.timesheets.reapply_rounding'
47
+
48
+ /** One command call per batch; the command itself caps the id list at 500. */
49
+ export const REAPPLY_ROUNDING_BATCH_SIZE = 200
50
+
51
+ export type ReapplyRoundingScope = {
52
+ tenantId: string
53
+ /** Organizations the caller may act in; `null` means every organization of the tenant. */
54
+ organizationIds: string[] | null
55
+ userId?: string | null
56
+ }
57
+
58
+ export type ReapplyRoundingJobPayload = {
59
+ progressJobId: string
60
+ scope: ReapplyRoundingScope
61
+ /**
62
+ * EP-51. The recalculation hooks this job should run, in the order given.
63
+ * Absent — which is every job the settings route enqueues — means the built-in
64
+ * rounding hook alone, so the retro-rounding button keeps doing exactly what it
65
+ * did before the registry existed.
66
+ */
67
+ hookIds?: string[] | null
68
+ }
69
+
70
+ export type ReapplyRoundingSummary = {
71
+ totalCount: number
72
+ processedCount: number
73
+ updatedCount: number
74
+ unchangedCount: number
75
+ skippedCount: number
76
+ cancelled: boolean
77
+ }
78
+
79
+ const queues = new Map<string, Queue<Record<string, unknown>>>()
80
+
81
+ export function getStaffQueue(queueName: string): Queue<Record<string, unknown>> {
82
+ const existing = queues.get(queueName)
83
+ if (existing) return existing
84
+ const concurrency = Math.max(1, Number.parseInt(process.env.STAFF_QUEUE_CONCURRENCY ?? '1', 10) || 1)
85
+ const created = createModuleQueue<Record<string, unknown>>(queueName, { concurrency })
86
+ queues.set(queueName, created)
87
+ return created
88
+ }
89
+
90
+ type CandidateRow = {
91
+ id: string
92
+ organization_id: string
93
+ }
94
+
95
+ type CountRow = {
96
+ candidate_count: string | number | null
97
+ }
98
+
99
+ function buildCommandContext(
100
+ container: AwilixContainer,
101
+ tenantId: string,
102
+ organizationId: string,
103
+ ): CommandRuntimeContext {
104
+ return {
105
+ container,
106
+ auth: null,
107
+ // The job runs without an end user; the enqueuing route is the authorization
108
+ // gate (`staff.timesheets.settings.manage`), so the worker declares itself a
109
+ // system actor and passes the scope explicitly rather than inheriting one.
110
+ systemActor: true,
111
+ bulkImport: { skipEvents: true, skipNotifications: true },
112
+ organizationScope: {
113
+ selectedId: organizationId,
114
+ filterIds: [organizationId],
115
+ allowedIds: [organizationId],
116
+ tenantId,
117
+ },
118
+ selectedOrganizationId: organizationId,
119
+ organizationIds: [organizationId],
120
+ }
121
+ }
122
+
123
+ function organizationClause(organizationIds: string[] | null): { sql: string; params: unknown[] } {
124
+ if (!organizationIds) return { sql: '', params: [] }
125
+ const clause = buildSqlInClause('organization_id', organizationIds)
126
+ return { sql: ` AND ${clause.sql}`, params: clause.params }
127
+ }
128
+
129
+ export async function countReapplyRoundingCandidates(
130
+ em: EntityManager,
131
+ scope: ReapplyRoundingScope,
132
+ ): Promise<number> {
133
+ const org = organizationClause(scope.organizationIds)
134
+ const rows = (await em.getConnection().execute(
135
+ `
136
+ SELECT COUNT(*)::bigint AS candidate_count
137
+ FROM staff_time_entries
138
+ WHERE tenant_id = ?
139
+ AND deleted_at IS NULL
140
+ AND locked_report_id IS NULL${org.sql}
141
+ `,
142
+ [scope.tenantId, ...org.params],
143
+ )) as CountRow[]
144
+ const parsed = Number(rows?.[0]?.candidate_count ?? 0)
145
+ return Number.isFinite(parsed) ? parsed : 0
146
+ }
147
+
148
+ async function loadCandidatePage(
149
+ em: EntityManager,
150
+ scope: ReapplyRoundingScope,
151
+ cursor: string | null,
152
+ limit: number,
153
+ ): Promise<CandidateRow[]> {
154
+ const org = organizationClause(scope.organizationIds)
155
+ const cursorClause = cursor ? ' AND id > ?' : ''
156
+ const cursorParams = cursor ? [cursor] : []
157
+ return (await em.getConnection().execute(
158
+ `
159
+ SELECT id, organization_id
160
+ FROM staff_time_entries
161
+ WHERE tenant_id = ?
162
+ AND deleted_at IS NULL
163
+ AND locked_report_id IS NULL${org.sql}${cursorClause}
164
+ ORDER BY id ASC
165
+ LIMIT ?
166
+ `,
167
+ [scope.tenantId, ...org.params, ...cursorParams, limit],
168
+ )) as CandidateRow[]
169
+ }
170
+
171
+ function groupByOrganization(rows: readonly CandidateRow[]): Map<string, string[]> {
172
+ const grouped = new Map<string, string[]>()
173
+ for (const row of rows) {
174
+ const bucket = grouped.get(row.organization_id) ?? []
175
+ bucket.push(row.id)
176
+ grouped.set(row.organization_id, bucket)
177
+ }
178
+ return grouped
179
+ }
180
+
181
+ /**
182
+ * The restatement itself, with the `ProgressJob` lifecycle lifted out (EP-51).
183
+ *
184
+ * `reapplyRoundingWithProgress` below owns start/complete/cancel and is unchanged
185
+ * for its callers; the recalculation runner owns the same lifecycle when several
186
+ * hooks share one job. Both drive this function, so there is exactly one copy of
187
+ * the candidate query, the batching and the locked-entry exclusion.
188
+ */
189
+ export async function reapplyRoundingBatches(params: {
190
+ container: AwilixContainer
191
+ scope: ReapplyRoundingScope
192
+ report: {
193
+ setTotal(total: number): Promise<void>
194
+ advance(processed: number): Promise<void>
195
+ isCancellationRequested(): Promise<boolean>
196
+ }
197
+ }): Promise<ReapplyRoundingSummary> {
198
+ const { container, scope, report } = params
199
+ const em = (container.resolve('em') as EntityManager).fork()
200
+ const commandBus = container.resolve('commandBus') as CommandBus
201
+
202
+ const totalCount = await countReapplyRoundingCandidates(em, scope)
203
+ const summary: ReapplyRoundingSummary = {
204
+ totalCount,
205
+ processedCount: 0,
206
+ updatedCount: 0,
207
+ unchangedCount: 0,
208
+ skippedCount: 0,
209
+ cancelled: false,
210
+ }
211
+
212
+ if (totalCount === 0) return summary
213
+
214
+ await report.setTotal(totalCount)
215
+
216
+ let cursor: string | null = null
217
+ for (;;) {
218
+ const page: CandidateRow[] = await loadCandidatePage(em, scope, cursor, REAPPLY_ROUNDING_BATCH_SIZE)
219
+ if (page.length === 0) break
220
+ cursor = page[page.length - 1].id
221
+
222
+ let pageProcessed = 0
223
+ for (const [organizationId, entryIds] of groupByOrganization(page)) {
224
+ const executed = await commandBus.execute<
225
+ { tenantId: string; organizationId: string; entryIds: string[] },
226
+ StaffTimeEntryReapplyRoundingResult
227
+ >(staffTimeEntryCommandIds.reapplyRounding, {
228
+ input: { tenantId: scope.tenantId, organizationId, entryIds },
229
+ ctx: buildCommandContext(container, scope.tenantId, organizationId),
230
+ })
231
+ const result = executed?.result
232
+ summary.updatedCount += result?.updatedCount ?? 0
233
+ summary.unchangedCount += result?.unchangedCount ?? 0
234
+ summary.skippedCount += result?.skippedCount ?? 0
235
+ summary.processedCount += entryIds.length
236
+ pageProcessed += entryIds.length
237
+ }
238
+
239
+ await report.advance(pageProcessed)
240
+
241
+ if (await report.isCancellationRequested()) {
242
+ summary.cancelled = true
243
+ return summary
244
+ }
245
+ }
246
+
247
+ return summary
248
+ }
249
+
250
+ export async function reapplyRoundingWithProgress(params: {
251
+ container: AwilixContainer
252
+ progressJobId: string
253
+ scope: ReapplyRoundingScope
254
+ }): Promise<ReapplyRoundingSummary> {
255
+ const { container, progressJobId, scope } = params
256
+ const progressService = container.resolve('progressService') as ProgressService
257
+ const progressContext: ProgressServiceContext = {
258
+ tenantId: scope.tenantId,
259
+ organizationId: scope.organizationIds?.length === 1 ? scope.organizationIds[0] : null,
260
+ userId: scope.userId ?? null,
261
+ }
262
+
263
+ await progressService.startJob(progressJobId, progressContext)
264
+
265
+ let totalCount = 0
266
+ let processedCount = 0
267
+ const summary = await reapplyRoundingBatches({
268
+ container,
269
+ scope,
270
+ report: {
271
+ setTotal: async (total) => {
272
+ totalCount = total
273
+ await progressService.updateProgress(progressJobId, { totalCount, processedCount: 0 }, progressContext)
274
+ },
275
+ advance: async (processed) => {
276
+ processedCount += processed
277
+ await progressService.updateProgress(
278
+ progressJobId,
279
+ { totalCount, processedCount: Math.min(processedCount, totalCount) },
280
+ progressContext,
281
+ )
282
+ },
283
+ isCancellationRequested: () =>
284
+ progressService.isCancellationRequested(progressJobId, scope.tenantId, progressContext.organizationId),
285
+ },
286
+ })
287
+
288
+ if (summary.cancelled) {
289
+ logger.info('staff.timesheets reapply-rounding cancelled', { progressJobId, ...summary })
290
+ await progressService.markCancelled(progressJobId, progressContext)
291
+ return summary
292
+ }
293
+
294
+ await progressService.completeJob(progressJobId, { resultSummary: { ...summary } }, progressContext)
295
+ if (summary.totalCount > 0) {
296
+ logger.info('staff.timesheets reapply-rounding finished', { progressJobId, ...summary })
297
+ }
298
+ return summary
299
+ }
300
+
301
+ /**
302
+ * EP-51. The retro-rounding pass registers itself as the built-in recalculation,
303
+ * so `registerTimeTrackingRecalculation` has a working reference implementation
304
+ * and the worker has one code path for the shipped hook and a contributed one.
305
+ * `BUILT_IN_STRATEGY_PRIORITY` keeps it last in the registry's order, the same as
306
+ * every other built-in in this module.
307
+ */
308
+ registerTimeTrackingRecalculation({
309
+ id: BUILT_IN_RECALCULATION_ID,
310
+ labelKey: 'staff.time_tracking.settings.retro.jobName',
311
+ priority: BUILT_IN_STRATEGY_PRIORITY,
312
+ run: ({ container, scope, report }) => reapplyRoundingBatches({ container, scope, report }),
313
+ })
@@ -0,0 +1,118 @@
1
+ /**
2
+ * EP-51 — the job shell every registered recalculation runs inside.
3
+ *
4
+ * It owns the `ProgressJob` (start, totals, cancel, complete) and hands each hook
5
+ * a reporter scoped to that job, so N hooks share one progress bar instead of
6
+ * fighting over it. Hooks run **sequentially** and in registry order: they write
7
+ * the same rows, and two of them racing over `staff_time_entries` is the kind of
8
+ * bug that shows up as a wrong invoice a month later.
9
+ *
10
+ * A hook that throws does not silently vanish — the runner logs it and rethrows,
11
+ * because a half-finished restatement the operator believes succeeded is worse
12
+ * than a loud failure. Marking the `ProgressJob` failed is the worker's job: it
13
+ * already does that for every exception that reaches it, and doing it in both
14
+ * places would write the failure twice.
15
+ */
16
+
17
+ import type { AwilixContainer } from 'awilix'
18
+ import { createLogger } from '@open-mercato/shared/lib/logger'
19
+ import type { ProgressService, ProgressServiceContext } from '../../../progress/lib/progressService'
20
+ import {
21
+ emptyRecalculationSummary,
22
+ resolveTimeTrackingRecalculations,
23
+ type TimeTrackingRecalculationScope,
24
+ type TimeTrackingRecalculationSummary,
25
+ } from './recalculations'
26
+
27
+ const logger = createLogger('staff').child({ component: 'time-tracking/recalculation-runner' })
28
+
29
+ export type TimeTrackingRecalculationRunSummary = TimeTrackingRecalculationSummary & {
30
+ hooks: Array<{ id: string } & TimeTrackingRecalculationSummary>
31
+ }
32
+
33
+ function progressContextFor(scope: TimeTrackingRecalculationScope): ProgressServiceContext {
34
+ return {
35
+ tenantId: scope.tenantId,
36
+ organizationId: scope.organizationIds?.length === 1 ? scope.organizationIds[0] : null,
37
+ userId: scope.userId ?? null,
38
+ }
39
+ }
40
+
41
+ function accumulate(
42
+ target: TimeTrackingRecalculationSummary,
43
+ addend: TimeTrackingRecalculationSummary,
44
+ ): void {
45
+ target.totalCount += addend.totalCount
46
+ target.processedCount += addend.processedCount
47
+ target.updatedCount += addend.updatedCount
48
+ target.unchangedCount += addend.unchangedCount
49
+ target.skippedCount += addend.skippedCount
50
+ target.cancelled = target.cancelled || addend.cancelled
51
+ }
52
+
53
+ export async function runTimeTrackingRecalculations(params: {
54
+ container: AwilixContainer
55
+ progressJobId: string
56
+ scope: TimeTrackingRecalculationScope
57
+ hookIds?: readonly string[] | null
58
+ }): Promise<TimeTrackingRecalculationRunSummary> {
59
+ const { container, progressJobId, scope } = params
60
+ const hooks = resolveTimeTrackingRecalculations(params.hookIds)
61
+ const progressService = container.resolve('progressService') as ProgressService
62
+ const progressContext = progressContextFor(scope)
63
+
64
+ await progressService.startJob(progressJobId, progressContext)
65
+
66
+ const summary: TimeTrackingRecalculationRunSummary = { ...emptyRecalculationSummary(), hooks: [] }
67
+ let knownTotal = 0
68
+ let processed = 0
69
+
70
+ try {
71
+ for (const hook of hooks) {
72
+ const hookSummary = await hook.run({
73
+ container,
74
+ scope,
75
+ report: {
76
+ setTotal: async (total) => {
77
+ knownTotal += total
78
+ await progressService.updateProgress(
79
+ progressJobId,
80
+ { totalCount: knownTotal, processedCount: Math.min(processed, knownTotal) },
81
+ progressContext,
82
+ )
83
+ },
84
+ advance: async (count) => {
85
+ processed += count
86
+ await progressService.updateProgress(
87
+ progressJobId,
88
+ { totalCount: knownTotal, processedCount: Math.min(processed, knownTotal) },
89
+ progressContext,
90
+ )
91
+ },
92
+ isCancellationRequested: () =>
93
+ progressService.isCancellationRequested(
94
+ progressJobId,
95
+ scope.tenantId,
96
+ progressContext.organizationId,
97
+ ),
98
+ },
99
+ })
100
+ summary.hooks.push({ id: hook.id, ...hookSummary })
101
+ accumulate(summary, hookSummary)
102
+ if (hookSummary.cancelled) break
103
+ }
104
+ } catch (err) {
105
+ logger.error('staff.timesheets recalculation failed', { progressJobId, ...summary, err })
106
+ throw err
107
+ }
108
+
109
+ if (summary.cancelled) {
110
+ logger.info('staff.timesheets recalculation cancelled', { progressJobId, ...summary })
111
+ await progressService.markCancelled(progressJobId, progressContext)
112
+ return summary
113
+ }
114
+
115
+ await progressService.completeJob(progressJobId, { resultSummary: { ...summary } }, progressContext)
116
+ logger.info('staff.timesheets recalculation finished', { progressJobId, ...summary })
117
+ return summary
118
+ }