@hed-hog/operations 0.0.322 → 0.0.326

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 (694) hide show
  1. package/dist/controllers/operations-collaborators.controller.d.ts +14 -0
  2. package/dist/controllers/operations-collaborators.controller.d.ts.map +1 -1
  3. package/dist/controllers/operations-collaborators.controller.js +25 -0
  4. package/dist/controllers/operations-collaborators.controller.js.map +1 -1
  5. package/dist/controllers/operations-project-costs.controller.d.ts +422 -0
  6. package/dist/controllers/operations-project-costs.controller.d.ts.map +1 -0
  7. package/dist/controllers/operations-project-costs.controller.js +250 -0
  8. package/dist/controllers/operations-project-costs.controller.js.map +1 -0
  9. package/dist/controllers/operations-reports.controller.d.ts +9 -0
  10. package/dist/controllers/operations-reports.controller.d.ts.map +1 -1
  11. package/dist/controllers/operations-tasks.controller.d.ts +42 -0
  12. package/dist/controllers/operations-tasks.controller.d.ts.map +1 -1
  13. package/dist/controllers/operations-tasks.controller.js +48 -0
  14. package/dist/controllers/operations-tasks.controller.js.map +1 -1
  15. package/dist/controllers/operations-timesheets.controller.d.ts +1 -0
  16. package/dist/controllers/operations-timesheets.controller.d.ts.map +1 -1
  17. package/dist/dto/create-collaborator-project-assignment.dto.d.ts +5 -0
  18. package/dist/dto/create-collaborator-project-assignment.dto.d.ts.map +1 -0
  19. package/dist/dto/create-collaborator-project-assignment.dto.js +30 -0
  20. package/dist/dto/create-collaborator-project-assignment.dto.js.map +1 -0
  21. package/dist/dto/create-project-cost-category.dto.d.ts +10 -0
  22. package/dist/dto/create-project-cost-category.dto.d.ts.map +1 -0
  23. package/dist/dto/create-project-cost-category.dto.js +59 -0
  24. package/dist/dto/create-project-cost-category.dto.js.map +1 -0
  25. package/dist/dto/create-project-cost-type.dto.d.ts +14 -0
  26. package/dist/dto/create-project-cost-type.dto.d.ts.map +1 -0
  27. package/dist/dto/create-project-cost-type.dto.js +87 -0
  28. package/dist/dto/create-project-cost-type.dto.js.map +1 -0
  29. package/dist/dto/create-project-cost.dto.d.ts +22 -0
  30. package/dist/dto/create-project-cost.dto.d.ts.map +1 -0
  31. package/dist/dto/create-project-cost.dto.js +135 -0
  32. package/dist/dto/create-project-cost.dto.js.map +1 -0
  33. package/dist/dto/get-project-cost-report.dto.d.ts +10 -0
  34. package/dist/dto/get-project-cost-report.dto.d.ts.map +1 -0
  35. package/dist/dto/get-project-cost-report.dto.js +65 -0
  36. package/dist/dto/get-project-cost-report.dto.js.map +1 -0
  37. package/dist/dto/list-project-cost-categories.dto.d.ts +6 -0
  38. package/dist/dto/list-project-cost-categories.dto.d.ts.map +1 -0
  39. package/dist/dto/list-project-cost-categories.dto.js +34 -0
  40. package/dist/dto/list-project-cost-categories.dto.js.map +1 -0
  41. package/dist/dto/list-project-cost-types.dto.d.ts +8 -0
  42. package/dist/dto/list-project-cost-types.dto.d.ts.map +1 -0
  43. package/dist/dto/list-project-cost-types.dto.js +45 -0
  44. package/dist/dto/list-project-cost-types.dto.js.map +1 -0
  45. package/dist/dto/list-project-costs.dto.d.ts +14 -0
  46. package/dist/dto/list-project-costs.dto.d.ts.map +1 -0
  47. package/dist/dto/list-project-costs.dto.js +81 -0
  48. package/dist/dto/list-project-costs.dto.js.map +1 -0
  49. package/dist/dto/list-tasks.dto.d.ts +1 -0
  50. package/dist/dto/list-tasks.dto.d.ts.map +1 -1
  51. package/dist/dto/list-tasks.dto.js +6 -0
  52. package/dist/dto/list-tasks.dto.js.map +1 -1
  53. package/dist/dto/list-timesheets.dto.d.ts +1 -0
  54. package/dist/dto/list-timesheets.dto.d.ts.map +1 -1
  55. package/dist/dto/list-timesheets.dto.js +7 -0
  56. package/dist/dto/list-timesheets.dto.js.map +1 -1
  57. package/dist/dto/update-collaborator-project-assignment.dto.d.ts +11 -0
  58. package/dist/dto/update-collaborator-project-assignment.dto.d.ts.map +1 -0
  59. package/dist/dto/update-collaborator-project-assignment.dto.js +65 -0
  60. package/dist/dto/update-collaborator-project-assignment.dto.js.map +1 -0
  61. package/dist/dto/update-project-cost-category.dto.d.ts +6 -0
  62. package/dist/dto/update-project-cost-category.dto.d.ts.map +1 -0
  63. package/dist/dto/update-project-cost-category.dto.js +9 -0
  64. package/dist/dto/update-project-cost-category.dto.js.map +1 -0
  65. package/dist/dto/update-project-cost-type.dto.d.ts +6 -0
  66. package/dist/dto/update-project-cost-type.dto.d.ts.map +1 -0
  67. package/dist/dto/update-project-cost-type.dto.js +9 -0
  68. package/dist/dto/update-project-cost-type.dto.js.map +1 -0
  69. package/dist/dto/update-project-cost.dto.d.ts +6 -0
  70. package/dist/dto/update-project-cost.dto.d.ts.map +1 -0
  71. package/dist/dto/update-project-cost.dto.js +9 -0
  72. package/dist/dto/update-project-cost.dto.js.map +1 -0
  73. package/dist/operations.module.d.ts.map +1 -1
  74. package/dist/operations.module.js +2 -0
  75. package/dist/operations.module.js.map +1 -1
  76. package/dist/operations.service.d.ts +571 -1
  77. package/dist/operations.service.d.ts.map +1 -1
  78. package/dist/operations.service.js +1793 -69
  79. package/dist/operations.service.js.map +1 -1
  80. package/hedhog/data/integration_event_catalog.yaml +313 -0
  81. package/hedhog/data/menu.yaml +52 -0
  82. package/hedhog/data/operations_project_cost_category.yaml +80 -0
  83. package/hedhog/data/operations_project_cost_type.yaml +503 -0
  84. package/hedhog/data/route.yaml +274 -0
  85. package/hedhog/data/setting_group.yaml +21 -0
  86. package/hedhog/frontend/app/_components/collaborator-costs-section.tsx.ejs +2 -18
  87. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +593 -297
  88. package/hedhog/frontend/app/_components/collaborator-tasks-tab.tsx.ejs +358 -0
  89. package/hedhog/frontend/app/_components/collaborator-timesheets-tab.tsx.ejs +242 -0
  90. package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +533 -296
  91. package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +1 -853
  92. package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +450 -0
  93. package/hedhog/frontend/app/_components/project-cost-report-screen.tsx.ejs +602 -0
  94. package/hedhog/frontend/app/_components/project-costs-section.tsx.ejs +1401 -0
  95. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +2248 -2063
  96. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +56 -11
  97. package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +454 -96
  98. package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +784 -0
  99. package/hedhog/frontend/app/_lib/api.ts.ejs +256 -0
  100. package/hedhog/frontend/app/_lib/hooks/use-mention-items.ts.ejs +28 -0
  101. package/hedhog/frontend/app/_lib/types.ts.ejs +190 -0
  102. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +9 -3
  103. package/hedhog/frontend/app/collaborators/page.tsx.ejs +18 -7
  104. package/hedhog/frontend/app/my-tasks/page.tsx.ejs +536 -328
  105. package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +674 -0
  106. package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +845 -0
  107. package/hedhog/frontend/app/projects/[id]/costs-report/page.tsx.ejs +10 -0
  108. package/hedhog/frontend/app/reports/collaborators/page.tsx.ejs +20 -349
  109. package/hedhog/frontend/app/reports/projects/page.tsx.ejs +217 -485
  110. package/hedhog/frontend/messages/en.json +257 -5
  111. package/hedhog/frontend/messages/en.json.ejs +2060 -0
  112. package/hedhog/frontend/messages/operations/en.json +2068 -0
  113. package/hedhog/frontend/messages/operations/operations/en.json +2102 -0
  114. package/hedhog/frontend/messages/operations/operations/pt.json +2111 -0
  115. package/hedhog/frontend/messages/operations/pt.json +2072 -0
  116. package/hedhog/frontend/messages/pt.json +256 -4
  117. package/hedhog/frontend/messages/pt.json.ejs +2067 -0
  118. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.d.ts +29 -0
  119. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.d.ts.map +1 -0
  120. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.js +95 -0
  121. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.js.map +1 -0
  122. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.tsx +233 -0
  123. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.d.ts +10 -0
  124. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.d.ts.map +1 -0
  125. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.js +577 -0
  126. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.js.map +1 -0
  127. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.tsx +868 -0
  128. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.d.ts +4 -0
  129. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.d.ts.map +1 -0
  130. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.js +337 -0
  131. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.js.map +1 -0
  132. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.tsx +476 -0
  133. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.d.ts +9 -0
  134. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.d.ts.map +1 -0
  135. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.js +1348 -0
  136. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.js.map +1 -0
  137. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.tsx +2233 -0
  138. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.d.ts +12 -0
  139. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.d.ts.map +1 -0
  140. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.js +162 -0
  141. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.js.map +1 -0
  142. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.tsx +261 -0
  143. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.d.ts +18 -0
  144. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.d.ts.map +1 -0
  145. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.js +145 -0
  146. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.js.map +1 -0
  147. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.tsx +258 -0
  148. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.d.ts +4 -0
  149. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.d.ts.map +1 -0
  150. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.js +223 -0
  151. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.js.map +1 -0
  152. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.tsx +342 -0
  153. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.d.ts +58 -0
  154. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.d.ts.map +1 -0
  155. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.js +438 -0
  156. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.js.map +1 -0
  157. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.tsx +698 -0
  158. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.d.ts +20 -0
  159. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.d.ts.map +1 -0
  160. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.js +233 -0
  161. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.js.map +1 -0
  162. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.tsx +392 -0
  163. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.d.ts +4 -0
  164. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.d.ts.map +1 -0
  165. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.js +814 -0
  166. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.js.map +1 -0
  167. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.tsx +1288 -0
  168. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.d.ts +21 -0
  169. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.d.ts.map +1 -0
  170. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.js +174 -0
  171. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.js.map +1 -0
  172. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.tsx +306 -0
  173. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.d.ts +10 -0
  174. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.d.ts.map +1 -0
  175. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.js +12 -0
  176. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.js.map +1 -0
  177. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.tsx +29 -0
  178. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.d.ts +15 -0
  179. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.d.ts.map +1 -0
  180. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.js +501 -0
  181. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.js.map +1 -0
  182. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.tsx +853 -0
  183. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.d.ts +6 -0
  184. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.d.ts.map +1 -0
  185. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.js +847 -0
  186. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.js.map +1 -0
  187. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.tsx +1340 -0
  188. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.d.ts +4 -0
  189. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.d.ts.map +1 -0
  190. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.js +2930 -0
  191. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.js.map +1 -0
  192. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.tsx +4378 -0
  193. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.d.ts +9 -0
  194. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.d.ts.map +1 -0
  195. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.js +1013 -0
  196. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.js.map +1 -0
  197. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.tsx +1745 -0
  198. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.d.ts +13 -0
  199. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.d.ts.map +1 -0
  200. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.js +38 -0
  201. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.js.map +1 -0
  202. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.tsx +74 -0
  203. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.d.ts +7 -0
  204. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.d.ts.map +1 -0
  205. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.js +11 -0
  206. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.js.map +1 -0
  207. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.tsx +15 -0
  208. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.d.ts +18 -0
  209. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.d.ts.map +1 -0
  210. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.js +406 -0
  211. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.js.map +1 -0
  212. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.tsx +660 -0
  213. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.d.ts +26 -0
  214. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.d.ts.map +1 -0
  215. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.js +332 -0
  216. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.js.map +1 -0
  217. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.tsx +518 -0
  218. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.d.ts +6 -0
  219. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.d.ts.map +1 -0
  220. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.js +255 -0
  221. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.js.map +1 -0
  222. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.tsx +388 -0
  223. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.d.ts +10 -0
  224. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.d.ts.map +1 -0
  225. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.js +131 -0
  226. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.js.map +1 -0
  227. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.tsx +214 -0
  228. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.d.ts +108 -0
  229. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.d.ts.map +1 -0
  230. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.js +162 -0
  231. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.js.map +1 -0
  232. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.ts +428 -0
  233. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.d.ts +8 -0
  234. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.d.ts.map +1 -0
  235. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.js +36 -0
  236. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.js.map +1 -0
  237. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.ts +44 -0
  238. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts +837 -0
  239. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts.map +1 -0
  240. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.js +3 -0
  241. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.js.map +1 -0
  242. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.ts +861 -0
  243. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.d.ts +16 -0
  244. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.d.ts.map +1 -0
  245. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.js +182 -0
  246. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.js.map +1 -0
  247. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.ts +250 -0
  248. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.d.ts +4 -0
  249. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.d.ts.map +1 -0
  250. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.js +51 -0
  251. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.js.map +1 -0
  252. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.ts +61 -0
  253. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.d.ts +2 -0
  254. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.d.ts.map +1 -0
  255. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.js +954 -0
  256. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.js.map +1 -0
  257. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.tsx +1277 -0
  258. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.d.ts +2 -0
  259. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.d.ts.map +1 -0
  260. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.js +488 -0
  261. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.js.map +1 -0
  262. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.tsx +805 -0
  263. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.d.ts +6 -0
  264. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.d.ts.map +1 -0
  265. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.js +9 -0
  266. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.js.map +1 -0
  267. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.tsx +11 -0
  268. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.d.ts +6 -0
  269. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.d.ts.map +1 -0
  270. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.js +9 -0
  271. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.js.map +1 -0
  272. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.tsx +11 -0
  273. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.d.ts +2 -0
  274. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.d.ts.map +1 -0
  275. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.js +8 -0
  276. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.js.map +1 -0
  277. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.tsx +5 -0
  278. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.d.ts +2 -0
  279. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.d.ts.map +1 -0
  280. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.js +612 -0
  281. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.js.map +1 -0
  282. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.tsx +939 -0
  283. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.d.ts +6 -0
  284. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.d.ts.map +1 -0
  285. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.js +9 -0
  286. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.js.map +1 -0
  287. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.tsx +11 -0
  288. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.d.ts +6 -0
  289. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.d.ts.map +1 -0
  290. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.js +9 -0
  291. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.js.map +1 -0
  292. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.tsx +11 -0
  293. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.d.ts +6 -0
  294. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.d.ts.map +1 -0
  295. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.js +9 -0
  296. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.js.map +1 -0
  297. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.tsx +17 -0
  298. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.d.ts +2 -0
  299. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.d.ts.map +1 -0
  300. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.js +348 -0
  301. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.js.map +1 -0
  302. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.tsx +536 -0
  303. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.d.ts +2 -0
  304. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.d.ts.map +1 -0
  305. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.js +401 -0
  306. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.js.map +1 -0
  307. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.tsx +607 -0
  308. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.d.ts +5 -0
  309. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.d.ts.map +1 -0
  310. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.js +7 -0
  311. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.js.map +1 -0
  312. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.tsx +9 -0
  313. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.d.ts +6 -0
  314. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.d.ts.map +1 -0
  315. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.js +9 -0
  316. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.js.map +1 -0
  317. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.tsx +11 -0
  318. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.d.ts +2 -0
  319. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.d.ts.map +1 -0
  320. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.js +321 -0
  321. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.js.map +1 -0
  322. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.tsx +440 -0
  323. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.d.ts +2 -0
  324. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.d.ts.map +1 -0
  325. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.js +939 -0
  326. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.js.map +1 -0
  327. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.tsx +1499 -0
  328. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.d.ts +29 -0
  329. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.d.ts.map +1 -0
  330. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.js +95 -0
  331. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.js.map +1 -0
  332. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.tsx +233 -0
  333. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.d.ts +10 -0
  334. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.d.ts.map +1 -0
  335. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.js +577 -0
  336. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.js.map +1 -0
  337. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.tsx +868 -0
  338. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.d.ts +4 -0
  339. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.d.ts.map +1 -0
  340. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.js +337 -0
  341. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.js.map +1 -0
  342. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.tsx +476 -0
  343. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.d.ts +9 -0
  344. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.d.ts.map +1 -0
  345. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.js +1348 -0
  346. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.js.map +1 -0
  347. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.tsx +2233 -0
  348. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.d.ts +12 -0
  349. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.d.ts.map +1 -0
  350. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.js +162 -0
  351. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.js.map +1 -0
  352. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.tsx +261 -0
  353. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.d.ts +18 -0
  354. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.d.ts.map +1 -0
  355. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.js +145 -0
  356. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.js.map +1 -0
  357. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.tsx +258 -0
  358. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.d.ts +4 -0
  359. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.d.ts.map +1 -0
  360. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.js +223 -0
  361. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.js.map +1 -0
  362. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.tsx +342 -0
  363. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.d.ts +58 -0
  364. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.d.ts.map +1 -0
  365. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.js +438 -0
  366. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.js.map +1 -0
  367. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.tsx +698 -0
  368. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.d.ts +20 -0
  369. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.d.ts.map +1 -0
  370. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.js +233 -0
  371. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.js.map +1 -0
  372. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.tsx +392 -0
  373. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.d.ts +4 -0
  374. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.d.ts.map +1 -0
  375. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.js +814 -0
  376. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.js.map +1 -0
  377. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.tsx +1288 -0
  378. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.d.ts +21 -0
  379. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.d.ts.map +1 -0
  380. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.js +174 -0
  381. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.js.map +1 -0
  382. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.tsx +306 -0
  383. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.d.ts +10 -0
  384. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.d.ts.map +1 -0
  385. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.js +12 -0
  386. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.js.map +1 -0
  387. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.tsx +29 -0
  388. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.d.ts +15 -0
  389. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.d.ts.map +1 -0
  390. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.js +501 -0
  391. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.js.map +1 -0
  392. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.tsx +853 -0
  393. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.d.ts +6 -0
  394. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.d.ts.map +1 -0
  395. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.js +459 -0
  396. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.js.map +1 -0
  397. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.tsx +598 -0
  398. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.d.ts +6 -0
  399. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.d.ts.map +1 -0
  400. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.js +876 -0
  401. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.js.map +1 -0
  402. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.tsx +1368 -0
  403. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.d.ts +4 -0
  404. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.d.ts.map +1 -0
  405. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.js +2930 -0
  406. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.js.map +1 -0
  407. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.tsx +4378 -0
  408. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.d.ts +9 -0
  409. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.d.ts.map +1 -0
  410. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.js +1013 -0
  411. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.js.map +1 -0
  412. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.tsx +1745 -0
  413. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.d.ts +13 -0
  414. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.d.ts.map +1 -0
  415. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.js +38 -0
  416. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.js.map +1 -0
  417. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.tsx +74 -0
  418. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.d.ts +7 -0
  419. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.d.ts.map +1 -0
  420. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.js +11 -0
  421. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.js.map +1 -0
  422. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.tsx +15 -0
  423. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.d.ts +18 -0
  424. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.d.ts.map +1 -0
  425. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.js +406 -0
  426. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.js.map +1 -0
  427. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.tsx +660 -0
  428. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.d.ts +26 -0
  429. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.d.ts.map +1 -0
  430. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.js +332 -0
  431. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.js.map +1 -0
  432. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.tsx +518 -0
  433. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.d.ts +6 -0
  434. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.d.ts.map +1 -0
  435. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.js +255 -0
  436. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.js.map +1 -0
  437. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.tsx +388 -0
  438. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.d.ts +10 -0
  439. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.d.ts.map +1 -0
  440. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.js +131 -0
  441. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.js.map +1 -0
  442. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.tsx +214 -0
  443. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.d.ts +108 -0
  444. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.d.ts.map +1 -0
  445. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.js +162 -0
  446. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.js.map +1 -0
  447. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.ts +428 -0
  448. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.d.ts +8 -0
  449. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.d.ts.map +1 -0
  450. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.js +36 -0
  451. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.js.map +1 -0
  452. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.ts +44 -0
  453. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts +837 -0
  454. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts.map +1 -0
  455. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.js +3 -0
  456. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.js.map +1 -0
  457. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.ts +861 -0
  458. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.d.ts +16 -0
  459. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.d.ts.map +1 -0
  460. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.js +182 -0
  461. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.js.map +1 -0
  462. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.ts +250 -0
  463. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.d.ts +4 -0
  464. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.d.ts.map +1 -0
  465. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.js +51 -0
  466. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.js.map +1 -0
  467. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.ts +61 -0
  468. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.d.ts +2 -0
  469. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.d.ts.map +1 -0
  470. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.js +954 -0
  471. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.js.map +1 -0
  472. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.tsx +1277 -0
  473. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.d.ts +2 -0
  474. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.d.ts.map +1 -0
  475. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.js +488 -0
  476. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.js.map +1 -0
  477. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.tsx +805 -0
  478. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.d.ts +6 -0
  479. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.d.ts.map +1 -0
  480. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.js +9 -0
  481. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.js.map +1 -0
  482. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.tsx +11 -0
  483. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.d.ts +6 -0
  484. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.d.ts.map +1 -0
  485. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.js +9 -0
  486. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.js.map +1 -0
  487. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.tsx +11 -0
  488. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.d.ts +2 -0
  489. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.d.ts.map +1 -0
  490. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.js +8 -0
  491. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.js.map +1 -0
  492. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.tsx +5 -0
  493. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.d.ts +2 -0
  494. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.d.ts.map +1 -0
  495. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.js +612 -0
  496. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.js.map +1 -0
  497. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.tsx +939 -0
  498. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.d.ts +6 -0
  499. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.d.ts.map +1 -0
  500. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.js +9 -0
  501. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.js.map +1 -0
  502. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.tsx +11 -0
  503. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.d.ts +6 -0
  504. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.d.ts.map +1 -0
  505. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.js +9 -0
  506. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.js.map +1 -0
  507. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.tsx +11 -0
  508. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.d.ts +6 -0
  509. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.d.ts.map +1 -0
  510. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.js +9 -0
  511. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.js.map +1 -0
  512. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.tsx +17 -0
  513. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.d.ts +2 -0
  514. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.d.ts.map +1 -0
  515. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.js +348 -0
  516. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.js.map +1 -0
  517. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.tsx +536 -0
  518. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.d.ts +2 -0
  519. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.d.ts.map +1 -0
  520. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.js +401 -0
  521. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.js.map +1 -0
  522. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.tsx +607 -0
  523. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.d.ts +5 -0
  524. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.d.ts.map +1 -0
  525. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.js +7 -0
  526. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.js.map +1 -0
  527. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.tsx +9 -0
  528. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.d.ts +6 -0
  529. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.d.ts.map +1 -0
  530. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.js +9 -0
  531. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.js.map +1 -0
  532. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.tsx +11 -0
  533. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.d.ts +2 -0
  534. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.d.ts.map +1 -0
  535. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.js +321 -0
  536. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.js.map +1 -0
  537. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.tsx +440 -0
  538. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.d.ts +2 -0
  539. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.d.ts.map +1 -0
  540. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.js +939 -0
  541. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.js.map +1 -0
  542. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.tsx +1499 -0
  543. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.d.ts +2 -0
  544. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.d.ts.map +1 -0
  545. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.js +8 -0
  546. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.js.map +1 -0
  547. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.tsx +5 -0
  548. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.d.ts +2 -0
  549. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.d.ts.map +1 -0
  550. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.js +436 -0
  551. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.js.map +1 -0
  552. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.tsx +675 -0
  553. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.d.ts +2 -0
  554. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.d.ts.map +1 -0
  555. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.js +563 -0
  556. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.js.map +1 -0
  557. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.tsx +846 -0
  558. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.d.ts +6 -0
  559. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.d.ts.map +1 -0
  560. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.js +9 -0
  561. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.js.map +1 -0
  562. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.tsx +10 -0
  563. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.d.ts +6 -0
  564. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.d.ts.map +1 -0
  565. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.js +9 -0
  566. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.js.map +1 -0
  567. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.tsx +11 -0
  568. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.d.ts +6 -0
  569. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.d.ts.map +1 -0
  570. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.js +9 -0
  571. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.js.map +1 -0
  572. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.tsx +11 -0
  573. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.d.ts +2 -0
  574. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.d.ts.map +1 -0
  575. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.js +8 -0
  576. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.js.map +1 -0
  577. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.tsx +5 -0
  578. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.d.ts +2 -0
  579. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.d.ts.map +1 -0
  580. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.js +492 -0
  581. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.js.map +1 -0
  582. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.tsx +757 -0
  583. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.d.ts +2 -0
  584. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.d.ts.map +1 -0
  585. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.js +342 -0
  586. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.js.map +1 -0
  587. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.tsx +430 -0
  588. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.d.ts +2 -0
  589. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.d.ts.map +1 -0
  590. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.js +338 -0
  591. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.js.map +1 -0
  592. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.tsx +428 -0
  593. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.d.ts +2 -0
  594. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.d.ts.map +1 -0
  595. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.js +660 -0
  596. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.js.map +1 -0
  597. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.tsx +992 -0
  598. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.d.ts +2 -0
  599. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.d.ts.map +1 -0
  600. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.js +515 -0
  601. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.js.map +1 -0
  602. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.tsx +707 -0
  603. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.d.ts +2 -0
  604. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.d.ts.map +1 -0
  605. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.js +1141 -0
  606. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.js.map +1 -0
  607. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.tsx +1705 -0
  608. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.d.ts +2 -0
  609. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.d.ts.map +1 -0
  610. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.js +8 -0
  611. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.js.map +1 -0
  612. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.tsx +5 -0
  613. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.d.ts +2 -0
  614. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.d.ts.map +1 -0
  615. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.js +436 -0
  616. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.js.map +1 -0
  617. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.tsx +675 -0
  618. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.d.ts +2 -0
  619. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.d.ts.map +1 -0
  620. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.js +563 -0
  621. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.js.map +1 -0
  622. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.tsx +846 -0
  623. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.d.ts +6 -0
  624. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.d.ts.map +1 -0
  625. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.js +9 -0
  626. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.js.map +1 -0
  627. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.tsx +11 -0
  628. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.d.ts +6 -0
  629. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.d.ts.map +1 -0
  630. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.js +9 -0
  631. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.js.map +1 -0
  632. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.tsx +11 -0
  633. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.d.ts +2 -0
  634. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.d.ts.map +1 -0
  635. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.js +8 -0
  636. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.js.map +1 -0
  637. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.tsx +5 -0
  638. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.d.ts +2 -0
  639. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.d.ts.map +1 -0
  640. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.js +492 -0
  641. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.js.map +1 -0
  642. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.tsx +757 -0
  643. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.d.ts +2 -0
  644. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.d.ts.map +1 -0
  645. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.js +342 -0
  646. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.js.map +1 -0
  647. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.tsx +430 -0
  648. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.d.ts +2 -0
  649. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.d.ts.map +1 -0
  650. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.js +338 -0
  651. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.js.map +1 -0
  652. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.tsx +428 -0
  653. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.d.ts +2 -0
  654. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.d.ts.map +1 -0
  655. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.js +660 -0
  656. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.js.map +1 -0
  657. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.tsx +992 -0
  658. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.d.ts +2 -0
  659. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.d.ts.map +1 -0
  660. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.js +515 -0
  661. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.js.map +1 -0
  662. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.tsx +707 -0
  663. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.d.ts +2 -0
  664. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.d.ts.map +1 -0
  665. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.js +1141 -0
  666. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.js.map +1 -0
  667. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.tsx +1705 -0
  668. package/hedhog/table/operations_collaborator.yaml +5 -0
  669. package/hedhog/table/operations_collaborator_compensation_history.yaml +4 -0
  670. package/hedhog/table/operations_project_assignment.yaml +1 -0
  671. package/hedhog/table/operations_project_cost.yaml +93 -0
  672. package/hedhog/table/operations_project_cost_category.yaml +37 -0
  673. package/hedhog/table/operations_project_cost_type.yaml +55 -0
  674. package/hedhog/table/operations_task_comment.yaml +26 -0
  675. package/package.json +6 -6
  676. package/src/controllers/operations-collaborators.controller.ts +26 -0
  677. package/src/controllers/operations-project-costs.controller.ts +249 -0
  678. package/src/controllers/operations-tasks.controller.ts +49 -0
  679. package/src/dto/create-collaborator-project-assignment.dto.ts +14 -0
  680. package/src/dto/create-project-cost-category.dto.ts +37 -0
  681. package/src/dto/create-project-cost-type.dto.ts +64 -0
  682. package/src/dto/create-project-cost.dto.ts +126 -0
  683. package/src/dto/get-project-cost-report.dto.ts +46 -0
  684. package/src/dto/list-project-cost-categories.dto.ts +17 -0
  685. package/src/dto/list-project-cost-types.dto.ts +28 -0
  686. package/src/dto/list-project-costs.dto.ts +59 -0
  687. package/src/dto/list-tasks.dto.ts +7 -0
  688. package/src/dto/list-timesheets.dto.ts +7 -1
  689. package/src/dto/update-collaborator-project-assignment.dto.ts +58 -0
  690. package/src/dto/update-project-cost-category.dto.ts +4 -0
  691. package/src/dto/update-project-cost-type.dto.ts +4 -0
  692. package/src/dto/update-project-cost.dto.ts +4 -0
  693. package/src/operations.module.ts +2 -0
  694. package/src/operations.service.ts +2472 -61
@@ -997,7 +997,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
997
997
  throw new common_1.BadRequestException('Field "personId" is required.');
998
998
  }
999
999
  const collaboratorId = await this.prisma.$transaction(async (tx) => {
1000
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
1000
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6;
1001
1001
  const normalizedCode = String((_a = data.code) !== null && _a !== void 0 ? _a : '').trim() ||
1002
1002
  (await this.generateCollaboratorCode(tx));
1003
1003
  const resolvedDepartment = await this.resolveDepartmentReference(tx, {
@@ -1053,11 +1053,23 @@ let OperationsService = OperationsService_1 = class OperationsService {
1053
1053
  });
1054
1054
  }
1055
1055
  if (data.compensationAmount != null) {
1056
- await this.insertCollaboratorCompensationHistory(tx, createdCollaboratorId, Number(data.compensationAmount), actor.userId, null);
1056
+ await this.insertCollaboratorCompensationHistory(tx, createdCollaboratorId, Number(data.compensationAmount), actor.userId, (_3 = data.compensationNotes) !== null && _3 !== void 0 ? _3 : null, (_4 = data.compensationEffectiveDate) !== null && _4 !== void 0 ? _4 : null);
1057
+ }
1058
+ if (data.hourlyRate != null) {
1059
+ await tx.$executeRawUnsafe(`UPDATE operations_collaborator SET hourly_rate = $1 WHERE id = $2`, Number(data.hourlyRate), createdCollaboratorId);
1060
+ await this.insertCollaboratorCompensationHistory(tx, createdCollaboratorId, Number(data.hourlyRate), actor.userId, (_5 = data.compensationNotes) !== null && _5 !== void 0 ? _5 : null, (_6 = data.compensationEffectiveDate) !== null && _6 !== void 0 ? _6 : null, 'hourly_rate');
1057
1061
  }
1058
1062
  return createdCollaboratorId;
1059
1063
  });
1060
- return this.getCollaboratorByIdForUser(userId, collaboratorId);
1064
+ const result = await this.getCollaboratorByIdForUser(userId, collaboratorId);
1065
+ await this.integrationApi.publishEvent({
1066
+ eventName: 'operations.collaborator.created',
1067
+ sourceModule: 'operations',
1068
+ aggregateType: 'collaborator',
1069
+ aggregateId: String(collaboratorId),
1070
+ payload: { id: collaboratorId, displayName: resolvedDisplayName, status: normalizedStatus },
1071
+ }).catch(() => null);
1072
+ return result;
1061
1073
  }
1062
1074
  async updateCollaborator(userId, collaboratorId, data) {
1063
1075
  var _a, _b, _c, _d, _e;
@@ -1080,34 +1092,41 @@ let OperationsService = OperationsService_1 = class OperationsService {
1080
1092
  }
1081
1093
  this.pushUpdate(updates, params, 'level_label', data.levelLabel);
1082
1094
  this.pushUpdate(updates, params, 'weekly_capacity_hours', data.weeklyCapacityHours);
1095
+ this.pushUpdate(updates, params, 'hourly_rate', data.hourlyRate);
1083
1096
  this.pushUpdate(updates, params, 'status', normalizedStatus, 'operations_collaborator_status_ef779877d4_enum');
1084
1097
  this.pushUpdate(updates, params, 'joined_at', data.joinedAt, 'date');
1085
1098
  this.pushUpdate(updates, params, 'left_at', data.leftAt, 'date');
1086
1099
  this.pushUpdate(updates, params, 'notes', data.notes);
1100
+ let currentHourlyRate = null;
1087
1101
  await this.prisma.$transaction(async (tx) => {
1088
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
1102
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
1103
+ if (data.hourlyRate !== undefined && data.hourlyRate !== null) {
1104
+ const curr = (await tx.$queryRawUnsafe(`SELECT hourly_rate AS "hourlyRate" FROM operations_collaborator WHERE id = $1`, collaboratorId));
1105
+ currentHourlyRate =
1106
+ ((_a = curr[0]) === null || _a === void 0 ? void 0 : _a.hourlyRate) != null ? Number(curr[0].hourlyRate) : null;
1107
+ }
1089
1108
  if (data.collaboratorType !== undefined ||
1090
1109
  data.collaboratorTypeId !== undefined ||
1091
1110
  data.collaboratorTypeSlug !== undefined) {
1092
1111
  const resolvedCollaboratorType = await this.resolveCollaboratorTypeReference(tx, {
1093
- collaboratorTypeId: (_a = data.collaboratorTypeId) !== null && _a !== void 0 ? _a : null,
1094
- collaboratorTypeSlug: (_c = (_b = data.collaboratorTypeSlug) !== null && _b !== void 0 ? _b : data.collaboratorType) !== null && _c !== void 0 ? _c : null,
1112
+ collaboratorTypeId: (_b = data.collaboratorTypeId) !== null && _b !== void 0 ? _b : null,
1113
+ collaboratorTypeSlug: (_d = (_c = data.collaboratorTypeSlug) !== null && _c !== void 0 ? _c : data.collaboratorType) !== null && _d !== void 0 ? _d : null,
1095
1114
  });
1096
- this.pushUpdate(updates, params, 'collaborator_type_id', (_d = resolvedCollaboratorType === null || resolvedCollaboratorType === void 0 ? void 0 : resolvedCollaboratorType.id) !== null && _d !== void 0 ? _d : null);
1115
+ this.pushUpdate(updates, params, 'collaborator_type_id', (_e = resolvedCollaboratorType === null || resolvedCollaboratorType === void 0 ? void 0 : resolvedCollaboratorType.id) !== null && _e !== void 0 ? _e : null);
1097
1116
  }
1098
1117
  if (data.departmentId !== undefined) {
1099
1118
  const resolvedDepartment = await this.resolveDepartmentReference(tx, {
1100
- departmentId: (_e = data.departmentId) !== null && _e !== void 0 ? _e : null,
1119
+ departmentId: (_f = data.departmentId) !== null && _f !== void 0 ? _f : null,
1101
1120
  });
1102
- this.pushUpdate(updates, params, 'department_id', (_f = resolvedDepartment === null || resolvedDepartment === void 0 ? void 0 : resolvedDepartment.id) !== null && _f !== void 0 ? _f : null);
1121
+ this.pushUpdate(updates, params, 'department_id', (_g = resolvedDepartment === null || resolvedDepartment === void 0 ? void 0 : resolvedDepartment.id) !== null && _g !== void 0 ? _g : null);
1103
1122
  }
1104
1123
  if (data.title !== undefined || data.jobTitleId !== undefined) {
1105
1124
  const resolvedJobTitle = await this.resolveJobTitleReference(tx, {
1106
- jobTitleId: (_g = data.jobTitleId) !== null && _g !== void 0 ? _g : null,
1125
+ jobTitleId: (_h = data.jobTitleId) !== null && _h !== void 0 ? _h : null,
1107
1126
  jobTitleName: data.title,
1108
1127
  });
1109
- this.pushUpdate(updates, params, 'job_title_id', (_h = resolvedJobTitle === null || resolvedJobTitle === void 0 ? void 0 : resolvedJobTitle.id) !== null && _h !== void 0 ? _h : null);
1110
- this.pushUpdate(updates, params, 'title', (_j = resolvedJobTitle === null || resolvedJobTitle === void 0 ? void 0 : resolvedJobTitle.name) !== null && _j !== void 0 ? _j : this.normalizeOptionalText(data.title));
1128
+ this.pushUpdate(updates, params, 'job_title_id', (_j = resolvedJobTitle === null || resolvedJobTitle === void 0 ? void 0 : resolvedJobTitle.id) !== null && _j !== void 0 ? _j : null);
1129
+ this.pushUpdate(updates, params, 'title', (_k = resolvedJobTitle === null || resolvedJobTitle === void 0 ? void 0 : resolvedJobTitle.name) !== null && _k !== void 0 ? _k : this.normalizeOptionalText(data.title));
1111
1130
  }
1112
1131
  if (updates.length) {
1113
1132
  params.push(collaboratorId);
@@ -1125,6 +1144,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
1125
1144
  if (data.compensationAmount !== undefined ||
1126
1145
  data.contractDescription !== undefined ||
1127
1146
  data.autoGenerateContractDraft !== undefined ||
1147
+ data.hourlyRate !== undefined ||
1128
1148
  data.joinedAt !== undefined ||
1129
1149
  data.weeklyCapacityHours !== undefined ||
1130
1150
  data.supervisorCollaboratorId !== undefined ||
@@ -1134,14 +1154,103 @@ let OperationsService = OperationsService_1 = class OperationsService {
1134
1154
  data.code !== undefined ||
1135
1155
  data.personId !== undefined ||
1136
1156
  data.displayName !== undefined) {
1157
+ let currentBudgetAmount = null;
1158
+ if (data.compensationAmount !== undefined &&
1159
+ data.compensationAmount !== null) {
1160
+ const hiringContracts = (await tx.$queryRawUnsafe(`SELECT budget_amount AS "budgetAmount"
1161
+ FROM operations_contract
1162
+ WHERE related_collaborator_id = $1
1163
+ AND origin_type = 'employee_hiring'
1164
+ AND deleted_at IS NULL
1165
+ ORDER BY created_at DESC
1166
+ LIMIT 1`, collaboratorId));
1167
+ currentBudgetAmount =
1168
+ ((_l = hiringContracts[0]) === null || _l === void 0 ? void 0 : _l.budgetAmount) != null
1169
+ ? Number(hiringContracts[0].budgetAmount)
1170
+ : null;
1171
+ }
1137
1172
  await this.syncHiringContractDraft(tx, actor.userId, collaboratorId, data);
1138
1173
  if (data.compensationAmount !== undefined &&
1139
1174
  data.compensationAmount !== null) {
1140
- await this.insertCollaboratorCompensationHistory(tx, collaboratorId, Number(data.compensationAmount), actor.userId, null);
1175
+ const newAmount = Number(data.compensationAmount);
1176
+ if (currentBudgetAmount === null ||
1177
+ newAmount !== currentBudgetAmount) {
1178
+ await this.insertCollaboratorCompensationHistory(tx, collaboratorId, newAmount, actor.userId, (_m = data.compensationNotes) !== null && _m !== void 0 ? _m : null, (_o = data.compensationEffectiveDate) !== null && _o !== void 0 ? _o : null);
1179
+ }
1180
+ }
1181
+ if (data.hourlyRate !== undefined && data.hourlyRate !== null) {
1182
+ const newRate = Number(data.hourlyRate);
1183
+ if (currentHourlyRate === null || newRate !== currentHourlyRate) {
1184
+ await this.insertCollaboratorCompensationHistory(tx, collaboratorId, newRate, actor.userId, (_p = data.compensationNotes) !== null && _p !== void 0 ? _p : null, (_q = data.compensationEffectiveDate) !== null && _q !== void 0 ? _q : null, 'hourly_rate');
1185
+ }
1141
1186
  }
1142
1187
  }
1143
1188
  });
1144
- return this.getCollaboratorByIdForUser(userId, collaboratorId);
1189
+ const collaboratorResult = await this.getCollaboratorByIdForUser(userId, collaboratorId);
1190
+ await this.integrationApi.publishEvent({
1191
+ eventName: 'operations.collaborator.updated',
1192
+ sourceModule: 'operations',
1193
+ aggregateType: 'collaborator',
1194
+ aggregateId: String(collaboratorId),
1195
+ payload: { id: collaboratorId, displayName: data.displayName, status: data.status },
1196
+ }).catch(() => null);
1197
+ return collaboratorResult;
1198
+ }
1199
+ async updateCollaboratorProjectAssignment(collaboratorId, projectId, data) {
1200
+ var _a, _b, _c, _d, _e, _f;
1201
+ const sets = [];
1202
+ const params = [collaboratorId, projectId];
1203
+ let idx = 3;
1204
+ if ('projectRoleId' in data) {
1205
+ sets.push(`project_role_id = $${idx++}`);
1206
+ params.push((_a = data.projectRoleId) !== null && _a !== void 0 ? _a : null);
1207
+ }
1208
+ if ('roleLabel' in data) {
1209
+ sets.push(`role_label = $${idx++}`);
1210
+ params.push((_b = data.roleLabel) !== null && _b !== void 0 ? _b : null);
1211
+ }
1212
+ if ('allocationPercent' in data) {
1213
+ sets.push(`allocation_percent = $${idx++}`);
1214
+ params.push((_c = data.allocationPercent) !== null && _c !== void 0 ? _c : null);
1215
+ }
1216
+ if ('weeklyHours' in data) {
1217
+ sets.push(`weekly_hours = $${idx++}`);
1218
+ params.push((_d = data.weeklyHours) !== null && _d !== void 0 ? _d : null);
1219
+ }
1220
+ if ('startDate' in data) {
1221
+ sets.push(`start_date = $${idx++}::date`);
1222
+ params.push((_e = data.startDate) !== null && _e !== void 0 ? _e : null);
1223
+ }
1224
+ if ('endDate' in data) {
1225
+ sets.push(`end_date = $${idx++}::date`);
1226
+ params.push((_f = data.endDate) !== null && _f !== void 0 ? _f : null);
1227
+ }
1228
+ if ('status' in data) {
1229
+ sets.push(`status = $${idx++}::operations_project_assignment_status_155b459bbf_enum`);
1230
+ params.push(data.status);
1231
+ }
1232
+ if (!sets.length)
1233
+ return { updated: false };
1234
+ sets.push(`updated_at = NOW()`);
1235
+ await this.prisma.$executeRawUnsafe(`UPDATE operations_project_assignment
1236
+ SET ${sets.join(', ')}
1237
+ WHERE collaborator_id = $1
1238
+ AND project_id = $2
1239
+ AND deleted_at IS NULL`, ...params);
1240
+ return { updated: true };
1241
+ }
1242
+ async addCollaboratorProjectAssignment(collaboratorId, data) {
1243
+ var _a;
1244
+ const existing = await this.querySingle(`SELECT id FROM operations_project_assignment
1245
+ WHERE collaborator_id = $1 AND project_id = $2 AND deleted_at IS NULL`, [collaboratorId, data.projectId]);
1246
+ if (existing) {
1247
+ return { id: existing.id, created: false };
1248
+ }
1249
+ const row = await this.querySingle(`INSERT INTO operations_project_assignment
1250
+ (collaborator_id, project_id, role_label, status)
1251
+ VALUES ($1, $2, $3, 'active')
1252
+ RETURNING id`, [collaboratorId, data.projectId, (_a = data.roleLabel) !== null && _a !== void 0 ? _a : '']);
1253
+ return { id: row.id, created: true };
1145
1254
  }
1146
1255
  async getCollaboratorCompensationHistory(userId, collaboratorId) {
1147
1256
  const actor = await this.getActorContext(userId);
@@ -1154,6 +1263,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
1154
1263
  h.actor_user_id AS "actorUserId",
1155
1264
  u.name AS "actorName",
1156
1265
  h.notes,
1266
+ h.amount_type AS "amountType",
1157
1267
  h.created_at AS "createdAt"
1158
1268
  FROM operations_collaborator_compensation_history h
1159
1269
  LEFT JOIN "user" u ON u.id = h.actor_user_id
@@ -1589,6 +1699,10 @@ let OperationsService = OperationsService_1 = class OperationsService {
1589
1699
  if (paginationParams.status) {
1590
1700
  filters.push(`t.status::text = ${this.param(params, paginationParams.status)}`);
1591
1701
  }
1702
+ if (paginationParams.collaboratorId) {
1703
+ const colId = paginationParams.collaboratorId;
1704
+ filters.push(`(pa.collaborator_id = ${this.param(params, colId)} OR t.assignee_collaborator_id = ${this.param(params, colId)})`);
1705
+ }
1592
1706
  const whereClause = filters.join(' AND ');
1593
1707
  const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
1594
1708
  FROM operations_task t
@@ -1621,6 +1735,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
1621
1735
  ac.display_name AS "assigneeName",
1622
1736
  au.photo_id AS "assigneeUserPhotoId",
1623
1737
  ap.avatar_id AS "assigneePersonAvatarId",
1738
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
1739
+ COALESCE(task_files.count, 0)::int AS "fileCount",
1624
1740
  t.created_at AS "createdAt",
1625
1741
  t.deleted_at AS "deletedAt"
1626
1742
  FROM operations_task t
@@ -1633,6 +1749,16 @@ let OperationsService = OperationsService_1 = class OperationsService {
1633
1749
  ON au.id = ac.user_id
1634
1750
  LEFT JOIN person ap
1635
1751
  ON ap.id = ac.person_id
1752
+ LEFT JOIN LATERAL (
1753
+ SELECT COUNT(*) AS count
1754
+ FROM operations_task_comment tc
1755
+ WHERE tc.task_id = t.id
1756
+ ) task_comments ON TRUE
1757
+ LEFT JOIN LATERAL (
1758
+ SELECT COUNT(*) AS count
1759
+ FROM operations_task_file tf
1760
+ WHERE tf.operations_task_id = t.id
1761
+ ) task_files ON TRUE
1636
1762
  JOIN operations_project p
1637
1763
  ON p.id = COALESCE(t.project_id, pa.project_id)
1638
1764
  WHERE ${whereClause}
@@ -1642,7 +1768,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
1642
1768
  return this.buildPaginationResult(rows.map((row) => (Object.assign(Object.assign({}, row), { label: [row.name, row.projectName].filter(Boolean).join(' • ') }))), Number((_b = totalRow === null || totalRow === void 0 ? void 0 : totalRow.total) !== null && _b !== void 0 ? _b : 0), pagination.page, pagination.pageSize);
1643
1769
  }
1644
1770
  async createTask(userId, data) {
1645
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1771
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
1646
1772
  const actor = await this.getActorContext(userId);
1647
1773
  if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
1648
1774
  throw new common_1.ForbiddenException('Operations collaborator access is required.');
@@ -1718,7 +1844,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
1718
1844
  (_m = data.position) !== null && _m !== void 0 ? _m : nextPosition,
1719
1845
  (_o = data.tags) !== null && _o !== void 0 ? _o : null,
1720
1846
  ]);
1721
- return this.getProjectBoardTask((_p = created === null || created === void 0 ? void 0 : created.id) !== null && _p !== void 0 ? _p : 0);
1847
+ const task = await this.getProjectBoardTask((_p = created === null || created === void 0 ? void 0 : created.id) !== null && _p !== void 0 ? _p : 0);
1848
+ await this.integrationApi.publishEvent({
1849
+ eventName: 'operations.task.created',
1850
+ sourceModule: 'operations',
1851
+ aggregateType: 'task',
1852
+ aggregateId: String((_q = created === null || created === void 0 ? void 0 : created.id) !== null && _q !== void 0 ? _q : 0),
1853
+ payload: { id: created === null || created === void 0 ? void 0 : created.id, projectId, name, status: (_r = data.status) !== null && _r !== void 0 ? _r : 'todo', priority: (_s = data.priority) !== null && _s !== void 0 ? _s : 'medium' },
1854
+ }).catch(() => null);
1855
+ return task;
1722
1856
  }
1723
1857
  async updateTask(userId, taskId, data) {
1724
1858
  const actor = await this.getActorContext(userId);
@@ -1776,7 +1910,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
1776
1910
  ? this.normalizeOptionalText(data.description)
1777
1911
  : ((_d = current.description) !== null && _d !== void 0 ? _d : null), (_e = data.priority) !== null && _e !== void 0 ? _e : current.priority, nextStatus, data.dueDate !== undefined ? ((_f = data.dueDate) !== null && _f !== void 0 ? _f : null) : current.dueDate, data.estimateHours !== undefined ? ((_g = data.estimateHours) !== null && _g !== void 0 ? _g : null) : current.estimateHours, data.position !== undefined ? data.position : current.position, data.tags !== undefined ? ((_h = data.tags) !== null && _h !== void 0 ? _h : null) : current.tags, nextArchived, taskId, Boolean(current.deletedAt));
1778
1912
  });
1779
- return this.getProjectBoardTask(taskId);
1913
+ const taskResult = await this.getProjectBoardTask(taskId);
1914
+ await this.integrationApi.publishEvent({
1915
+ eventName: 'operations.task.updated',
1916
+ sourceModule: 'operations',
1917
+ aggregateType: 'task',
1918
+ aggregateId: String(taskId),
1919
+ payload: { id: taskId, name: data.name, status: data.status },
1920
+ }).catch(() => null);
1921
+ return taskResult;
1780
1922
  }
1781
1923
  async removeTask(userId, taskId, permanent = false) {
1782
1924
  const actor = await this.getActorContext(userId);
@@ -1797,6 +1939,13 @@ let OperationsService = OperationsService_1 = class OperationsService {
1797
1939
  WHERE id = $1
1798
1940
  AND deleted_at IS NULL`, taskId);
1799
1941
  });
1942
+ await this.integrationApi.publishEvent({
1943
+ eventName: 'operations.task.deleted',
1944
+ sourceModule: 'operations',
1945
+ aggregateType: 'task',
1946
+ aggregateId: String(taskId),
1947
+ payload: { id: taskId, projectId: current.projectId, permanent },
1948
+ }).catch(() => null);
1800
1949
  return { success: true };
1801
1950
  }
1802
1951
  async listTaskFiles(userId, taskId) {
@@ -1844,6 +1993,126 @@ let OperationsService = OperationsService_1 = class OperationsService {
1844
1993
  }
1845
1994
  return { success: true };
1846
1995
  }
1996
+ async listTaskComments(userId, taskId) {
1997
+ const actor = await this.getActorContext(userId);
1998
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
1999
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
2000
+ }
2001
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
2002
+ await this.assertProjectAccess(actor, current.projectId);
2003
+ return this.queryRows(`SELECT tc.id,
2004
+ tc.task_id AS "taskId",
2005
+ tc.content,
2006
+ tc.actor_collaborator_id AS "actorCollaboratorId",
2007
+ actor.display_name AS "actorName",
2008
+ actor_user.photo_id AS "actorUserPhotoId",
2009
+ actor_person.avatar_id AS "actorPersonAvatarId",
2010
+ tc.created_at AS "createdAt",
2011
+ tc.updated_at AS "updatedAt"
2012
+ FROM operations_task_comment tc
2013
+ LEFT JOIN operations_collaborator actor
2014
+ ON actor.id = tc.actor_collaborator_id
2015
+ AND actor.deleted_at IS NULL
2016
+ LEFT JOIN "user" actor_user
2017
+ ON actor_user.id = actor.user_id
2018
+ LEFT JOIN person actor_person
2019
+ ON actor_person.id = actor.person_id
2020
+ WHERE tc.task_id = $1
2021
+ ORDER BY tc.created_at ASC, tc.id ASC`, [taskId]);
2022
+ }
2023
+ async addTaskComment(userId, taskId, content) {
2024
+ var _a, _b;
2025
+ const actor = await this.getActorContext(userId);
2026
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
2027
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
2028
+ }
2029
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
2030
+ await this.assertProjectAccess(actor, current.projectId);
2031
+ const normalizedContent = this.normalizeOptionalText(content);
2032
+ if (!normalizedContent) {
2033
+ throw new common_1.BadRequestException('Comment content is required.');
2034
+ }
2035
+ const inserted = await this.queryRows(`INSERT INTO operations_task_comment (
2036
+ task_id,
2037
+ actor_collaborator_id,
2038
+ content,
2039
+ created_at,
2040
+ updated_at
2041
+ ) VALUES ($1, $2, $3, NOW(), NOW())
2042
+ RETURNING id`, [taskId, (_a = actor.collaboratorId) !== null && _a !== void 0 ? _a : null, normalizedContent]);
2043
+ const commentId = (_b = inserted[0]) === null || _b === void 0 ? void 0 : _b.id;
2044
+ const comments = await this.listTaskComments(userId, taskId);
2045
+ const createdComment = comments.find((comment) => comment.id === commentId);
2046
+ if (!createdComment) {
2047
+ throw new common_1.NotFoundException('Task comment could not be loaded.');
2048
+ }
2049
+ return createdComment;
2050
+ }
2051
+ async updateTaskComment(userId, taskId, commentId, content) {
2052
+ var _a, _b;
2053
+ const actor = await this.getActorContext(userId);
2054
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
2055
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
2056
+ }
2057
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
2058
+ await this.assertProjectAccess(actor, current.projectId);
2059
+ const normalizedContent = this.normalizeOptionalText(content);
2060
+ if (!normalizedContent) {
2061
+ throw new common_1.BadRequestException('Comment content is required.');
2062
+ }
2063
+ const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId", created_at AS "createdAt"
2064
+ FROM operations_task_comment
2065
+ WHERE id = $1 AND task_id = $2`, [commentId, taskId]);
2066
+ const row = rows[0];
2067
+ if (!row) {
2068
+ throw new common_1.NotFoundException('Comment not found.');
2069
+ }
2070
+ if (row.actorCollaboratorId !== actor.collaboratorId) {
2071
+ throw new common_1.ForbiddenException('You can only edit your own comments.');
2072
+ }
2073
+ const editSettings = await this.settingService.getSettingValues(['operations.comment-edit-window']);
2074
+ const editWindowMinutes = Number((_a = editSettings['operations.comment-edit-window']) !== null && _a !== void 0 ? _a : 5);
2075
+ if (editWindowMinutes > 0) {
2076
+ const diffMinutes = (Date.now() - new Date(row.createdAt).getTime()) / 60000;
2077
+ if (diffMinutes > editWindowMinutes) {
2078
+ throw new common_1.ForbiddenException(`Comments can only be edited within ${editWindowMinutes} minute(s) of posting.`);
2079
+ }
2080
+ }
2081
+ await this.queryRows(`UPDATE operations_task_comment
2082
+ SET content = $1, updated_at = NOW()
2083
+ WHERE id = $2`, [normalizedContent, commentId]);
2084
+ const comments = await this.listTaskComments(userId, taskId);
2085
+ return (_b = comments.find((c) => c.id === commentId)) !== null && _b !== void 0 ? _b : null;
2086
+ }
2087
+ async removeTaskComment(userId, taskId, commentId) {
2088
+ var _a;
2089
+ const actor = await this.getActorContext(userId);
2090
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
2091
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
2092
+ }
2093
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
2094
+ await this.assertProjectAccess(actor, current.projectId);
2095
+ const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId", created_at AS "createdAt"
2096
+ FROM operations_task_comment
2097
+ WHERE id = $1 AND task_id = $2`, [commentId, taskId]);
2098
+ const row = rows[0];
2099
+ if (!row) {
2100
+ throw new common_1.NotFoundException('Comment not found.');
2101
+ }
2102
+ if (row.actorCollaboratorId !== actor.collaboratorId) {
2103
+ throw new common_1.ForbiddenException('You can only delete your own comments.');
2104
+ }
2105
+ const deleteSettings = await this.settingService.getSettingValues(['operations.comment-edit-window']);
2106
+ const deleteWindowMinutes = Number((_a = deleteSettings['operations.comment-edit-window']) !== null && _a !== void 0 ? _a : 5);
2107
+ if (deleteWindowMinutes > 0) {
2108
+ const diffMinutes = (Date.now() - new Date(row.createdAt).getTime()) / 60000;
2109
+ if (diffMinutes > deleteWindowMinutes) {
2110
+ throw new common_1.ForbiddenException(`Comments can only be deleted within ${deleteWindowMinutes} minute(s) of posting.`);
2111
+ }
2112
+ }
2113
+ await this.queryRows(`DELETE FROM operations_task_comment WHERE id = $1`, [commentId]);
2114
+ return { success: true };
2115
+ }
1847
2116
  async listTimesheetEntries(userId, paginationParams) {
1848
2117
  var _a, _b;
1849
2118
  const actor = await this.getActorContext(userId);
@@ -2110,6 +2379,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
2110
2379
  return this.getProjectDetails(projectId, actor.collaboratorId);
2111
2380
  }
2112
2381
  async createProject(userId, data) {
2382
+ var _a;
2113
2383
  const actor = await this.getActorContext(userId);
2114
2384
  this.ensureDirector(actor);
2115
2385
  this.requireFields(data, ['code', 'name']);
@@ -2145,7 +2415,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
2145
2415
  }
2146
2416
  return projectId;
2147
2417
  });
2148
- return this.getProjectById(userId, createdProjectId);
2418
+ const result = await this.getProjectById(userId, createdProjectId);
2419
+ await this.integrationApi.publishEvent({
2420
+ eventName: 'operations.project.created',
2421
+ sourceModule: 'operations',
2422
+ aggregateType: 'project',
2423
+ aggregateId: String(createdProjectId),
2424
+ payload: { id: createdProjectId, code: data.code, name: data.name, status: (_a = data.status) !== null && _a !== void 0 ? _a : 'planning' },
2425
+ }).catch(() => null);
2426
+ return result;
2149
2427
  }
2150
2428
  async updateProject(userId, projectId, data) {
2151
2429
  const actor = await this.getActorContext(userId);
@@ -2198,7 +2476,15 @@ let OperationsService = OperationsService_1 = class OperationsService {
2198
2476
  }
2199
2477
  }
2200
2478
  });
2201
- return this.getProjectById(userId, projectId);
2479
+ const projectResult = await this.getProjectById(userId, projectId);
2480
+ await this.integrationApi.publishEvent({
2481
+ eventName: 'operations.project.updated',
2482
+ sourceModule: 'operations',
2483
+ aggregateType: 'project',
2484
+ aggregateId: String(projectId),
2485
+ payload: { id: projectId, name: data.name, status: data.status },
2486
+ }).catch(() => null);
2487
+ return projectResult;
2202
2488
  }
2203
2489
  async listContracts(userId, filters = {}) {
2204
2490
  var _a, _b;
@@ -3055,6 +3341,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
3055
3341
  if (filters.dateTo) {
3056
3342
  where.push(`t.week_start_date <= ${this.param(params, filters.dateTo)}::date`);
3057
3343
  }
3344
+ if (filters.collaboratorId) {
3345
+ where.push(`t.collaborator_id = ${this.param(params, filters.collaboratorId)}`);
3346
+ }
3058
3347
  if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
3059
3348
  const searchPlaceholder = this.param(params, `%${pagination.search}%`);
3060
3349
  where.push(`(
@@ -3088,7 +3377,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
3088
3377
  t.submitted_at AS "submittedAt",
3089
3378
  t.reviewed_at AS "reviewedAt",
3090
3379
  t.notes,
3091
- approval.decision_note AS "decisionNote"
3380
+ approval.decision_note AS "decisionNote",
3381
+ approval.id AS "approvalId"
3092
3382
  FROM operations_timesheet t
3093
3383
  JOIN operations_collaborator c ON c.id = t.collaborator_id
3094
3384
  LEFT JOIN operations_collaborator a ON a.id = t.approver_collaborator_id
@@ -4587,6 +4877,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
4587
4877
  COALESCE(NULLIF(job_title_record.name, ''), NULLIF(c.title, '')) AS "title",
4588
4878
  c.level_label AS "levelLabel",
4589
4879
  c.weekly_capacity_hours AS "weeklyCapacityHours",
4880
+ c.hourly_rate AS "hourlyRate",
4590
4881
  c.status,
4591
4882
  c.joined_at AS "joinedAt",
4592
4883
  c.left_at AS "leftAt",
@@ -4882,6 +5173,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
4882
5173
  au.photo_id AS "assigneeUserPhotoId",
4883
5174
  ap.avatar_id AS "assigneePersonAvatarId",
4884
5175
  t.project_assignment_id AS "projectAssignmentId",
5176
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
4885
5177
  t.created_at AS "createdAt"
4886
5178
  FROM operations_task t
4887
5179
  LEFT JOIN operations_collaborator ac
@@ -4890,6 +5182,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
4890
5182
  ON au.id = ac.user_id
4891
5183
  LEFT JOIN person ap
4892
5184
  ON ap.id = ac.person_id
5185
+ LEFT JOIN LATERAL (
5186
+ SELECT COUNT(*) AS count
5187
+ FROM operations_task_comment tc
5188
+ WHERE tc.task_id = t.id
5189
+ ) task_comments ON TRUE
4893
5190
  WHERE COALESCE(t.project_id, (
4894
5191
  SELECT pa.project_id FROM operations_project_assignment pa
4895
5192
  WHERE pa.id = t.project_assignment_id AND pa.deleted_at IS NULL
@@ -4916,6 +5213,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
4916
5213
  ap.avatar_id AS "assigneePersonAvatarId",
4917
5214
  t.project_assignment_id AS "projectAssignmentId",
4918
5215
  COALESCE(t.project_id, pa.project_id) AS "projectId",
5216
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
4919
5217
  t.created_at AS "createdAt",
4920
5218
  t.deleted_at AS "deletedAt"
4921
5219
  FROM operations_task t
@@ -4925,6 +5223,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
4925
5223
  LEFT JOIN person ap ON ap.id = ac.person_id
4926
5224
  LEFT JOIN operations_project_assignment pa
4927
5225
  ON pa.id = t.project_assignment_id AND pa.deleted_at IS NULL
5226
+ LEFT JOIN LATERAL (
5227
+ SELECT COUNT(*) AS count
5228
+ FROM operations_task_comment tc
5229
+ WHERE tc.task_id = t.id
5230
+ ) task_comments ON TRUE
4928
5231
  WHERE t.id = $1`, [taskId]);
4929
5232
  return (_a = rows[0]) !== null && _a !== void 0 ? _a : null;
4930
5233
  }
@@ -6031,16 +6334,18 @@ let OperationsService = OperationsService_1 = class OperationsService {
6031
6334
  $1, $2, $3, $4, $5, NOW()
6032
6335
  )`, contractId, actorUserId, action, note, metadataJson !== null && metadataJson !== void 0 ? metadataJson : null);
6033
6336
  }
6034
- async insertCollaboratorCompensationHistory(client, collaboratorId, amount, actorUserId, notes) {
6337
+ async insertCollaboratorCompensationHistory(client, collaboratorId, amount, actorUserId, notes, effectiveDate, amountType = 'salary') {
6035
6338
  await client.$executeRawUnsafe(`INSERT INTO operations_collaborator_compensation_history (
6036
6339
  collaborator_id,
6037
6340
  amount,
6038
6341
  actor_user_id,
6039
6342
  notes,
6343
+ effective_date,
6344
+ amount_type,
6040
6345
  created_at
6041
6346
  ) VALUES (
6042
- $1, $2, $3, $4, NOW()
6043
- )`, collaboratorId, amount, actorUserId, notes !== null && notes !== void 0 ? notes : null);
6347
+ $1, $2, $3, $4, $5::date, $6::operations_collaborator_compensation_history_am_f803c4196e_enum, NOW()
6348
+ )`, collaboratorId, amount, actorUserId, notes !== null && notes !== void 0 ? notes : null, effectiveDate !== null && effectiveDate !== void 0 ? effectiveDate : null, amountType);
6044
6349
  }
6045
6350
  async generateCollaboratorCode(client) {
6046
6351
  for (let attempt = 0; attempt < 5; attempt += 1) {
@@ -6919,12 +7224,18 @@ let OperationsService = OperationsService_1 = class OperationsService {
6919
7224
  au.photo_id AS "assigneeUserPhotoId",
6920
7225
  ap.avatar_id AS "assigneePersonAvatarId",
6921
7226
  t.project_assignment_id AS "projectAssignmentId",
7227
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
6922
7228
  t.created_at AS "createdAt"
6923
7229
  FROM operations_task t
6924
7230
  LEFT JOIN operations_collaborator ac
6925
7231
  ON ac.id = t.assignee_collaborator_id AND ac.deleted_at IS NULL
6926
7232
  LEFT JOIN "user" au ON au.id = ac.user_id
6927
7233
  LEFT JOIN person ap ON ap.id = ac.person_id
7234
+ LEFT JOIN LATERAL (
7235
+ SELECT COUNT(*) AS count
7236
+ FROM operations_task_comment tc
7237
+ WHERE tc.task_id = t.id
7238
+ ) task_comments ON TRUE
6928
7239
  WHERE COALESCE(t.project_id, (
6929
7240
  SELECT pa.project_id FROM operations_project_assignment pa
6930
7241
  WHERE pa.id = t.project_assignment_id AND pa.deleted_at IS NULL
@@ -6964,7 +7275,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
6964
7275
  )`,
6965
7276
  ];
6966
7277
  if (actor.collaboratorId) {
6967
- filters.push(`pa.collaborator_id = ${this.param(params, actor.collaboratorId)}`);
7278
+ const p1 = this.param(params, actor.collaboratorId);
7279
+ const p2 = this.param(params, actor.collaboratorId);
7280
+ filters.push(`(pa.collaborator_id = ${p1} OR t.assignee_collaborator_id = ${p2})`);
6968
7281
  }
6969
7282
  if (pagination.search) {
6970
7283
  const searchPlaceholder = this.param(params, `%${pagination.search}%`);
@@ -7010,6 +7323,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
7010
7323
  ac.display_name AS "assigneeName",
7011
7324
  au.photo_id AS "assigneeUserPhotoId",
7012
7325
  ap.avatar_id AS "assigneePersonAvatarId",
7326
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
7013
7327
  t.created_at AS "createdAt",
7014
7328
  t.deleted_at AS "deletedAt"
7015
7329
  FROM operations_task t
@@ -7022,6 +7336,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
7022
7336
  ON au.id = ac.user_id
7023
7337
  LEFT JOIN person ap
7024
7338
  ON ap.id = ac.person_id
7339
+ LEFT JOIN LATERAL (
7340
+ SELECT COUNT(*) AS count
7341
+ FROM operations_task_comment tc
7342
+ WHERE tc.task_id = t.id
7343
+ ) task_comments ON TRUE
7025
7344
  JOIN operations_project p
7026
7345
  ON p.id = COALESCE(t.project_id, pa.project_id)
7027
7346
  WHERE ${whereClause}
@@ -7173,7 +7492,12 @@ let OperationsService = OperationsService_1 = class OperationsService {
7173
7492
  : scenario === 'conservative'
7174
7493
  ? { revenue: 0.9, cost: 0.96, backlog: 0.82 }
7175
7494
  : { revenue: 1, cost: 1, backlog: 1 };
7176
- const params = [from, to];
7495
+ const fromDate = new Date(`${from}T00:00:00`);
7496
+ const toDate = new Date(`${to}T00:00:00`);
7497
+ const periodDays = Math.max(1, Math.floor((toDate.getTime() - fromDate.getTime()) / 86400000) + 1);
7498
+ const periodWeeks = Math.max(1, Math.ceil(periodDays / 7));
7499
+ const periodMonths = periodDays / 30.4375;
7500
+ const params = [from, to, periodMonths, periodWeeks];
7177
7501
  const where = [
7178
7502
  'p.deleted_at IS NULL',
7179
7503
  '(p.end_date IS NULL OR p.end_date >= $1::date)',
@@ -7196,6 +7520,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
7196
7520
  COALESCE(assignment_stats.weekly_hours, 0)::text AS "weeklyHours",
7197
7521
  COALESCE(time_stats.actual_hours, 0)::text AS "actualHours",
7198
7522
  COALESCE(time_stats.billable_hours, 0)::text AS "billableHours",
7523
+ COALESCE(cost_stats.realized_cost, 0)::text AS "realizedCost",
7524
+ COALESCE(alloc_cost_stats.allocated_cost, 0)::text AS "allocatedCost",
7199
7525
  COALESCE(task_stats.open_tasks, 0)::text AS "openTasks",
7200
7526
  COALESCE(task_stats.backlog_hours, 0)::text AS "backlogHours",
7201
7527
  COALESCE(task_stats.future_deliveries, 0)::text AS "futureDeliveries"
@@ -7224,6 +7550,146 @@ let OperationsService = OperationsService_1 = class OperationsService {
7224
7550
  AND entry.deleted_at IS NULL
7225
7551
  AND entry.work_date BETWEEN $1::date AND $2::date
7226
7552
  ) time_stats ON TRUE
7553
+ LEFT JOIN LATERAL (
7554
+ SELECT COALESCE(
7555
+ SUM(
7556
+ entry.hours
7557
+ * (
7558
+ (
7559
+ COALESCE(collaborator_costs.salary_cost, 0)
7560
+ + COALESCE(collaborator_costs.benefits_cost, 0)
7561
+ + COALESCE(collaborator_costs.taxes_cost, 0)
7562
+ + COALESCE(collaborator_costs.tools_cost, 0)
7563
+ )
7564
+ * $3::numeric
7565
+ / GREATEST(
7566
+ COALESCE(collaborator_record.weekly_capacity_hours, 40)::numeric * $4::numeric,
7567
+ COALESCE(collaborator_hours.total_hours, 0),
7568
+ 1
7569
+ )
7570
+ )
7571
+ ),
7572
+ 0
7573
+ ) AS realized_cost
7574
+ FROM operations_timesheet_entry entry
7575
+ JOIN operations_project_assignment pa
7576
+ ON pa.id = entry.project_assignment_id
7577
+ AND pa.deleted_at IS NULL
7578
+ JOIN operations_collaborator collaborator_record
7579
+ ON collaborator_record.id = pa.collaborator_id
7580
+ AND collaborator_record.deleted_at IS NULL
7581
+ LEFT JOIN LATERAL (
7582
+ SELECT COALESCE(NULLIF(cost_totals.salary_cost, 0), compensation_history.amount, hiring_contract.budget_amount, 0) AS salary_cost,
7583
+ cost_totals.benefits_cost,
7584
+ cost_totals.taxes_cost,
7585
+ cost_totals.tools_cost
7586
+ FROM (
7587
+ SELECT COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('salario-base', 'pro-labore')), 0) AS salary_cost,
7588
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('vale-refeicao', 'vale-alimentacao', 'vale-transporte', 'plano-saude', 'plano-odontologico', 'seguro-vida')), 0) AS benefits_cost,
7589
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('inss-patronal', 'fgts', 'rat-fap', 'terceiros-sistema-s', 'provisao-decimo-terceiro', 'provisao-ferias')), 0) AS taxes_cost,
7590
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('software-licenca', 'equipamento')), 0) AS tools_cost
7591
+ FROM operations_collaborator_cost cost
7592
+ LEFT JOIN operations_cost_type cost_type
7593
+ ON cost_type.id = cost.cost_type_id
7594
+ WHERE cost.collaborator_id = collaborator_record.id
7595
+ AND (cost.start_date IS NULL OR cost.start_date <= $2::date)
7596
+ AND (cost.end_date IS NULL OR cost.end_date >= $1::date)
7597
+ ) cost_totals
7598
+ LEFT JOIN LATERAL (
7599
+ SELECT h.amount
7600
+ FROM operations_collaborator_compensation_history h
7601
+ WHERE h.collaborator_id = collaborator_record.id
7602
+ AND (h.effective_date IS NULL OR h.effective_date <= $2::date)
7603
+ ORDER BY h.effective_date DESC NULLS LAST, h.created_at DESC
7604
+ LIMIT 1
7605
+ ) compensation_history ON TRUE
7606
+ LEFT JOIN LATERAL (
7607
+ SELECT oc.budget_amount
7608
+ FROM operations_contract oc
7609
+ WHERE oc.related_collaborator_id = collaborator_record.id
7610
+ AND oc.deleted_at IS NULL
7611
+ ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
7612
+ oc.created_at DESC
7613
+ LIMIT 1
7614
+ ) hiring_contract ON TRUE
7615
+ ) collaborator_costs ON TRUE
7616
+ LEFT JOIN LATERAL (
7617
+ SELECT COALESCE(SUM(entry2.hours), 0) AS total_hours
7618
+ FROM operations_timesheet_entry entry2
7619
+ JOIN operations_project_assignment pa2
7620
+ ON pa2.id = entry2.project_assignment_id
7621
+ AND pa2.deleted_at IS NULL
7622
+ WHERE pa2.collaborator_id = collaborator_record.id
7623
+ AND entry2.deleted_at IS NULL
7624
+ AND entry2.work_date BETWEEN $1::date AND $2::date
7625
+ ) collaborator_hours ON TRUE
7626
+ WHERE pa.project_id = p.id
7627
+ AND entry.deleted_at IS NULL
7628
+ AND entry.work_date BETWEEN $1::date AND $2::date
7629
+ ) cost_stats ON TRUE
7630
+ LEFT JOIN LATERAL (
7631
+ SELECT COALESCE(
7632
+ SUM(
7633
+ pa.weekly_hours
7634
+ * (
7635
+ (
7636
+ COALESCE(alloc_costs.salary_cost, 0)
7637
+ + COALESCE(alloc_costs.benefits_cost, 0)
7638
+ + COALESCE(alloc_costs.taxes_cost, 0)
7639
+ + COALESCE(alloc_costs.tools_cost, 0)
7640
+ )
7641
+ * $3::numeric
7642
+ / GREATEST(
7643
+ COALESCE(alloc_col.weekly_capacity_hours, 40)::numeric,
7644
+ 1
7645
+ )
7646
+ )
7647
+ ),
7648
+ 0
7649
+ ) AS allocated_cost
7650
+ FROM operations_project_assignment pa
7651
+ JOIN operations_collaborator alloc_col
7652
+ ON alloc_col.id = pa.collaborator_id
7653
+ AND alloc_col.deleted_at IS NULL
7654
+ LEFT JOIN LATERAL (
7655
+ SELECT COALESCE(NULLIF(ct.salary_cost, 0), ch.amount, hc.budget_amount, 0) AS salary_cost,
7656
+ ct.benefits_cost,
7657
+ ct.taxes_cost,
7658
+ ct.tools_cost
7659
+ FROM (
7660
+ SELECT COALESCE(SUM(c.amount) FILTER (WHERE c.recurrence::text = 'monthly' AND ct2.slug IN ('salario-base', 'pro-labore')), 0) AS salary_cost,
7661
+ COALESCE(SUM(c.amount) FILTER (WHERE c.recurrence::text = 'monthly' AND ct2.slug IN ('vale-refeicao', 'vale-alimentacao', 'vale-transporte', 'plano-saude', 'plano-odontologico', 'seguro-vida')), 0) AS benefits_cost,
7662
+ COALESCE(SUM(c.amount) FILTER (WHERE c.recurrence::text = 'monthly' AND ct2.slug IN ('inss-patronal', 'fgts', 'rat-fap', 'terceiros-sistema-s', 'provisao-decimo-terceiro', 'provisao-ferias')), 0) AS taxes_cost,
7663
+ COALESCE(SUM(c.amount) FILTER (WHERE c.recurrence::text = 'monthly' AND ct2.slug IN ('software-licenca', 'equipamento')), 0) AS tools_cost
7664
+ FROM operations_collaborator_cost c
7665
+ LEFT JOIN operations_cost_type ct2
7666
+ ON ct2.id = c.cost_type_id
7667
+ WHERE c.collaborator_id = alloc_col.id
7668
+ AND (c.start_date IS NULL OR c.start_date <= $2::date)
7669
+ AND (c.end_date IS NULL OR c.end_date >= $1::date)
7670
+ ) ct
7671
+ LEFT JOIN LATERAL (
7672
+ SELECT h.amount
7673
+ FROM operations_collaborator_compensation_history h
7674
+ WHERE h.collaborator_id = alloc_col.id
7675
+ AND (h.effective_date IS NULL OR h.effective_date <= $2::date)
7676
+ ORDER BY h.effective_date DESC NULLS LAST, h.created_at DESC
7677
+ LIMIT 1
7678
+ ) ch ON TRUE
7679
+ LEFT JOIN LATERAL (
7680
+ SELECT oc.budget_amount
7681
+ FROM operations_contract oc
7682
+ WHERE oc.related_collaborator_id = alloc_col.id
7683
+ AND oc.deleted_at IS NULL
7684
+ ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
7685
+ oc.created_at DESC
7686
+ LIMIT 1
7687
+ ) hc ON TRUE
7688
+ ) alloc_costs ON TRUE
7689
+ WHERE pa.project_id = p.id
7690
+ AND pa.deleted_at IS NULL
7691
+ AND pa.status IN ('planned', 'active')
7692
+ ) alloc_cost_stats ON TRUE
7227
7693
  LEFT JOIN LATERAL (
7228
7694
  SELECT COUNT(*) FILTER (WHERE task.status IN ('todo', 'doing', 'review')) AS open_tasks,
7229
7695
  COALESCE(SUM(task.estimate_hours) FILTER (WHERE task.status IN ('todo', 'doing', 'review')), 0) AS backlog_hours,
@@ -7234,18 +7700,20 @@ let OperationsService = OperationsService_1 = class OperationsService {
7234
7700
  ) task_stats ON TRUE
7235
7701
  WHERE ${where.join(' AND ')}
7236
7702
  ORDER BY p.name ASC`, params);
7237
- const fromDate = new Date(`${from}T00:00:00`);
7238
- const toDate = new Date(`${to}T00:00:00`);
7239
- const periodWeeks = Math.max(1, Math.ceil((toDate.getTime() - fromDate.getTime()) / 604800000));
7240
7703
  const rows = dbRows
7241
7704
  .map((row) => {
7242
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
7705
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
7243
7706
  const progress = Number((_a = row.progressPercent) !== null && _a !== void 0 ? _a : 0);
7244
7707
  const contractedRevenue = Number((_b = row.contractedRevenue) !== null && _b !== void 0 ? _b : 0);
7245
7708
  const recognizedRevenue = contractedRevenue * (progress / 100);
7246
7709
  const actualHours = Number((_c = row.actualHours) !== null && _c !== void 0 ? _c : 0);
7247
7710
  const plannedHours = Math.max(Number((_d = row.weeklyHours) !== null && _d !== void 0 ? _d : 0) * periodWeeks, actualHours);
7248
- const realizedCost = 0;
7711
+ const realizedCost = Number((_e = row.realizedCost) !== null && _e !== void 0 ? _e : 0);
7712
+ const allocatedCost = Number((_f = row.allocatedCost) !== null && _f !== void 0 ? _f : 0);
7713
+ const consumedHoursCost = realizedCost;
7714
+ const idlenessHours = Math.max(plannedHours - actualHours, 0);
7715
+ const idlenessRate = plannedHours > 0 ? (idlenessHours / plannedHours) * 100 : 0;
7716
+ const idlenessCost = Math.max(allocatedCost - consumedHoursCost, 0);
7249
7717
  const reportStatus = row.status === 'paused'
7250
7718
  ? 'paused'
7251
7719
  : row.status === 'at_risk'
@@ -7261,9 +7729,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
7261
7729
  return {
7262
7730
  id: Number(row.id),
7263
7731
  name: row.name,
7264
- client: (_e = row.client) !== null && _e !== void 0 ? _e : '-',
7265
- manager: (_f = row.manager) !== null && _f !== void 0 ? _f : '-',
7266
- squad: String((_g = row.squad) !== null && _g !== void 0 ? _g : '-').replace(/_/g, ' '),
7732
+ client: (_g = row.client) !== null && _g !== void 0 ? _g : '-',
7733
+ manager: (_h = row.manager) !== null && _h !== void 0 ? _h : '-',
7734
+ squad: String((_j = row.squad) !== null && _j !== void 0 ? _j : '-').replace(/_/g, ' '),
7267
7735
  status: reportStatus,
7268
7736
  contractType: row.contractType === 'monthly_retainer'
7269
7737
  ? 'retainer'
@@ -7276,7 +7744,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
7276
7744
  contractedRevenue,
7277
7745
  recognizedRevenue,
7278
7746
  realizedCost,
7279
- forecastCost: realizedCost,
7747
+ forecastCost: realizedCost * multiplier.cost,
7280
7748
  teamCost: realizedCost,
7281
7749
  infraCost: 0,
7282
7750
  licenseCost: 0,
@@ -7284,14 +7752,18 @@ let OperationsService = OperationsService_1 = class OperationsService {
7284
7752
  reworkCost: 0,
7285
7753
  plannedHours,
7286
7754
  actualHours,
7287
- billableHours: Number((_h = row.billableHours) !== null && _h !== void 0 ? _h : 0),
7755
+ billableHours: Number((_k = row.billableHours) !== null && _k !== void 0 ? _k : 0),
7288
7756
  reworkHours: 0,
7289
- internalHours: Math.max(actualHours - Number((_j = row.billableHours) !== null && _j !== void 0 ? _j : 0), 0),
7757
+ internalHours: Math.max(actualHours - Number((_l = row.billableHours) !== null && _l !== void 0 ? _l : 0), 0),
7290
7758
  allocatedCapacity: plannedHours ? (actualHours / plannedHours) * 100 : 0,
7291
7759
  physicalProgress: progress,
7292
7760
  financialProgress: contractedRevenue ? (recognizedRevenue / contractedRevenue) * 100 : 0,
7293
7761
  backlogValue: Math.max(contractedRevenue - recognizedRevenue, 0),
7294
- futureDeliveries: Number((_k = row.futureDeliveries) !== null && _k !== void 0 ? _k : 0),
7762
+ futureDeliveries: Number((_m = row.futureDeliveries) !== null && _m !== void 0 ? _m : 0),
7763
+ allocatedCost,
7764
+ consumedHoursCost,
7765
+ idlenessRate,
7766
+ idlenessCost,
7295
7767
  risk,
7296
7768
  recommendation: risk === 'alto'
7297
7769
  ? 'Revisar escopo, prazo ou capacidade alocada.'
@@ -7314,6 +7786,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
7314
7786
  acc.avgDeadline += row.physicalProgress;
7315
7787
  acc.avgAllocation += row.allocatedCapacity;
7316
7788
  acc.atRisk += row.risk === 'alto' ? 1 : 0;
7789
+ acc.allocatedCost += row.allocatedCost;
7790
+ acc.consumedHoursCost += row.consumedHoursCost;
7791
+ acc.idlenessCost += row.idlenessCost;
7317
7792
  return acc;
7318
7793
  }, {
7319
7794
  contractedRevenue: 0,
@@ -7331,12 +7806,21 @@ let OperationsService = OperationsService_1 = class OperationsService {
7331
7806
  avgAllocation: 0,
7332
7807
  atRisk: 0,
7333
7808
  burnRate: 0,
7809
+ allocatedCost: 0,
7810
+ consumedHoursCost: 0,
7811
+ idlenessCost: 0,
7812
+ idlenessRate: 0,
7813
+ plannedProfit: 0,
7334
7814
  });
7335
7815
  summary.profit = summary.recognizedRevenue - summary.realizedCost;
7336
7816
  summary.margin = summary.recognizedRevenue ? (summary.profit / summary.recognizedRevenue) * 100 : 0;
7337
7817
  summary.avgDeadline = rows.length ? summary.avgDeadline / rows.length : 0;
7338
7818
  summary.avgAllocation = rows.length ? summary.avgAllocation / rows.length : 0;
7339
7819
  summary.burnRate = summary.plannedHours ? (summary.actualHours / summary.plannedHours) * 100 : 0;
7820
+ summary.plannedProfit = summary.contractedRevenue - summary.allocatedCost;
7821
+ summary.idlenessRate = summary.plannedHours > 0
7822
+ ? Math.max(0, (summary.plannedHours - summary.actualHours) / summary.plannedHours * 100)
7823
+ : 0;
7340
7824
  const forecast = Array.from({ length: 12 }, (_, index) => {
7341
7825
  const monthDate = new Date(fromDate);
7342
7826
  monthDate.setMonth(fromDate.getMonth() + index);
@@ -7425,6 +7909,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
7425
7909
  : scenario === 'conservative'
7426
7910
  ? { revenue: 0.9, cost: 0.96, capacity: 0.94 }
7427
7911
  : { revenue: 1, cost: 1, capacity: 1 };
7912
+ const fromDate = new Date(`${from}T00:00:00`);
7913
+ const toDate = new Date(`${to}T00:00:00`);
7914
+ const periodDays = Math.max(1, Math.floor((toDate.getTime() - fromDate.getTime()) / 86400000) + 1);
7915
+ const periodWeeks = Math.max(1, Math.ceil(periodDays / 7));
7916
+ const periodMonths = periodDays / 30.4375;
7428
7917
  const params = [from, to];
7429
7918
  const where = [
7430
7919
  'c.deleted_at IS NULL',
@@ -7451,9 +7940,14 @@ let OperationsService = OperationsService_1 = class OperationsService {
7451
7940
  COALESCE(cost_stats.taxes_cost, 0)::text AS "taxesCost",
7452
7941
  COALESCE(cost_stats.tools_cost, 0)::text AS "toolsCost",
7453
7942
  COALESCE(value_stats.billable_value, 0)::text AS "billableValue",
7943
+ COALESCE(assignment_stats.planned_allocated_hours, 0)::text AS "plannedAllocatedHours",
7944
+ COALESCE(assignment_stats.planned_billable_hours, 0)::text AS "plannedBillableHours",
7945
+ COALESCE(task_stats.open_task_hours, 0)::text AS "openTaskHours",
7946
+ COALESCE(task_stats.open_task_billable_hours, 0)::text AS "openTaskBillableHours",
7947
+ COALESCE(task_stats.open_tasks, 0)::text AS "openTasks",
7454
7948
  COALESCE(value_stats.allocated_hours, 0)::text AS "allocatedHours",
7455
7949
  COALESCE(value_stats.billable_hours, 0)::text AS "billableHours",
7456
- COALESCE(project_stats.projects, 0)::text AS projects
7950
+ COALESCE(assignment_stats.projects, 0)::text AS projects
7457
7951
  FROM operations_collaborator c
7458
7952
  LEFT JOIN person person_record ON person_record.id = c.person_id
7459
7953
  LEFT JOIN operations_department department_record
@@ -7466,16 +7960,85 @@ let OperationsService = OperationsService_1 = class OperationsService {
7466
7960
  ON collaborator_type.id = c.collaborator_type_id
7467
7961
  AND collaborator_type.deleted_at IS NULL
7468
7962
  LEFT JOIN LATERAL (
7469
- SELECT COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('salario-base', 'pro-labore')), 0) AS salary_cost,
7470
- COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('vale-refeicao', 'vale-alimentacao', 'vale-transporte', 'plano-saude', 'plano-odontologico', 'seguro-vida')), 0) AS benefits_cost,
7471
- COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('inss-patronal', 'fgts', 'rat-fap', 'terceiros-sistema-s', 'provisao-decimo-terceiro', 'provisao-ferias')), 0) AS taxes_cost,
7472
- COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('software-licenca', 'equipamento')), 0) AS tools_cost
7473
- FROM operations_collaborator_cost cost
7474
- LEFT JOIN operations_cost_type cost_type ON cost_type.id = cost.cost_type_id
7475
- WHERE cost.collaborator_id = c.id
7476
- AND (cost.start_date IS NULL OR cost.start_date <= $2::date)
7477
- AND (cost.end_date IS NULL OR cost.end_date >= $1::date)
7963
+ SELECT COALESCE(NULLIF(cost_totals.salary_cost, 0), compensation_history.amount, hiring_contract.budget_amount, 0) AS salary_cost,
7964
+ cost_totals.benefits_cost,
7965
+ cost_totals.taxes_cost,
7966
+ cost_totals.tools_cost
7967
+ FROM (
7968
+ SELECT COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('salario-base', 'pro-labore')), 0) AS salary_cost,
7969
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('vale-refeicao', 'vale-alimentacao', 'vale-transporte', 'plano-saude', 'plano-odontologico', 'seguro-vida')), 0) AS benefits_cost,
7970
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('inss-patronal', 'fgts', 'rat-fap', 'terceiros-sistema-s', 'provisao-decimo-terceiro', 'provisao-ferias')), 0) AS taxes_cost,
7971
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('software-licenca', 'equipamento')), 0) AS tools_cost
7972
+ FROM operations_collaborator_cost cost
7973
+ LEFT JOIN operations_cost_type cost_type
7974
+ ON cost_type.id = cost.cost_type_id
7975
+ WHERE cost.collaborator_id = c.id
7976
+ AND (cost.start_date IS NULL OR cost.start_date <= $2::date)
7977
+ AND (cost.end_date IS NULL OR cost.end_date >= $1::date)
7978
+ ) cost_totals
7979
+ LEFT JOIN LATERAL (
7980
+ SELECT h.amount
7981
+ FROM operations_collaborator_compensation_history h
7982
+ WHERE h.collaborator_id = c.id
7983
+ AND (h.effective_date IS NULL OR h.effective_date <= $2::date)
7984
+ ORDER BY h.effective_date DESC NULLS LAST, h.created_at DESC
7985
+ LIMIT 1
7986
+ ) compensation_history ON TRUE
7987
+ LEFT JOIN LATERAL (
7988
+ SELECT oc.budget_amount
7989
+ FROM operations_contract oc
7990
+ WHERE oc.related_collaborator_id = c.id
7991
+ AND oc.deleted_at IS NULL
7992
+ ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
7993
+ oc.created_at DESC
7994
+ LIMIT 1
7995
+ ) hiring_contract ON TRUE
7478
7996
  ) cost_stats ON TRUE
7997
+ LEFT JOIN LATERAL (
7998
+ SELECT COALESCE(
7999
+ SUM(
8000
+ COALESCE(
8001
+ pa.weekly_hours,
8002
+ COALESCE(c.weekly_capacity_hours, 40) * COALESCE(pa.allocation_percent, 0) / 100
8003
+ ) * GREATEST(
8004
+ CEIL(
8005
+ (
8006
+ LEAST(COALESCE(pa.end_date, $2::date), $2::date)
8007
+ - GREATEST(COALESCE(pa.start_date, $1::date), $1::date)
8008
+ + 1
8009
+ ) / 7.0
8010
+ ),
8011
+ 0
8012
+ )
8013
+ ),
8014
+ 0
8015
+ ) AS planned_allocated_hours,
8016
+ COALESCE(
8017
+ SUM(
8018
+ COALESCE(
8019
+ pa.weekly_hours,
8020
+ COALESCE(c.weekly_capacity_hours, 40) * COALESCE(pa.allocation_percent, 0) / 100
8021
+ ) * GREATEST(
8022
+ CEIL(
8023
+ (
8024
+ LEAST(COALESCE(pa.end_date, $2::date), $2::date)
8025
+ - GREATEST(COALESCE(pa.start_date, $1::date), $1::date)
8026
+ + 1
8027
+ ) / 7.0
8028
+ ),
8029
+ 0
8030
+ )
8031
+ ) FILTER (WHERE pa.is_billable = true),
8032
+ 0
8033
+ ) AS planned_billable_hours,
8034
+ COUNT(DISTINCT pa.project_id) AS projects
8035
+ FROM operations_project_assignment pa
8036
+ WHERE pa.collaborator_id = c.id
8037
+ AND pa.deleted_at IS NULL
8038
+ AND pa.status IN ('planned', 'active')
8039
+ AND (pa.start_date IS NULL OR pa.start_date <= $2::date)
8040
+ AND (pa.end_date IS NULL OR pa.end_date >= $1::date)
8041
+ ) assignment_stats ON TRUE
7479
8042
  LEFT JOIN LATERAL (
7480
8043
  SELECT COALESCE(SUM(entry.hours), 0) AS allocated_hours,
7481
8044
  COALESCE(SUM(entry.hours) FILTER (WHERE pa.is_billable = true), 0) AS billable_hours,
@@ -7489,48 +8052,62 @@ let OperationsService = OperationsService_1 = class OperationsService {
7489
8052
  AND entry.work_date BETWEEN $1::date AND $2::date
7490
8053
  ) value_stats ON TRUE
7491
8054
  LEFT JOIN LATERAL (
7492
- SELECT COUNT(DISTINCT pa.project_id) AS projects
7493
- FROM operations_project_assignment pa
7494
- WHERE pa.collaborator_id = c.id
8055
+ SELECT COUNT(*) AS open_tasks,
8056
+ COALESCE(SUM(COALESCE(task.estimate_hours, 0)), 0) AS open_task_hours,
8057
+ COALESCE(
8058
+ SUM(COALESCE(task.estimate_hours, 0)) FILTER (WHERE pa.is_billable = true),
8059
+ 0
8060
+ ) AS open_task_billable_hours
8061
+ FROM operations_task task
8062
+ LEFT JOIN operations_project_assignment pa
8063
+ ON pa.id = task.project_assignment_id
7495
8064
  AND pa.deleted_at IS NULL
7496
- AND pa.status IN ('planned', 'active')
7497
- ) project_stats ON TRUE
8065
+ WHERE task.deleted_at IS NULL
8066
+ AND task.status IN ('todo', 'doing', 'review')
8067
+ AND (
8068
+ task.assignee_collaborator_id = c.id
8069
+ OR pa.collaborator_id = c.id
8070
+ )
8071
+ ) task_stats ON TRUE
7498
8072
  WHERE ${where.join(' AND ')}
7499
8073
  ORDER BY name ASC`, params);
7500
- const fromDate = new Date(`${from}T00:00:00`);
7501
- const toDate = new Date(`${to}T00:00:00`);
7502
- const periodWeeks = Math.max(1, Math.ceil((toDate.getTime() - fromDate.getTime()) / 604800000));
7503
8074
  const rows = dbRows.map((row) => {
7504
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
7505
- const salaryCost = Number((_a = row.salaryCost) !== null && _a !== void 0 ? _a : 0);
7506
- const benefitsCost = Number((_b = row.benefitsCost) !== null && _b !== void 0 ? _b : 0);
7507
- const taxesCost = Number((_c = row.taxesCost) !== null && _c !== void 0 ? _c : 0);
7508
- const toolsCost = Number((_d = row.toolsCost) !== null && _d !== void 0 ? _d : 0);
8075
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
8076
+ const salaryCost = Number((_a = row.salaryCost) !== null && _a !== void 0 ? _a : 0) * periodMonths;
8077
+ const benefitsCost = Number((_b = row.benefitsCost) !== null && _b !== void 0 ? _b : 0) * periodMonths;
8078
+ const taxesCost = Number((_c = row.taxesCost) !== null && _c !== void 0 ? _c : 0) * periodMonths;
8079
+ const toolsCost = Number((_d = row.toolsCost) !== null && _d !== void 0 ? _d : 0) * periodMonths;
7509
8080
  const availableHours = Number((_e = row.weeklyCapacityHours) !== null && _e !== void 0 ? _e : 40) * periodWeeks;
7510
- const allocatedHours = Number((_f = row.allocatedHours) !== null && _f !== void 0 ? _f : 0);
7511
- const billableHours = Number((_g = row.billableHours) !== null && _g !== void 0 ? _g : 0);
8081
+ const plannedAllocatedHours = Number((_f = row.plannedAllocatedHours) !== null && _f !== void 0 ? _f : 0);
8082
+ const plannedBillableHours = Number((_g = row.plannedBillableHours) !== null && _g !== void 0 ? _g : 0);
8083
+ const openTaskHours = Number((_h = row.openTaskHours) !== null && _h !== void 0 ? _h : 0);
8084
+ const openTaskBillableHours = Number((_j = row.openTaskBillableHours) !== null && _j !== void 0 ? _j : 0);
8085
+ const actualAllocatedHours = Number((_k = row.allocatedHours) !== null && _k !== void 0 ? _k : 0);
8086
+ const actualBillableHours = Number((_l = row.billableHours) !== null && _l !== void 0 ? _l : 0);
8087
+ const allocatedHours = Math.max(actualAllocatedHours, plannedAllocatedHours, openTaskHours);
8088
+ const billableHours = Math.max(actualBillableHours, plannedBillableHours, openTaskBillableHours);
7512
8089
  const allocation = availableHours ? (allocatedHours / availableHours) * 100 : 0;
7513
8090
  const risk = allocation >= 98 ? 'alto' : allocation < 75 ? 'médio' : 'baixo';
7514
8091
  return {
7515
8092
  id: Number(row.id),
7516
8093
  name: row.name,
7517
- role: (_h = row.role) !== null && _h !== void 0 ? _h : '-',
7518
- seniority: (_j = row.seniority) !== null && _j !== void 0 ? _j : '-',
7519
- department: (_k = row.department) !== null && _k !== void 0 ? _k : '-',
7520
- contractType: (_l = row.contractType) !== null && _l !== void 0 ? _l : '-',
8094
+ role: (_m = row.role) !== null && _m !== void 0 ? _m : '-',
8095
+ seniority: (_o = row.seniority) !== null && _o !== void 0 ? _o : '-',
8096
+ department: (_p = row.department) !== null && _p !== void 0 ? _p : '-',
8097
+ contractType: (_q = row.contractType) !== null && _q !== void 0 ? _q : '-',
7521
8098
  startDate: row.startDate,
7522
8099
  endDate: row.endDate,
7523
8100
  salaryCost,
7524
8101
  benefitsCost,
7525
8102
  taxesCost,
7526
8103
  toolsCost,
7527
- billableValue: Number((_m = row.billableValue) !== null && _m !== void 0 ? _m : 0),
8104
+ billableValue: Number((_r = row.billableValue) !== null && _r !== void 0 ? _r : 0),
7528
8105
  availableHours,
7529
8106
  allocatedHours,
7530
8107
  billableHours,
7531
8108
  internalHours: Math.max(allocatedHours - billableHours, 0),
7532
8109
  overtimeHours: Math.max(allocatedHours - availableHours, 0),
7533
- projects: Number((_o = row.projects) !== null && _o !== void 0 ? _o : 0),
8110
+ projects: Number((_s = row.projects) !== null && _s !== void 0 ? _s : 0),
7534
8111
  risk,
7535
8112
  recommendation: risk === 'alto'
7536
8113
  ? 'Reduzir sobrecarga ou redistribuir entregas.'
@@ -7578,7 +8155,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
7578
8155
  summary.freeHours = Math.max(summary.availableHours - summary.allocatedHours, 0);
7579
8156
  summary.allocation = summary.availableHours ? (summary.allocatedHours / summary.availableHours) * 100 : 0;
7580
8157
  summary.utilization = summary.availableHours ? (summary.billableHours / summary.availableHours) * 100 : 0;
7581
- summary.hourlyCost = summary.allocatedHours ? summary.cost / summary.allocatedHours : 0;
8158
+ summary.hourlyCost = summary.allocatedHours
8159
+ ? summary.cost / summary.allocatedHours
8160
+ : summary.availableHours
8161
+ ? summary.cost / summary.availableHours
8162
+ : 0;
7582
8163
  const forecast = Array.from({ length: 12 }, (_, index) => {
7583
8164
  const monthDate = new Date(fromDate);
7584
8165
  monthDate.setMonth(fromDate.getMonth() + index);
@@ -7764,6 +8345,1149 @@ let OperationsService = OperationsService_1 = class OperationsService {
7764
8345
  await this.prisma.$queryRawUnsafe(`DELETE FROM operations_collaborator_cost WHERE id = $1`, costId);
7765
8346
  return { success: true };
7766
8347
  }
8348
+ // ──────────────────────────────────────────────────────────────────────────
8349
+ // Project Cost Categories
8350
+ // ──────────────────────────────────────────────────────────────────────────
8351
+ async listProjectCostCategories(userId, filters = {}) {
8352
+ var _a;
8353
+ await this.getActorContext(userId);
8354
+ const localeId = await this.resolvePreferredLocaleId();
8355
+ const params = [localeId];
8356
+ const where = ['pcc.deleted_at IS NULL'];
8357
+ if (filters.is_active === true) {
8358
+ where.push('pcc.is_active = true');
8359
+ }
8360
+ if ((_a = filters.search) === null || _a === void 0 ? void 0 : _a.trim()) {
8361
+ const p = this.param(params, `%${filters.search.trim()}%`);
8362
+ where.push(`(COALESCE(pccl.name, pcc.slug) ILIKE ${p} OR COALESCE(pcc.slug, '') ILIKE ${p})`);
8363
+ }
8364
+ const whereClause = `WHERE ${where.join(' AND ')}`;
8365
+ return this.queryRows(`SELECT pcc.id,
8366
+ pcc.slug,
8367
+ COALESCE(pccl.name, pcc.slug) AS name,
8368
+ pccl.description,
8369
+ pcc.icon,
8370
+ pcc.color,
8371
+ pcc.is_active AS "isActive",
8372
+ pcc.sort_order AS "sortOrder",
8373
+ pcc.created_at AS "createdAt"
8374
+ FROM operations_project_cost_category pcc
8375
+ LEFT JOIN LATERAL (
8376
+ SELECT l.name, l.description
8377
+ FROM operations_project_cost_category_locale l
8378
+ WHERE l.operations_project_cost_category_id = pcc.id
8379
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8380
+ l.id ASC
8381
+ LIMIT 1
8382
+ ) pccl ON TRUE
8383
+ ${whereClause}
8384
+ ORDER BY pcc.sort_order ASC, COALESCE(pccl.name, pcc.slug) ASC`, params);
8385
+ }
8386
+ async createProjectCostCategory(userId, data) {
8387
+ var _a;
8388
+ const actor = await this.getActorContext(userId);
8389
+ this.ensureDirector(actor);
8390
+ const slug = (_a = data.slug) === null || _a === void 0 ? void 0 : _a.trim();
8391
+ if (!slug) {
8392
+ throw new common_1.BadRequestException('Cost category slug is required.');
8393
+ }
8394
+ return this.prisma.$transaction(async (tx) => {
8395
+ var _a, _b, _c, _d, _e, _f;
8396
+ const localeId = await this.resolvePreferredLocaleId(tx);
8397
+ const created = (await tx.$queryRawUnsafe(`INSERT INTO operations_project_cost_category (slug, icon, color, is_active, sort_order, created_at, updated_at)
8398
+ VALUES ($1, $2, $3, $4, $5, NOW(), NOW())
8399
+ RETURNING id`, slug, (_a = data.icon) !== null && _a !== void 0 ? _a : null, (_b = data.color) !== null && _b !== void 0 ? _b : null, (_c = data.is_active) !== null && _c !== void 0 ? _c : true, (_d = data.sort_order) !== null && _d !== void 0 ? _d : 0));
8400
+ const createdId = (_e = created[0]) === null || _e === void 0 ? void 0 : _e.id;
8401
+ if (!createdId) {
8402
+ throw new common_1.BadRequestException('Unable to create project cost category.');
8403
+ }
8404
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : slug);
8405
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8406
+ if (localeId && name) {
8407
+ await tx.$executeRawUnsafe(`INSERT INTO operations_project_cost_category_locale (operations_project_cost_category_id, locale_id, name, description)
8408
+ VALUES ($1, $2, $3, $4)`, createdId, localeId, name, description !== null && description !== void 0 ? description : null);
8409
+ }
8410
+ const rows = (await tx.$queryRawUnsafe(`SELECT pcc.id,
8411
+ pcc.slug,
8412
+ COALESCE(pccl.name, pcc.slug) AS name,
8413
+ pccl.description,
8414
+ pcc.icon,
8415
+ pcc.color,
8416
+ pcc.is_active AS "isActive",
8417
+ pcc.sort_order AS "sortOrder",
8418
+ pcc.created_at AS "createdAt"
8419
+ FROM operations_project_cost_category pcc
8420
+ LEFT JOIN operations_project_cost_category_locale pccl
8421
+ ON pccl.operations_project_cost_category_id = pcc.id AND pccl.locale_id = $2
8422
+ WHERE pcc.id = $1`, createdId, localeId));
8423
+ return (_f = rows[0]) !== null && _f !== void 0 ? _f : null;
8424
+ });
8425
+ }
8426
+ async updateProjectCostCategory(userId, id, data) {
8427
+ const actor = await this.getActorContext(userId);
8428
+ this.ensureDirector(actor);
8429
+ const category = await this.querySingle(`SELECT id FROM operations_project_cost_category WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8430
+ if (!category) {
8431
+ throw new common_1.NotFoundException('Project cost category not found.');
8432
+ }
8433
+ const sets = [];
8434
+ const params = [];
8435
+ if (data.slug !== undefined)
8436
+ sets.push(`slug = ${this.param(params, data.slug)}`);
8437
+ if (data.icon !== undefined)
8438
+ sets.push(`icon = ${this.param(params, data.icon)}`);
8439
+ if (data.color !== undefined)
8440
+ sets.push(`color = ${this.param(params, data.color)}`);
8441
+ if (data.is_active !== undefined)
8442
+ sets.push(`is_active = ${this.param(params, data.is_active)}`);
8443
+ if (data.sort_order !== undefined)
8444
+ sets.push(`sort_order = ${this.param(params, data.sort_order)}`);
8445
+ if (sets.length > 0) {
8446
+ sets.push(`updated_at = NOW()`);
8447
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_category SET ${sets.join(', ')} WHERE id = ${this.param(params, id)}`, ...params);
8448
+ }
8449
+ if (data.name !== undefined || data.description !== undefined) {
8450
+ const localeId = await this.resolvePreferredLocaleId();
8451
+ if (localeId) {
8452
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : undefined);
8453
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8454
+ const existing = await this.querySingle(`SELECT id FROM operations_project_cost_category_locale WHERE operations_project_cost_category_id = $1 AND locale_id = $2 LIMIT 1`, [id, localeId]);
8455
+ if (existing) {
8456
+ const localeSets = [];
8457
+ const localeParams = [];
8458
+ if (name !== undefined)
8459
+ localeSets.push(`name = ${this.param(localeParams, name)}`);
8460
+ if (description !== undefined)
8461
+ localeSets.push(`description = ${this.param(localeParams, description)}`);
8462
+ if (localeSets.length > 0) {
8463
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_category_locale SET ${localeSets.join(', ')} WHERE operations_project_cost_category_id = ${this.param(localeParams, id)} AND locale_id = ${this.param(localeParams, localeId)}`, ...localeParams);
8464
+ }
8465
+ }
8466
+ else if (name) {
8467
+ await this.prisma.$queryRawUnsafe(`INSERT INTO operations_project_cost_category_locale (operations_project_cost_category_id, locale_id, name, description) VALUES ($1, $2, $3, $4)`, id, localeId, name, description !== null && description !== void 0 ? description : null);
8468
+ }
8469
+ }
8470
+ }
8471
+ return this.querySingle(`SELECT id, slug FROM operations_project_cost_category WHERE id = $1`, [id]);
8472
+ }
8473
+ async deleteProjectCostCategory(userId, id) {
8474
+ const actor = await this.getActorContext(userId);
8475
+ this.ensureDirector(actor);
8476
+ const category = await this.querySingle(`SELECT id FROM operations_project_cost_category WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8477
+ if (!category) {
8478
+ throw new common_1.NotFoundException('Project cost category not found.');
8479
+ }
8480
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_category SET deleted_at = NOW() WHERE id = $1`, id);
8481
+ return { success: true };
8482
+ }
8483
+ async getProjectCostCategory(userId, id) {
8484
+ await this.getActorContext(userId);
8485
+ const localeId = await this.resolvePreferredLocaleId();
8486
+ const row = await this.querySingle(`SELECT pcc.id,
8487
+ pcc.slug,
8488
+ COALESCE(pccl.name, pcc.slug) AS name,
8489
+ pccl.description,
8490
+ pcc.icon,
8491
+ pcc.color,
8492
+ pcc.is_active AS "isActive",
8493
+ pcc.sort_order AS "sortOrder",
8494
+ pcc.created_at AS "createdAt"
8495
+ FROM operations_project_cost_category pcc
8496
+ LEFT JOIN LATERAL (
8497
+ SELECT l.name, l.description
8498
+ FROM operations_project_cost_category_locale l
8499
+ WHERE l.operations_project_cost_category_id = pcc.id
8500
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8501
+ l.id ASC
8502
+ LIMIT 1
8503
+ ) pccl ON TRUE
8504
+ WHERE pcc.id = $2 AND pcc.deleted_at IS NULL`, [localeId, id]);
8505
+ if (!row) {
8506
+ throw new common_1.NotFoundException('Project cost category not found.');
8507
+ }
8508
+ return row;
8509
+ }
8510
+ // ──────────────────────────────────────────────────────────────────────────
8511
+ // Project Cost Types
8512
+ // ──────────────────────────────────────────────────────────────────────────
8513
+ async listProjectCostTypes(userId, filters = {}) {
8514
+ var _a;
8515
+ await this.getActorContext(userId);
8516
+ const localeId = await this.resolvePreferredLocaleId();
8517
+ const params = [localeId];
8518
+ const where = ['pct.deleted_at IS NULL'];
8519
+ if (filters.is_active === true) {
8520
+ where.push('pct.is_active = true');
8521
+ }
8522
+ if (filters.category_id) {
8523
+ where.push(`pct.category_id = ${this.param(params, filters.category_id)}`);
8524
+ }
8525
+ if (filters.default_calculation_type) {
8526
+ where.push(`pct.default_calculation_type = ${this.param(params, filters.default_calculation_type)}`);
8527
+ }
8528
+ if ((_a = filters.search) === null || _a === void 0 ? void 0 : _a.trim()) {
8529
+ const p = this.param(params, `%${filters.search.trim()}%`);
8530
+ where.push(`(COALESCE(pctl.name, pct.slug) ILIKE ${p} OR COALESCE(pct.code, '') ILIKE ${p} OR COALESCE(pct.slug, '') ILIKE ${p})`);
8531
+ }
8532
+ const whereClause = `WHERE ${where.join(' AND ')}`;
8533
+ return this.queryRows(`SELECT pct.id,
8534
+ pct.slug,
8535
+ pct.code,
8536
+ COALESCE(pctl.name, pct.slug) AS name,
8537
+ pctl.description,
8538
+ pct.category_id AS "categoryId",
8539
+ pcc.slug AS "categorySlug",
8540
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
8541
+ pct.default_unit AS "defaultUnit",
8542
+ pct.default_calculation_type AS "defaultCalculationType",
8543
+ pct.is_recurring_allowed AS "isRecurringAllowed",
8544
+ pct.is_active AS "isActive",
8545
+ pct.sort_order AS "sortOrder",
8546
+ pct.created_at AS "createdAt"
8547
+ FROM operations_project_cost_type pct
8548
+ LEFT JOIN operations_project_cost_category pcc
8549
+ ON pcc.id = pct.category_id AND pcc.deleted_at IS NULL
8550
+ LEFT JOIN LATERAL (
8551
+ SELECT l.name, l.description
8552
+ FROM operations_project_cost_category_locale l
8553
+ WHERE l.operations_project_cost_category_id = pcc.id
8554
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8555
+ l.id ASC
8556
+ LIMIT 1
8557
+ ) pccl ON TRUE
8558
+ LEFT JOIN LATERAL (
8559
+ SELECT l.name, l.description
8560
+ FROM operations_project_cost_type_locale l
8561
+ WHERE l.operations_project_cost_type_id = pct.id
8562
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8563
+ l.id ASC
8564
+ LIMIT 1
8565
+ ) pctl ON TRUE
8566
+ ${whereClause}
8567
+ ORDER BY pct.sort_order ASC, COALESCE(pctl.name, pct.slug) ASC`, params);
8568
+ }
8569
+ async createProjectCostType(userId, data) {
8570
+ var _a, _b, _c;
8571
+ const actor = await this.getActorContext(userId);
8572
+ this.ensureDirector(actor);
8573
+ const slug = (_a = data.slug) === null || _a === void 0 ? void 0 : _a.trim();
8574
+ if (!slug) {
8575
+ throw new common_1.BadRequestException('Cost type slug is required.');
8576
+ }
8577
+ if (data.category_id) {
8578
+ const category = await this.querySingle(`SELECT id FROM operations_project_cost_category WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [data.category_id]);
8579
+ if (!category) {
8580
+ throw new common_1.BadRequestException(`Category with id ${data.category_id} not found.`);
8581
+ }
8582
+ }
8583
+ const existingSlug = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE slug = $1 AND deleted_at IS NULL LIMIT 1`, [slug]);
8584
+ if (existingSlug) {
8585
+ throw new common_1.ConflictException(`A cost type with slug '${slug}' already exists.`);
8586
+ }
8587
+ const code = (_c = (_b = data.code) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : slug;
8588
+ const existingCode = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE code = $1 AND deleted_at IS NULL LIMIT 1`, [code]);
8589
+ if (existingCode) {
8590
+ throw new common_1.ConflictException(`A cost type with code '${code}' already exists.`);
8591
+ }
8592
+ return this.prisma.$transaction(async (tx) => {
8593
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
8594
+ const localeId = await this.resolvePreferredLocaleId(tx);
8595
+ const created = (await tx.$queryRawUnsafe(`INSERT INTO operations_project_cost_type (category_id, slug, code, default_unit, default_calculation_type, is_recurring_allowed, is_active, sort_order, created_at, updated_at)
8596
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
8597
+ RETURNING id`, (_a = data.category_id) !== null && _a !== void 0 ? _a : null, slug, (_c = (_b = data.code) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : slug, (_d = data.default_unit) !== null && _d !== void 0 ? _d : null, (_e = data.default_calculation_type) !== null && _e !== void 0 ? _e : 'fixed', (_f = data.is_recurring_allowed) !== null && _f !== void 0 ? _f : true, (_g = data.is_active) !== null && _g !== void 0 ? _g : true, (_h = data.sort_order) !== null && _h !== void 0 ? _h : 0));
8598
+ const createdId = (_j = created[0]) === null || _j === void 0 ? void 0 : _j.id;
8599
+ if (!createdId) {
8600
+ throw new common_1.BadRequestException('Unable to create project cost type.');
8601
+ }
8602
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : slug);
8603
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8604
+ if (localeId && name) {
8605
+ await tx.$executeRawUnsafe(`INSERT INTO operations_project_cost_type_locale (operations_project_cost_type_id, locale_id, name, description)
8606
+ VALUES ($1, $2, $3, $4)`, createdId, localeId, name, description !== null && description !== void 0 ? description : null);
8607
+ }
8608
+ const rows = (await tx.$queryRawUnsafe(`SELECT pct.id,
8609
+ pct.slug,
8610
+ pct.code,
8611
+ COALESCE(pctl.name, pct.slug) AS name,
8612
+ pctl.description,
8613
+ pct.category_id AS "categoryId",
8614
+ pct.default_unit AS "defaultUnit",
8615
+ pct.default_calculation_type AS "defaultCalculationType",
8616
+ pct.is_recurring_allowed AS "isRecurringAllowed",
8617
+ pct.is_active AS "isActive",
8618
+ pct.sort_order AS "sortOrder",
8619
+ pct.created_at AS "createdAt"
8620
+ FROM operations_project_cost_type pct
8621
+ LEFT JOIN operations_project_cost_type_locale pctl
8622
+ ON pctl.operations_project_cost_type_id = pct.id AND pctl.locale_id = $2
8623
+ WHERE pct.id = $1`, createdId, localeId));
8624
+ return (_k = rows[0]) !== null && _k !== void 0 ? _k : null;
8625
+ });
8626
+ }
8627
+ async updateProjectCostType(userId, id, data) {
8628
+ const actor = await this.getActorContext(userId);
8629
+ this.ensureDirector(actor);
8630
+ const costType = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8631
+ if (!costType) {
8632
+ throw new common_1.NotFoundException('Project cost type not found.');
8633
+ }
8634
+ if (data.category_id !== undefined && data.category_id !== null) {
8635
+ const category = await this.querySingle(`SELECT id FROM operations_project_cost_category WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [data.category_id]);
8636
+ if (!category) {
8637
+ throw new common_1.BadRequestException(`Category with id ${data.category_id} not found.`);
8638
+ }
8639
+ }
8640
+ if (data.slug !== undefined) {
8641
+ const existingSlug = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE slug = $1 AND id != $2 AND deleted_at IS NULL LIMIT 1`, [data.slug, id]);
8642
+ if (existingSlug) {
8643
+ throw new common_1.ConflictException(`A cost type with slug '${data.slug}' already exists.`);
8644
+ }
8645
+ }
8646
+ if (data.code !== undefined) {
8647
+ const existingCode = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE code = $1 AND id != $2 AND deleted_at IS NULL LIMIT 1`, [data.code, id]);
8648
+ if (existingCode) {
8649
+ throw new common_1.ConflictException(`A cost type with code '${data.code}' already exists.`);
8650
+ }
8651
+ }
8652
+ const sets = [];
8653
+ const params = [];
8654
+ if (data.category_id !== undefined)
8655
+ sets.push(`category_id = ${this.param(params, data.category_id)}`);
8656
+ if (data.slug !== undefined)
8657
+ sets.push(`slug = ${this.param(params, data.slug)}`);
8658
+ if (data.code !== undefined)
8659
+ sets.push(`code = ${this.param(params, data.code)}`);
8660
+ if (data.default_unit !== undefined)
8661
+ sets.push(`default_unit = ${this.param(params, data.default_unit)}`);
8662
+ if (data.default_calculation_type !== undefined)
8663
+ sets.push(`default_calculation_type = ${this.param(params, data.default_calculation_type)}`);
8664
+ if (data.is_recurring_allowed !== undefined)
8665
+ sets.push(`is_recurring_allowed = ${this.param(params, data.is_recurring_allowed)}`);
8666
+ if (data.is_active !== undefined)
8667
+ sets.push(`is_active = ${this.param(params, data.is_active)}`);
8668
+ if (data.sort_order !== undefined)
8669
+ sets.push(`sort_order = ${this.param(params, data.sort_order)}`);
8670
+ if (sets.length > 0) {
8671
+ sets.push(`updated_at = NOW()`);
8672
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_type SET ${sets.join(', ')} WHERE id = ${this.param(params, id)}`, ...params);
8673
+ }
8674
+ if (data.name !== undefined || data.description !== undefined) {
8675
+ const localeId = await this.resolvePreferredLocaleId();
8676
+ if (localeId) {
8677
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : undefined);
8678
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8679
+ const existing = await this.querySingle(`SELECT id FROM operations_project_cost_type_locale WHERE operations_project_cost_type_id = $1 AND locale_id = $2 LIMIT 1`, [id, localeId]);
8680
+ if (existing) {
8681
+ const localeSets = [];
8682
+ const localeParams = [];
8683
+ if (name !== undefined)
8684
+ localeSets.push(`name = ${this.param(localeParams, name)}`);
8685
+ if (description !== undefined)
8686
+ localeSets.push(`description = ${this.param(localeParams, description)}`);
8687
+ if (localeSets.length > 0) {
8688
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_type_locale SET ${localeSets.join(', ')} WHERE operations_project_cost_type_id = ${this.param(localeParams, id)} AND locale_id = ${this.param(localeParams, localeId)}`, ...localeParams);
8689
+ }
8690
+ }
8691
+ else if (name) {
8692
+ await this.prisma.$queryRawUnsafe(`INSERT INTO operations_project_cost_type_locale (operations_project_cost_type_id, locale_id, name, description) VALUES ($1, $2, $3, $4)`, id, localeId, name, description !== null && description !== void 0 ? description : null);
8693
+ }
8694
+ }
8695
+ }
8696
+ return this.querySingle(`SELECT id, slug FROM operations_project_cost_type WHERE id = $1`, [id]);
8697
+ }
8698
+ async deleteProjectCostType(userId, id) {
8699
+ const actor = await this.getActorContext(userId);
8700
+ this.ensureDirector(actor);
8701
+ const costType = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8702
+ if (!costType) {
8703
+ throw new common_1.NotFoundException('Project cost type not found.');
8704
+ }
8705
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_type SET deleted_at = NOW() WHERE id = $1`, id);
8706
+ return { success: true };
8707
+ }
8708
+ async getProjectCostType(userId, id) {
8709
+ await this.getActorContext(userId);
8710
+ const localeId = await this.resolvePreferredLocaleId();
8711
+ const row = await this.querySingle(`SELECT pct.id,
8712
+ pct.slug,
8713
+ pct.code,
8714
+ COALESCE(pctl.name, pct.slug) AS name,
8715
+ pctl.description,
8716
+ pct.default_unit,
8717
+ pct.default_calculation_type,
8718
+ pct.is_recurring_allowed,
8719
+ pct.is_active,
8720
+ pct.sort_order,
8721
+ pct.category_id,
8722
+ CASE WHEN pcc.id IS NOT NULL THEN
8723
+ jsonb_build_object(
8724
+ 'id', pcc.id,
8725
+ 'slug', pcc.slug,
8726
+ 'name', COALESCE(pccl.name, pcc.slug),
8727
+ 'color', pcc.color,
8728
+ 'icon', pcc.icon
8729
+ )
8730
+ ELSE NULL END AS category
8731
+ FROM operations_project_cost_type pct
8732
+ LEFT JOIN operations_project_cost_category pcc
8733
+ ON pcc.id = pct.category_id AND pcc.deleted_at IS NULL
8734
+ LEFT JOIN LATERAL (
8735
+ SELECT l.name, l.description
8736
+ FROM operations_project_cost_category_locale l
8737
+ WHERE l.operations_project_cost_category_id = pcc.id
8738
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8739
+ l.id ASC
8740
+ LIMIT 1
8741
+ ) pccl ON TRUE
8742
+ LEFT JOIN LATERAL (
8743
+ SELECT l.name, l.description
8744
+ FROM operations_project_cost_type_locale l
8745
+ WHERE l.operations_project_cost_type_id = pct.id
8746
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8747
+ l.id ASC
8748
+ LIMIT 1
8749
+ ) pctl ON TRUE
8750
+ WHERE pct.id = $2 AND pct.deleted_at IS NULL`, [localeId, id]);
8751
+ if (!row) {
8752
+ throw new common_1.NotFoundException('Project cost type not found.');
8753
+ }
8754
+ return row;
8755
+ }
8756
+ // ──────────────────────────────────────────────────────────────────────────
8757
+ // Project Costs
8758
+ // ──────────────────────────────────────────────────────────────────────────
8759
+ async listProjectCosts(userId, projectId, filters = {}) {
8760
+ var _a;
8761
+ await this.getActorContext(userId);
8762
+ const localeId = await this.resolvePreferredLocaleId();
8763
+ const params = [localeId, projectId];
8764
+ const where = ['pc.deleted_at IS NULL', 'pc.project_id = $2'];
8765
+ if (filters.cost_type_id) {
8766
+ where.push(`pc.cost_type_id = ${this.param(params, filters.cost_type_id)}`);
8767
+ }
8768
+ if (filters.category_id) {
8769
+ where.push(`COALESCE(pc.category_id, pct.category_id) = ${this.param(params, filters.category_id)}`);
8770
+ }
8771
+ if (filters.recurrence_type) {
8772
+ where.push(`pc.recurrence_type = ${this.param(params, filters.recurrence_type)}`);
8773
+ }
8774
+ if (filters.calculation_type) {
8775
+ where.push(`pc.calculation_type = ${this.param(params, filters.calculation_type)}`);
8776
+ }
8777
+ if (filters.status) {
8778
+ where.push(`pc.status = ${this.param(params, filters.status)}`);
8779
+ }
8780
+ if (filters.is_billable !== undefined) {
8781
+ where.push(`pc.is_billable = ${this.param(params, filters.is_billable)}`);
8782
+ }
8783
+ if (filters.is_reimbursable !== undefined) {
8784
+ where.push(`pc.is_reimbursable = ${this.param(params, filters.is_reimbursable)}`);
8785
+ }
8786
+ if (filters.date_from) {
8787
+ where.push(`pc.cost_date >= ${this.param(params, filters.date_from)}::date`);
8788
+ }
8789
+ if (filters.date_to) {
8790
+ where.push(`pc.cost_date <= ${this.param(params, filters.date_to)}::date`);
8791
+ }
8792
+ if ((_a = filters.search) === null || _a === void 0 ? void 0 : _a.trim()) {
8793
+ const p = this.param(params, `%${filters.search.trim()}%`);
8794
+ where.push(`(COALESCE(pc.description, '') ILIKE ${p} OR COALESCE(pc.notes, '') ILIKE ${p})`);
8795
+ }
8796
+ const whereClause = `WHERE ${where.join(' AND ')}`;
8797
+ const rows = await this.queryRows(`SELECT pc.id,
8798
+ pc.project_id AS "projectId",
8799
+ pc.cost_type_id AS "costTypeId",
8800
+ pct.slug AS "costTypeSlug",
8801
+ pct.code AS "costTypeCode",
8802
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
8803
+ pc.category_id AS "categoryId",
8804
+ COALESCE(pc.category_id, pct.category_id) AS "resolvedCategoryId",
8805
+ pcc.slug AS "categorySlug",
8806
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
8807
+ pcc.color AS "categoryColor",
8808
+ pcc.icon AS "categoryIcon",
8809
+ pc.description,
8810
+ pc.amount::text AS amount,
8811
+ pc.quantity::text AS quantity,
8812
+ pc.unit_amount::text AS "unitAmount",
8813
+ pc.currency,
8814
+ TO_CHAR(pc.cost_date, 'YYYY-MM-DD') AS "costDate",
8815
+ TO_CHAR(pc.period_start, 'YYYY-MM-DD') AS "periodStart",
8816
+ TO_CHAR(pc.period_end, 'YYYY-MM-DD') AS "periodEnd",
8817
+ pc.calculation_type AS "calculationType",
8818
+ pc.recurrence_type AS "recurrenceType",
8819
+ pc.is_billable AS "isBillable",
8820
+ pc.is_reimbursable AS "isReimbursable",
8821
+ pc.notes,
8822
+ pc.status,
8823
+ pc.created_at AS "createdAt"
8824
+ FROM operations_project_cost pc
8825
+ LEFT JOIN operations_project_cost_type pct
8826
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
8827
+ LEFT JOIN operations_project_cost_category pcc
8828
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
8829
+ LEFT JOIN LATERAL (
8830
+ SELECT l.name
8831
+ FROM operations_project_cost_type_locale l
8832
+ WHERE l.operations_project_cost_type_id = pct.id
8833
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8834
+ l.id ASC
8835
+ LIMIT 1
8836
+ ) pctl ON TRUE
8837
+ LEFT JOIN LATERAL (
8838
+ SELECT l.name
8839
+ FROM operations_project_cost_category_locale l
8840
+ WHERE l.operations_project_cost_category_id = pcc.id
8841
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8842
+ l.id ASC
8843
+ LIMIT 1
8844
+ ) pccl ON TRUE
8845
+ ${whereClause}
8846
+ ORDER BY pc.created_at DESC`, params);
8847
+ return rows.map((row) => ({
8848
+ id: row.id,
8849
+ project_id: row.projectId,
8850
+ cost_type_id: row.costTypeId,
8851
+ category_id: row.categoryId,
8852
+ description: row.description,
8853
+ amount: row.amount,
8854
+ quantity: row.quantity,
8855
+ unit_amount: row.unitAmount,
8856
+ currency: row.currency,
8857
+ cost_date: row.costDate,
8858
+ period_start: row.periodStart,
8859
+ period_end: row.periodEnd,
8860
+ calculation_type: row.calculationType,
8861
+ recurrence_type: row.recurrenceType,
8862
+ is_billable: row.isBillable,
8863
+ is_reimbursable: row.isReimbursable,
8864
+ notes: row.notes,
8865
+ status: row.status,
8866
+ created_at: row.createdAt,
8867
+ cost_type: row.costTypeId
8868
+ ? { id: row.costTypeId, slug: row.costTypeSlug, name: row.costTypeName, code: row.costTypeCode }
8869
+ : null,
8870
+ category: row.resolvedCategoryId
8871
+ ? { id: row.resolvedCategoryId, slug: row.categorySlug, name: row.categoryName, color: row.categoryColor, icon: row.categoryIcon }
8872
+ : null,
8873
+ }));
8874
+ }
8875
+ async getProjectCostsSummaryGrouped(userId, projectId) {
8876
+ var _a, _b;
8877
+ const items = await this.listProjectCosts(userId, projectId, {});
8878
+ // Group by resolved category
8879
+ const categoryMap = new Map();
8880
+ for (const cost of items) {
8881
+ const cat = (_a = cost.category) !== null && _a !== void 0 ? _a : null;
8882
+ const key = (_b = cat === null || cat === void 0 ? void 0 : cat.id) !== null && _b !== void 0 ? _b : null;
8883
+ if (!categoryMap.has(key)) {
8884
+ categoryMap.set(key, { category: cat, items: [], total_amount: 0 });
8885
+ }
8886
+ const group = categoryMap.get(key);
8887
+ group.items.push(cost);
8888
+ group.total_amount += (parseFloat(String(cost.amount)) || 0) * (parseFloat(String(cost.quantity)) || 1);
8889
+ }
8890
+ const grand_total = Array.from(categoryMap.values()).reduce((sum, g) => sum + g.total_amount, 0);
8891
+ return {
8892
+ categories: Array.from(categoryMap.values()).map((g) => ({
8893
+ category: g.category,
8894
+ items: g.items,
8895
+ total_amount: Math.round(g.total_amount * 100) / 100,
8896
+ count: g.items.length,
8897
+ })),
8898
+ grand_total: Math.round(grand_total * 100) / 100,
8899
+ };
8900
+ }
8901
+ async getProjectCost(userId, projectId, id) {
8902
+ const rows = await this.listProjectCosts(userId, projectId, {});
8903
+ const cost = rows.find((r) => r.id === id);
8904
+ if (!cost) {
8905
+ throw new common_1.NotFoundException('Project cost not found.');
8906
+ }
8907
+ return cost;
8908
+ }
8909
+ async getProjectCostsSummary(userId, projectId) {
8910
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
8911
+ await this.getActorContext(userId);
8912
+ const localeId = await this.resolvePreferredLocaleId();
8913
+ // ── 1. Verify project exists and fetch budget_amount ──────────────────
8914
+ const project = await this.querySingle(`SELECT id, budget_amount::text AS "budgetAmount"
8915
+ FROM operations_project
8916
+ WHERE id = $1 AND deleted_at IS NULL
8917
+ LIMIT 1`, [projectId]);
8918
+ if (!project) {
8919
+ throw new common_1.NotFoundException('Project not found.');
8920
+ }
8921
+ const budgetAmount = parseFloat((_a = project.budgetAmount) !== null && _a !== void 0 ? _a : '0') || 0;
8922
+ // ── 2. Aggregated cost totals ─────────────────────────────────────────
8923
+ const totals = await this.querySingle(`SELECT
8924
+ COALESCE(SUM(CASE WHEN status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "extraCostTotal",
8925
+ COALESCE(SUM(CASE WHEN status = 'planned' THEN amount * quantity ELSE 0 END), 0)::text AS "plannedTotal",
8926
+ COALESCE(SUM(CASE WHEN status = 'approved' THEN amount * quantity ELSE 0 END), 0)::text AS "approvedTotal",
8927
+ COALESCE(SUM(CASE WHEN status = 'realized' THEN amount * quantity ELSE 0 END), 0)::text AS "realizedTotal",
8928
+ COALESCE(SUM(CASE WHEN status = 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "cancelledTotal",
8929
+ COALESCE(SUM(CASE WHEN is_billable = true AND status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "billableTotal",
8930
+ COALESCE(SUM(CASE WHEN is_billable = false AND status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "nonBillableTotal",
8931
+ COALESCE(SUM(CASE WHEN is_reimbursable = true AND status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "reimbursableTotal"
8932
+ FROM operations_project_cost
8933
+ WHERE deleted_at IS NULL
8934
+ AND project_id = $1`, [projectId]);
8935
+ const extraCostTotal = Math.round((parseFloat((_b = totals === null || totals === void 0 ? void 0 : totals.extraCostTotal) !== null && _b !== void 0 ? _b : '0') || 0) * 100) / 100;
8936
+ const plannedTotal = Math.round((parseFloat((_c = totals === null || totals === void 0 ? void 0 : totals.plannedTotal) !== null && _c !== void 0 ? _c : '0') || 0) * 100) / 100;
8937
+ const approvedTotal = Math.round((parseFloat((_d = totals === null || totals === void 0 ? void 0 : totals.approvedTotal) !== null && _d !== void 0 ? _d : '0') || 0) * 100) / 100;
8938
+ const realizedTotal = Math.round((parseFloat((_e = totals === null || totals === void 0 ? void 0 : totals.realizedTotal) !== null && _e !== void 0 ? _e : '0') || 0) * 100) / 100;
8939
+ const cancelledTotal = Math.round((parseFloat((_f = totals === null || totals === void 0 ? void 0 : totals.cancelledTotal) !== null && _f !== void 0 ? _f : '0') || 0) * 100) / 100;
8940
+ const billableTotal = Math.round((parseFloat((_g = totals === null || totals === void 0 ? void 0 : totals.billableTotal) !== null && _g !== void 0 ? _g : '0') || 0) * 100) / 100;
8941
+ const nonBillableTotal = Math.round((parseFloat((_h = totals === null || totals === void 0 ? void 0 : totals.nonBillableTotal) !== null && _h !== void 0 ? _h : '0') || 0) * 100) / 100;
8942
+ const reimbursableTotal = Math.round((parseFloat((_j = totals === null || totals === void 0 ? void 0 : totals.reimbursableTotal) !== null && _j !== void 0 ? _j : '0') || 0) * 100) / 100;
8943
+ const teamCostTotal = 0;
8944
+ const totalProjectCost = Math.round((teamCostTotal + extraCostTotal) * 100) / 100;
8945
+ const remainingBudget = Math.round((budgetAmount - totalProjectCost) * 100) / 100;
8946
+ const budgetUsagePercent = budgetAmount > 0
8947
+ ? Math.round((totalProjectCost / budgetAmount) * 10000) / 100
8948
+ : 0;
8949
+ // ── 3. cost_by_category ───────────────────────────────────────────────
8950
+ const costByCategory = await this.queryRows(`SELECT
8951
+ COALESCE(pc.category_id, pct.category_id) AS "categoryId",
8952
+ pcc.slug AS "categorySlug",
8953
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
8954
+ pcc.color AS "categoryColor",
8955
+ pcc.icon AS "categoryIcon",
8956
+ SUM(pc.amount * pc.quantity)::text AS total,
8957
+ COUNT(*)::int AS count
8958
+ FROM operations_project_cost pc
8959
+ LEFT JOIN operations_project_cost_type pct
8960
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
8961
+ LEFT JOIN operations_project_cost_category pcc
8962
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
8963
+ LEFT JOIN LATERAL (
8964
+ SELECT l.name
8965
+ FROM operations_project_cost_category_locale l
8966
+ WHERE l.operations_project_cost_category_id = pcc.id
8967
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8968
+ l.id ASC
8969
+ LIMIT 1
8970
+ ) pccl ON TRUE
8971
+ WHERE pc.deleted_at IS NULL
8972
+ AND pc.project_id = $2
8973
+ AND pc.status != 'cancelled'
8974
+ GROUP BY COALESCE(pc.category_id, pct.category_id), pcc.slug, pcc.color, pcc.icon, pccl.name
8975
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, projectId]);
8976
+ // ── 4. cost_by_type ───────────────────────────────────────────────────
8977
+ const costByType = await this.queryRows(`SELECT
8978
+ pc.cost_type_id AS "costTypeId",
8979
+ pct.slug AS "costTypeSlug",
8980
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
8981
+ pct.code AS "costTypeCode",
8982
+ SUM(pc.amount * pc.quantity)::text AS total,
8983
+ COUNT(*)::int AS count
8984
+ FROM operations_project_cost pc
8985
+ LEFT JOIN operations_project_cost_type pct
8986
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
8987
+ LEFT JOIN LATERAL (
8988
+ SELECT l.name
8989
+ FROM operations_project_cost_type_locale l
8990
+ WHERE l.operations_project_cost_type_id = pct.id
8991
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8992
+ l.id ASC
8993
+ LIMIT 1
8994
+ ) pctl ON TRUE
8995
+ WHERE pc.deleted_at IS NULL
8996
+ AND pc.project_id = $2
8997
+ AND pc.status != 'cancelled'
8998
+ GROUP BY pc.cost_type_id, pct.slug, pct.code, pctl.name
8999
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, projectId]);
9000
+ // ── 5. cost_by_month ──────────────────────────────────────────────────
9001
+ const costByMonth = await this.queryRows(`SELECT
9002
+ TO_CHAR(COALESCE(pc.cost_date, pc.created_at), 'YYYY-MM') AS month,
9003
+ SUM(pc.amount * pc.quantity)::text AS total,
9004
+ COUNT(*)::int AS count
9005
+ FROM operations_project_cost pc
9006
+ WHERE pc.deleted_at IS NULL
9007
+ AND pc.project_id = $1
9008
+ AND pc.status != 'cancelled'
9009
+ GROUP BY TO_CHAR(COALESCE(pc.cost_date, pc.created_at), 'YYYY-MM')
9010
+ ORDER BY month ASC`, [projectId]);
9011
+ // ── 6. top_cost_types (top 5) ─────────────────────────────────────────
9012
+ const topCostTypes = costByType.slice(0, 5).map((ct) => {
9013
+ const typeTotal = Math.round((parseFloat(ct.total) || 0) * 100) / 100;
9014
+ const percentage = extraCostTotal > 0
9015
+ ? Math.round((typeTotal / extraCostTotal) * 10000) / 100
9016
+ : 0;
9017
+ return {
9018
+ cost_type_id: ct.costTypeId,
9019
+ cost_type_slug: ct.costTypeSlug,
9020
+ cost_type_name: ct.costTypeName,
9021
+ cost_type_code: ct.costTypeCode,
9022
+ total: typeTotal,
9023
+ percentage,
9024
+ };
9025
+ });
9026
+ return {
9027
+ project_id: projectId,
9028
+ budget_amount: budgetAmount,
9029
+ team_cost_total: teamCostTotal,
9030
+ extra_cost_total: extraCostTotal,
9031
+ total_project_cost: totalProjectCost,
9032
+ remaining_budget: remainingBudget,
9033
+ budget_usage_percent: budgetUsagePercent,
9034
+ planned_total: plannedTotal,
9035
+ approved_total: approvedTotal,
9036
+ realized_total: realizedTotal,
9037
+ cancelled_total: cancelledTotal,
9038
+ billable_total: billableTotal,
9039
+ non_billable_total: nonBillableTotal,
9040
+ reimbursable_total: reimbursableTotal,
9041
+ cost_by_category: costByCategory.map((c) => ({
9042
+ category_id: c.categoryId,
9043
+ category_slug: c.categorySlug,
9044
+ category_name: c.categoryName,
9045
+ category_color: c.categoryColor,
9046
+ category_icon: c.categoryIcon,
9047
+ total: Math.round((parseFloat(c.total) || 0) * 100) / 100,
9048
+ count: Number(c.count),
9049
+ })),
9050
+ cost_by_type: costByType.map((t) => ({
9051
+ cost_type_id: t.costTypeId,
9052
+ cost_type_slug: t.costTypeSlug,
9053
+ cost_type_name: t.costTypeName,
9054
+ cost_type_code: t.costTypeCode,
9055
+ total: Math.round((parseFloat(t.total) || 0) * 100) / 100,
9056
+ count: Number(t.count),
9057
+ })),
9058
+ cost_by_month: costByMonth.map((m) => ({
9059
+ month: m.month,
9060
+ total: Math.round((parseFloat(m.total) || 0) * 100) / 100,
9061
+ count: Number(m.count),
9062
+ })),
9063
+ top_cost_types: topCostTypes,
9064
+ };
9065
+ }
9066
+ async getProjectCostReport(userId, projectId, filters) {
9067
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
9068
+ await this.getActorContext(userId);
9069
+ const localeId = await this.resolvePreferredLocaleId();
9070
+ // ── Verify project ───────────────────────────────────────────────────
9071
+ const project = await this.querySingle(`SELECT id, budget_amount::text AS "budgetAmount"
9072
+ FROM operations_project
9073
+ WHERE id = $1 AND deleted_at IS NULL
9074
+ LIMIT 1`, [projectId]);
9075
+ if (!project) {
9076
+ throw new common_1.NotFoundException('Project not found.');
9077
+ }
9078
+ const budgetAmount = parseFloat((_a = project.budgetAmount) !== null && _a !== void 0 ? _a : '0') || 0;
9079
+ // ── Build dynamic WHERE clause ────────────────────────────────────────
9080
+ const conditions = [
9081
+ 'pc.deleted_at IS NULL',
9082
+ 'pc.project_id = $1',
9083
+ ];
9084
+ const params = [projectId];
9085
+ if (filters.date_from) {
9086
+ params.push(filters.date_from);
9087
+ conditions.push(`COALESCE(pc.cost_date, pc.created_at::date) >= $${params.length}::date`);
9088
+ }
9089
+ if (filters.date_to) {
9090
+ params.push(filters.date_to);
9091
+ conditions.push(`COALESCE(pc.cost_date, pc.created_at::date) <= $${params.length}::date`);
9092
+ }
9093
+ if (filters.category_id !== undefined) {
9094
+ params.push(filters.category_id);
9095
+ conditions.push(`(pc.category_id = $${params.length} OR (pc.category_id IS NULL AND EXISTS (
9096
+ SELECT 1 FROM operations_project_cost_type pct2
9097
+ WHERE pct2.id = pc.cost_type_id AND pct2.category_id = $${params.length} AND pct2.deleted_at IS NULL
9098
+ )))`);
9099
+ }
9100
+ if (filters.cost_type_id !== undefined) {
9101
+ params.push(filters.cost_type_id);
9102
+ conditions.push(`pc.cost_type_id = $${params.length}`);
9103
+ }
9104
+ if (filters.status !== undefined) {
9105
+ params.push(filters.status);
9106
+ conditions.push(`pc.status = $${params.length}`);
9107
+ }
9108
+ if (filters.is_billable !== undefined) {
9109
+ params.push(filters.is_billable);
9110
+ conditions.push(`pc.is_billable = $${params.length}`);
9111
+ }
9112
+ if (filters.is_reimbursable !== undefined) {
9113
+ params.push(filters.is_reimbursable);
9114
+ conditions.push(`pc.is_reimbursable = $${params.length}`);
9115
+ }
9116
+ const whereClause = conditions.join(' AND ');
9117
+ // ── Totals ────────────────────────────────────────────────────────────
9118
+ const totals = await this.querySingle(`SELECT
9119
+ COALESCE(SUM(pc.amount * pc.quantity), 0)::text AS "grandTotal",
9120
+ COALESCE(SUM(CASE WHEN pc.status = 'planned' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "plannedTotal",
9121
+ COALESCE(SUM(CASE WHEN pc.status = 'approved' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "approvedTotal",
9122
+ COALESCE(SUM(CASE WHEN pc.status = 'realized' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "realizedTotal",
9123
+ COALESCE(SUM(CASE WHEN pc.status = 'cancelled' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "cancelledTotal",
9124
+ COALESCE(SUM(CASE WHEN pc.is_billable = true THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "billableTotal",
9125
+ COALESCE(SUM(CASE WHEN pc.is_billable = false THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "nonBillableTotal",
9126
+ COALESCE(SUM(CASE WHEN pc.is_reimbursable = true THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "reimbursableTotal",
9127
+ COUNT(*)::int AS "totalCount"
9128
+ FROM operations_project_cost pc
9129
+ WHERE ${whereClause}`, params);
9130
+ const round2 = (v) => Math.round((parseFloat(v !== null && v !== void 0 ? v : '0') || 0) * 100) / 100;
9131
+ const grandTotal = round2(totals === null || totals === void 0 ? void 0 : totals.grandTotal);
9132
+ const plannedTotal = round2(totals === null || totals === void 0 ? void 0 : totals.plannedTotal);
9133
+ const approvedTotal = round2(totals === null || totals === void 0 ? void 0 : totals.approvedTotal);
9134
+ const realizedTotal = round2(totals === null || totals === void 0 ? void 0 : totals.realizedTotal);
9135
+ const cancelledTotal = round2(totals === null || totals === void 0 ? void 0 : totals.cancelledTotal);
9136
+ const billableTotal = round2(totals === null || totals === void 0 ? void 0 : totals.billableTotal);
9137
+ const nonBillableTotal = round2(totals === null || totals === void 0 ? void 0 : totals.nonBillableTotal);
9138
+ const reimbursableTotal = round2(totals === null || totals === void 0 ? void 0 : totals.reimbursableTotal);
9139
+ // ── By category ───────────────────────────────────────────────────────
9140
+ const costByCategory = await this.queryRows(`SELECT
9141
+ COALESCE(pc.category_id, pct.category_id) AS "categoryId",
9142
+ pcc.slug AS "categorySlug",
9143
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
9144
+ pcc.color AS "categoryColor",
9145
+ pcc.icon AS "categoryIcon",
9146
+ SUM(pc.amount * pc.quantity)::text AS total,
9147
+ COUNT(*)::int AS count,
9148
+ COALESCE(SUM(CASE WHEN pc.status='planned' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "plannedSubtotal",
9149
+ COALESCE(SUM(CASE WHEN pc.status='realized' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "realizedSubtotal"
9150
+ FROM operations_project_cost pc
9151
+ LEFT JOIN operations_project_cost_type pct
9152
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9153
+ LEFT JOIN operations_project_cost_category pcc
9154
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
9155
+ LEFT JOIN LATERAL (
9156
+ SELECT l.name
9157
+ FROM operations_project_cost_category_locale l
9158
+ WHERE l.operations_project_cost_category_id = pcc.id
9159
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9160
+ LIMIT 1
9161
+ ) pccl ON TRUE
9162
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9163
+ GROUP BY COALESCE(pc.category_id, pct.category_id), pcc.slug, pcc.color, pcc.icon, pccl.name
9164
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, ...params]);
9165
+ // ── By type ───────────────────────────────────────────────────────────
9166
+ const costByType = await this.queryRows(`SELECT
9167
+ pc.cost_type_id AS "costTypeId",
9168
+ pct.slug AS "costTypeSlug",
9169
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
9170
+ pct.code AS "costTypeCode",
9171
+ SUM(pc.amount * pc.quantity)::text AS total,
9172
+ COUNT(*)::int AS count,
9173
+ COALESCE(SUM(CASE WHEN pc.status='planned' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "plannedSubtotal",
9174
+ COALESCE(SUM(CASE WHEN pc.status='realized' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "realizedSubtotal"
9175
+ FROM operations_project_cost pc
9176
+ LEFT JOIN operations_project_cost_type pct
9177
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9178
+ LEFT JOIN LATERAL (
9179
+ SELECT l.name
9180
+ FROM operations_project_cost_type_locale l
9181
+ WHERE l.operations_project_cost_type_id = pct.id
9182
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9183
+ LIMIT 1
9184
+ ) pctl ON TRUE
9185
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9186
+ GROUP BY pc.cost_type_id, pct.slug, pct.code, pctl.name
9187
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, ...params]);
9188
+ // ── By month ──────────────────────────────────────────────────────────
9189
+ const costByMonth = await this.queryRows(`SELECT
9190
+ TO_CHAR(COALESCE(pc.cost_date, pc.created_at::date), 'YYYY-MM') AS month,
9191
+ SUM(pc.amount * pc.quantity)::text AS total,
9192
+ COALESCE(SUM(CASE WHEN pc.status='planned' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "plannedSubtotal",
9193
+ COALESCE(SUM(CASE WHEN pc.status='realized' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "realizedSubtotal",
9194
+ COUNT(*)::int AS count
9195
+ FROM operations_project_cost pc
9196
+ WHERE ${whereClause}
9197
+ GROUP BY TO_CHAR(COALESCE(pc.cost_date, pc.created_at::date), 'YYYY-MM')
9198
+ ORDER BY month ASC`, params);
9199
+ // ── Top 5 individual costs ────────────────────────────────────────────
9200
+ const top5Costs = await this.queryRows(`SELECT
9201
+ pc.id,
9202
+ pc.description,
9203
+ pc.amount::text,
9204
+ pc.quantity::text,
9205
+ pc.status,
9206
+ pc.cost_date AS "costDate",
9207
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
9208
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
9209
+ pcc.color AS "categoryColor"
9210
+ FROM operations_project_cost pc
9211
+ LEFT JOIN operations_project_cost_type pct
9212
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9213
+ LEFT JOIN LATERAL (
9214
+ SELECT l.name
9215
+ FROM operations_project_cost_type_locale l
9216
+ WHERE l.operations_project_cost_type_id = pct.id
9217
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9218
+ LIMIT 1
9219
+ ) pctl ON TRUE
9220
+ LEFT JOIN operations_project_cost_category pcc
9221
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
9222
+ LEFT JOIN LATERAL (
9223
+ SELECT l.name
9224
+ FROM operations_project_cost_category_locale l
9225
+ WHERE l.operations_project_cost_category_id = pcc.id
9226
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9227
+ LIMIT 1
9228
+ ) pccl ON TRUE
9229
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9230
+ ORDER BY (pc.amount * pc.quantity) DESC
9231
+ LIMIT 5`, [localeId, ...params]);
9232
+ // ── Detailed list ─────────────────────────────────────────────────────
9233
+ const detailedList = await this.queryRows(`SELECT
9234
+ pc.id,
9235
+ pc.description,
9236
+ pc.amount::text,
9237
+ pc.quantity::text,
9238
+ pc.unit_amount::text AS "unitAmount",
9239
+ pc.currency,
9240
+ pc.calculation_type AS "calculationType",
9241
+ pc.recurrence_type AS "recurrenceType",
9242
+ pc.status,
9243
+ pc.is_billable AS "isBillable",
9244
+ pc.is_reimbursable AS "isReimbursable",
9245
+ pc.cost_date AS "costDate",
9246
+ pc.period_start AS "periodStart",
9247
+ pc.period_end AS "periodEnd",
9248
+ pc.notes,
9249
+ pc.cost_type_id AS "costTypeId",
9250
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
9251
+ pct.code AS "costTypeCode",
9252
+ COALESCE(pc.category_id, pct.category_id) AS "categoryId",
9253
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
9254
+ pcc.color AS "categoryColor",
9255
+ pc.created_at::text AS "createdAt"
9256
+ FROM operations_project_cost pc
9257
+ LEFT JOIN operations_project_cost_type pct
9258
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9259
+ LEFT JOIN LATERAL (
9260
+ SELECT l.name
9261
+ FROM operations_project_cost_type_locale l
9262
+ WHERE l.operations_project_cost_type_id = pct.id
9263
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9264
+ LIMIT 1
9265
+ ) pctl ON TRUE
9266
+ LEFT JOIN operations_project_cost_category pcc
9267
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
9268
+ LEFT JOIN LATERAL (
9269
+ SELECT l.name
9270
+ FROM operations_project_cost_category_locale l
9271
+ WHERE l.operations_project_cost_category_id = pcc.id
9272
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9273
+ LIMIT 1
9274
+ ) pccl ON TRUE
9275
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9276
+ ORDER BY (pc.amount * pc.quantity) DESC, pc.cost_date DESC NULLS LAST`, [localeId, ...params]);
9277
+ return {
9278
+ project_id: projectId,
9279
+ budget_amount: budgetAmount,
9280
+ filters_applied: {
9281
+ date_from: (_b = filters.date_from) !== null && _b !== void 0 ? _b : null,
9282
+ date_to: (_c = filters.date_to) !== null && _c !== void 0 ? _c : null,
9283
+ category_id: (_d = filters.category_id) !== null && _d !== void 0 ? _d : null,
9284
+ cost_type_id: (_e = filters.cost_type_id) !== null && _e !== void 0 ? _e : null,
9285
+ status: (_f = filters.status) !== null && _f !== void 0 ? _f : null,
9286
+ is_billable: (_g = filters.is_billable) !== null && _g !== void 0 ? _g : null,
9287
+ is_reimbursable: (_h = filters.is_reimbursable) !== null && _h !== void 0 ? _h : null,
9288
+ },
9289
+ totals: {
9290
+ grand_total: grandTotal,
9291
+ planned_total: plannedTotal,
9292
+ approved_total: approvedTotal,
9293
+ realized_total: realizedTotal,
9294
+ cancelled_total: cancelledTotal,
9295
+ billable_total: billableTotal,
9296
+ non_billable_total: nonBillableTotal,
9297
+ reimbursable_total: reimbursableTotal,
9298
+ total_count: Number((_j = totals === null || totals === void 0 ? void 0 : totals.totalCount) !== null && _j !== void 0 ? _j : 0),
9299
+ },
9300
+ cost_by_category: costByCategory.map((c) => ({
9301
+ category_id: c.categoryId,
9302
+ category_slug: c.categorySlug,
9303
+ category_name: c.categoryName,
9304
+ category_color: c.categoryColor,
9305
+ category_icon: c.categoryIcon,
9306
+ total: round2(c.total),
9307
+ count: Number(c.count),
9308
+ planned_subtotal: round2(c.plannedSubtotal),
9309
+ realized_subtotal: round2(c.realizedSubtotal),
9310
+ })),
9311
+ cost_by_type: costByType.map((t) => ({
9312
+ cost_type_id: t.costTypeId,
9313
+ cost_type_slug: t.costTypeSlug,
9314
+ cost_type_name: t.costTypeName,
9315
+ cost_type_code: t.costTypeCode,
9316
+ total: round2(t.total),
9317
+ count: Number(t.count),
9318
+ planned_subtotal: round2(t.plannedSubtotal),
9319
+ realized_subtotal: round2(t.realizedSubtotal),
9320
+ })),
9321
+ cost_by_month: costByMonth.map((m) => ({
9322
+ month: m.month,
9323
+ total: round2(m.total),
9324
+ planned_subtotal: round2(m.plannedSubtotal),
9325
+ realized_subtotal: round2(m.realizedSubtotal),
9326
+ count: Number(m.count),
9327
+ })),
9328
+ top_5_costs: top5Costs.map((c) => ({
9329
+ id: c.id,
9330
+ description: c.description,
9331
+ total: round2(String(parseFloat(c.amount) * parseFloat(c.quantity))),
9332
+ amount: round2(c.amount),
9333
+ quantity: parseFloat(c.quantity),
9334
+ status: c.status,
9335
+ cost_type_name: c.costTypeName,
9336
+ category_name: c.categoryName,
9337
+ category_color: c.categoryColor,
9338
+ cost_date: c.costDate,
9339
+ })),
9340
+ detailed_list: detailedList.map((c) => ({
9341
+ id: c.id,
9342
+ description: c.description,
9343
+ amount: round2(c.amount),
9344
+ quantity: parseFloat(c.quantity),
9345
+ unit_amount: c.unitAmount ? round2(c.unitAmount) : null,
9346
+ total: round2(String(parseFloat(c.amount) * parseFloat(c.quantity))),
9347
+ currency: c.currency,
9348
+ calculation_type: c.calculationType,
9349
+ recurrence_type: c.recurrenceType,
9350
+ status: c.status,
9351
+ is_billable: c.isBillable,
9352
+ is_reimbursable: c.isReimbursable,
9353
+ cost_date: c.costDate,
9354
+ period_start: c.periodStart,
9355
+ period_end: c.periodEnd,
9356
+ notes: c.notes,
9357
+ cost_type_id: c.costTypeId,
9358
+ cost_type_name: c.costTypeName,
9359
+ cost_type_code: c.costTypeCode,
9360
+ category_id: c.categoryId,
9361
+ category_name: c.categoryName,
9362
+ category_color: c.categoryColor,
9363
+ created_at: c.createdAt,
9364
+ })),
9365
+ };
9366
+ }
9367
+ async createProjectCost(userId, projectId, data) {
9368
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
9369
+ const actor = await this.getActorContext(userId);
9370
+ this.ensureSupervisor(actor);
9371
+ const project = await this.querySingle(`SELECT id FROM operations_project WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [projectId]);
9372
+ if (!project) {
9373
+ throw new common_1.NotFoundException('Project not found.');
9374
+ }
9375
+ if (data.cost_type_id) {
9376
+ const costType = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [data.cost_type_id]);
9377
+ if (!costType) {
9378
+ throw new common_1.BadRequestException(`Cost type with id ${data.cost_type_id} not found.`);
9379
+ }
9380
+ }
9381
+ if (data.category_id) {
9382
+ const category = await this.querySingle(`SELECT id FROM operations_project_cost_category WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [data.category_id]);
9383
+ if (!category) {
9384
+ throw new common_1.BadRequestException(`Cost category with id ${data.category_id} not found.`);
9385
+ }
9386
+ }
9387
+ const calcType = (_a = data.calculation_type) !== null && _a !== void 0 ? _a : 'fixed';
9388
+ let effectiveAmount = data.amount;
9389
+ if (['unit', 'hourly', 'monthly'].includes(calcType) && data.unit_amount !== undefined && data.unit_amount !== null) {
9390
+ const qty = (_b = data.quantity) !== null && _b !== void 0 ? _b : 1;
9391
+ effectiveAmount = Math.round(qty * data.unit_amount * 100) / 100;
9392
+ }
9393
+ const created = await this.querySingle(`INSERT INTO operations_project_cost
9394
+ (project_id, cost_type_id, category_id, description, amount, quantity, unit_amount, currency, cost_date, period_start, period_end, calculation_type, recurrence_type, is_billable, is_reimbursable, notes, status, created_at, updated_at)
9395
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::date, $10::date, $11::date, $12::operations_project_cost_calculation_type_134cdfb49c_enum, $13::operations_project_cost_recurrence_type_09baf0f043_enum, $14, $15, $16, $17::operations_project_cost_status_153e8592ce_enum, NOW(), NOW())
9396
+ RETURNING id`, [
9397
+ projectId,
9398
+ (_c = data.cost_type_id) !== null && _c !== void 0 ? _c : null,
9399
+ (_d = data.category_id) !== null && _d !== void 0 ? _d : null,
9400
+ (_e = data.description) !== null && _e !== void 0 ? _e : null,
9401
+ effectiveAmount,
9402
+ (_f = data.quantity) !== null && _f !== void 0 ? _f : 1,
9403
+ (_g = data.unit_amount) !== null && _g !== void 0 ? _g : null,
9404
+ (_h = data.currency) !== null && _h !== void 0 ? _h : 'BRL',
9405
+ (_j = data.cost_date) !== null && _j !== void 0 ? _j : null,
9406
+ (_k = data.period_start) !== null && _k !== void 0 ? _k : null,
9407
+ (_l = data.period_end) !== null && _l !== void 0 ? _l : null,
9408
+ calcType,
9409
+ (_m = data.recurrence_type) !== null && _m !== void 0 ? _m : 'none',
9410
+ (_o = data.is_billable) !== null && _o !== void 0 ? _o : false,
9411
+ (_p = data.is_reimbursable) !== null && _p !== void 0 ? _p : false,
9412
+ (_q = data.notes) !== null && _q !== void 0 ? _q : null,
9413
+ (_r = data.status) !== null && _r !== void 0 ? _r : 'planned',
9414
+ ]);
9415
+ if (!(created === null || created === void 0 ? void 0 : created.id)) {
9416
+ throw new common_1.BadRequestException('Unable to create project cost.');
9417
+ }
9418
+ const rows = await this.listProjectCosts(userId, projectId, {});
9419
+ return (_s = rows.find((r) => r.id === created.id)) !== null && _s !== void 0 ? _s : null;
9420
+ }
9421
+ async updateProjectCost(userId, id, data) {
9422
+ var _a, _b, _c;
9423
+ const actor = await this.getActorContext(userId);
9424
+ this.ensureSupervisor(actor);
9425
+ const cost = await this.querySingle(`SELECT id, project_id AS "projectId", calculation_type AS "calculationType", unit_amount::text AS "unitAmount", quantity::text AS quantity FROM operations_project_cost WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
9426
+ if (!cost) {
9427
+ throw new common_1.NotFoundException('Project cost not found.');
9428
+ }
9429
+ // Auto-calculate amount when applicable
9430
+ const effectiveCalcType = (_a = data.calculation_type) !== null && _a !== void 0 ? _a : cost.calculationType;
9431
+ if (['unit', 'hourly', 'monthly'].includes(effectiveCalcType)) {
9432
+ const ua = data.unit_amount !== undefined ? data.unit_amount : (cost.unitAmount !== null ? parseFloat(cost.unitAmount) : null);
9433
+ const qty = data.quantity !== undefined ? data.quantity : parseFloat(cost.quantity);
9434
+ if (ua !== null && ua !== undefined) {
9435
+ data = Object.assign(Object.assign({}, data), { amount: Math.round(qty * ua * 100) / 100 });
9436
+ }
9437
+ }
9438
+ const sets = [];
9439
+ const params = [];
9440
+ if (data.cost_type_id !== undefined)
9441
+ sets.push(`cost_type_id = ${this.param(params, data.cost_type_id)}`);
9442
+ if (data.category_id !== undefined)
9443
+ sets.push(`category_id = ${this.param(params, data.category_id)}`);
9444
+ if (data.description !== undefined)
9445
+ sets.push(`description = ${this.param(params, data.description)}`);
9446
+ if (data.amount !== undefined)
9447
+ sets.push(`amount = ${this.param(params, data.amount)}`);
9448
+ if (data.currency !== undefined)
9449
+ sets.push(`currency = ${this.param(params, data.currency)}`);
9450
+ if (data.quantity !== undefined)
9451
+ sets.push(`quantity = ${this.param(params, data.quantity)}`);
9452
+ if (data.unit_amount !== undefined)
9453
+ sets.push(`unit_amount = ${this.param(params, data.unit_amount)}`);
9454
+ if (data.calculation_type !== undefined)
9455
+ sets.push(`calculation_type = ${this.param(params, data.calculation_type)}::operations_project_cost_calculation_type_134cdfb49c_enum`);
9456
+ if (data.recurrence_type !== undefined)
9457
+ sets.push(`recurrence_type = ${this.param(params, data.recurrence_type)}::operations_project_cost_recurrence_type_09baf0f043_enum`);
9458
+ if (data.is_billable !== undefined)
9459
+ sets.push(`is_billable = ${this.param(params, data.is_billable)}`);
9460
+ if (data.is_reimbursable !== undefined)
9461
+ sets.push(`is_reimbursable = ${this.param(params, data.is_reimbursable)}`);
9462
+ if (data.cost_date !== undefined)
9463
+ sets.push(`cost_date = ${this.param(params, data.cost_date)}::date`);
9464
+ if (data.period_start !== undefined)
9465
+ sets.push(`period_start = ${this.param(params, data.period_start)}::date`);
9466
+ if (data.period_end !== undefined)
9467
+ sets.push(`period_end = ${this.param(params, data.period_end)}::date`);
9468
+ if (data.notes !== undefined)
9469
+ sets.push(`notes = ${this.param(params, data.notes)}`);
9470
+ if (data.status !== undefined)
9471
+ sets.push(`status = ${this.param(params, data.status)}::operations_project_cost_status_153e8592ce_enum`);
9472
+ if (sets.length === 0) {
9473
+ const rows = await this.listProjectCosts(userId, cost.projectId, {});
9474
+ return (_b = rows.find((r) => r.id === id)) !== null && _b !== void 0 ? _b : null;
9475
+ }
9476
+ sets.push(`updated_at = NOW()`);
9477
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost SET ${sets.join(', ')} WHERE id = ${this.param(params, id)}`, ...params);
9478
+ const rows = await this.listProjectCosts(userId, cost.projectId, {});
9479
+ return (_c = rows.find((r) => r.id === id)) !== null && _c !== void 0 ? _c : null;
9480
+ }
9481
+ async deleteProjectCost(userId, id) {
9482
+ const actor = await this.getActorContext(userId);
9483
+ this.ensureSupervisor(actor);
9484
+ const cost = await this.querySingle(`SELECT id FROM operations_project_cost WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
9485
+ if (!cost) {
9486
+ throw new common_1.NotFoundException('Project cost not found.');
9487
+ }
9488
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost SET deleted_at = NOW() WHERE id = $1`, id);
9489
+ return { success: true };
9490
+ }
7767
9491
  };
7768
9492
  exports.OperationsService = OperationsService;
7769
9493
  exports.OperationsService = OperationsService = OperationsService_1 = __decorate([