@hed-hog/operations 0.0.322 → 0.0.325

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 (689) hide show
  1. package/dist/controllers/operations-collaborators.controller.d.ts +9 -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 +562 -0
  77. package/dist/operations.service.d.ts.map +1 -1
  78. package/dist/operations.service.js +1657 -47
  79. package/dist/operations.service.js.map +1 -1
  80. package/hedhog/data/menu.yaml +52 -0
  81. package/hedhog/data/operations_project_cost_category.yaml +80 -0
  82. package/hedhog/data/operations_project_cost_type.yaml +503 -0
  83. package/hedhog/data/route.yaml +274 -0
  84. package/hedhog/frontend/app/_components/collaborator-costs-section.tsx.ejs +2 -18
  85. package/hedhog/frontend/app/_components/collaborator-form-screen.tsx.ejs +185 -276
  86. package/hedhog/frontend/app/_components/collaborator-tasks-tab.tsx.ejs +358 -0
  87. package/hedhog/frontend/app/_components/collaborator-timesheets-tab.tsx.ejs +242 -0
  88. package/hedhog/frontend/app/_components/my-project-summary-screen.tsx.ejs +167 -59
  89. package/hedhog/frontend/app/_components/person-select-with-create.tsx.ejs +1 -853
  90. package/hedhog/frontend/app/_components/project-assignments-tab.tsx.ejs +450 -0
  91. package/hedhog/frontend/app/_components/project-cost-report-screen.tsx.ejs +602 -0
  92. package/hedhog/frontend/app/_components/project-costs-section.tsx.ejs +1401 -0
  93. package/hedhog/frontend/app/_components/project-details-screen.tsx.ejs +2003 -1846
  94. package/hedhog/frontend/app/_components/project-form-screen.tsx.ejs +56 -11
  95. package/hedhog/frontend/app/_components/task-detail-sheet.tsx.ejs +297 -2
  96. package/hedhog/frontend/app/_components/task-form-sheet.tsx.ejs +530 -0
  97. package/hedhog/frontend/app/_lib/api.ts.ejs +247 -0
  98. package/hedhog/frontend/app/_lib/types.ts.ejs +196 -7
  99. package/hedhog/frontend/app/_lib/utils/format.ts.ejs +9 -3
  100. package/hedhog/frontend/app/collaborators/page.tsx.ejs +18 -7
  101. package/hedhog/frontend/app/my-tasks/page.tsx.ejs +219 -122
  102. package/hedhog/frontend/app/project-cost-categories/page.tsx.ejs +674 -0
  103. package/hedhog/frontend/app/project-cost-types/page.tsx.ejs +845 -0
  104. package/hedhog/frontend/app/projects/[id]/costs-report/page.tsx.ejs +10 -0
  105. package/hedhog/frontend/app/reports/collaborators/page.tsx.ejs +20 -349
  106. package/hedhog/frontend/app/reports/projects/page.tsx.ejs +192 -484
  107. package/hedhog/frontend/messages/en.json +279 -10
  108. package/hedhog/frontend/messages/en.json.ejs +2043 -0
  109. package/hedhog/frontend/messages/operations/en.json +2068 -0
  110. package/hedhog/frontend/messages/operations/operations/en.json +2102 -0
  111. package/hedhog/frontend/messages/operations/operations/pt.json +2111 -0
  112. package/hedhog/frontend/messages/operations/pt.json +2072 -0
  113. package/hedhog/frontend/messages/pt.json +284 -13
  114. package/hedhog/frontend/messages/pt.json.ejs +2056 -0
  115. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.d.ts +29 -0
  116. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.d.ts.map +1 -0
  117. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.js +95 -0
  118. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.js.map +1 -0
  119. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/async-options-combobox.tsx +233 -0
  120. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.d.ts +10 -0
  121. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.d.ts.map +1 -0
  122. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.js +577 -0
  123. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.js.map +1 -0
  124. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-costs-section.tsx +868 -0
  125. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.d.ts +4 -0
  126. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.d.ts.map +1 -0
  127. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.js +337 -0
  128. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.js.map +1 -0
  129. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-details-screen.tsx +476 -0
  130. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.d.ts +9 -0
  131. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.d.ts.map +1 -0
  132. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.js +1348 -0
  133. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.js.map +1 -0
  134. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-form-screen.tsx +2233 -0
  135. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.d.ts +12 -0
  136. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.d.ts.map +1 -0
  137. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.js +162 -0
  138. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.js.map +1 -0
  139. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/collaborator-select-with-create.tsx +261 -0
  140. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.d.ts +18 -0
  141. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.d.ts.map +1 -0
  142. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.js +145 -0
  143. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.js.map +1 -0
  144. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-content-editor.tsx +258 -0
  145. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.d.ts +4 -0
  146. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.d.ts.map +1 -0
  147. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.js +223 -0
  148. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.js.map +1 -0
  149. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-details-screen.tsx +342 -0
  150. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.d.ts +58 -0
  151. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.d.ts.map +1 -0
  152. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.js +438 -0
  153. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.js.map +1 -0
  154. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/contract-form-screen.tsx +698 -0
  155. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.d.ts +20 -0
  156. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.d.ts.map +1 -0
  157. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.js +233 -0
  158. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.js.map +1 -0
  159. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/department-select-with-create.tsx +392 -0
  160. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.d.ts +4 -0
  161. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.d.ts.map +1 -0
  162. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.js +814 -0
  163. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.js.map +1 -0
  164. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/my-project-summary-screen.tsx +1288 -0
  165. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.d.ts +21 -0
  166. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.d.ts.map +1 -0
  167. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.js +174 -0
  168. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.js.map +1 -0
  169. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-calendar-view.tsx +306 -0
  170. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.d.ts +10 -0
  171. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.d.ts.map +1 -0
  172. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.js +12 -0
  173. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.js.map +1 -0
  174. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/operations-header.tsx +29 -0
  175. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.d.ts +15 -0
  176. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.d.ts.map +1 -0
  177. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.js +501 -0
  178. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.js.map +1 -0
  179. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/person-select-with-create.tsx +853 -0
  180. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.d.ts +6 -0
  181. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.d.ts.map +1 -0
  182. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.js +847 -0
  183. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.js.map +1 -0
  184. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-costs-section.tsx +1340 -0
  185. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.d.ts +4 -0
  186. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.d.ts.map +1 -0
  187. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.js +2930 -0
  188. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.js.map +1 -0
  189. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-details-screen.tsx +4378 -0
  190. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.d.ts +9 -0
  191. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.d.ts.map +1 -0
  192. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.js +1013 -0
  193. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.js.map +1 -0
  194. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/project-form-screen.tsx +1745 -0
  195. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.d.ts +13 -0
  196. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.d.ts.map +1 -0
  197. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.js +38 -0
  198. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.js.map +1 -0
  199. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/section-card.tsx +74 -0
  200. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.d.ts +7 -0
  201. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.d.ts.map +1 -0
  202. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.js +11 -0
  203. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.js.map +1 -0
  204. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/status-badge.tsx +15 -0
  205. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.d.ts +18 -0
  206. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.d.ts.map +1 -0
  207. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.js +406 -0
  208. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.js.map +1 -0
  209. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/system-user-select-with-create.tsx +660 -0
  210. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.d.ts +26 -0
  211. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.d.ts.map +1 -0
  212. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.js +332 -0
  213. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.js.map +1 -0
  214. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-detail-sheet.tsx +518 -0
  215. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.d.ts +6 -0
  216. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.d.ts.map +1 -0
  217. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.js +255 -0
  218. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.js.map +1 -0
  219. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/task-file-attachments.tsx +388 -0
  220. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.d.ts +10 -0
  221. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.d.ts.map +1 -0
  222. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.js +131 -0
  223. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.js.map +1 -0
  224. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_components/timesheet-task-create-sheet.tsx +214 -0
  225. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.d.ts +108 -0
  226. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.d.ts.map +1 -0
  227. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.js +162 -0
  228. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.js.map +1 -0
  229. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/api.ts +428 -0
  230. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.d.ts +8 -0
  231. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.d.ts.map +1 -0
  232. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.js +36 -0
  233. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.js.map +1 -0
  234. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/hooks/use-operations-access.ts +44 -0
  235. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts +836 -0
  236. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.d.ts.map +1 -0
  237. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.js +3 -0
  238. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.js.map +1 -0
  239. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/types.ts +860 -0
  240. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.d.ts +16 -0
  241. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.d.ts.map +1 -0
  242. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.js +182 -0
  243. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.js.map +1 -0
  244. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/format.ts +250 -0
  245. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.d.ts +4 -0
  246. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.d.ts.map +1 -0
  247. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.js +51 -0
  248. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.js.map +1 -0
  249. package/hedhog/frontend/src/app/(app)/(libraries)/operations/_lib/utils/forms.ts +61 -0
  250. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.d.ts +2 -0
  251. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.d.ts.map +1 -0
  252. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.js +954 -0
  253. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.js.map +1 -0
  254. package/hedhog/frontend/src/app/(app)/(libraries)/operations/approvals/page.tsx +1277 -0
  255. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.d.ts +2 -0
  256. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.d.ts.map +1 -0
  257. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.js +488 -0
  258. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.js.map +1 -0
  259. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborator-types/page.tsx +805 -0
  260. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.d.ts +6 -0
  261. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.d.ts.map +1 -0
  262. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.js +9 -0
  263. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.js.map +1 -0
  264. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/edit/page.tsx +11 -0
  265. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.d.ts +6 -0
  266. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.d.ts.map +1 -0
  267. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.js +9 -0
  268. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.js.map +1 -0
  269. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/[id]/page.tsx +11 -0
  270. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.d.ts +2 -0
  271. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.d.ts.map +1 -0
  272. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.js +8 -0
  273. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.js.map +1 -0
  274. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/new/page.tsx +5 -0
  275. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.d.ts +2 -0
  276. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.d.ts.map +1 -0
  277. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.js +612 -0
  278. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.js.map +1 -0
  279. package/hedhog/frontend/src/app/(app)/(libraries)/operations/collaborators/page.tsx +939 -0
  280. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.d.ts +6 -0
  281. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.d.ts.map +1 -0
  282. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.js +9 -0
  283. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.js.map +1 -0
  284. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/edit/page.tsx +11 -0
  285. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.d.ts +6 -0
  286. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.d.ts.map +1 -0
  287. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.js +9 -0
  288. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.js.map +1 -0
  289. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/[id]/page.tsx +11 -0
  290. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.d.ts +6 -0
  291. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.d.ts.map +1 -0
  292. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.js +9 -0
  293. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.js.map +1 -0
  294. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/new/page.tsx +17 -0
  295. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.d.ts +2 -0
  296. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.d.ts.map +1 -0
  297. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.js +348 -0
  298. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.js.map +1 -0
  299. package/hedhog/frontend/src/app/(app)/(libraries)/operations/contracts/page.tsx +536 -0
  300. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.d.ts +2 -0
  301. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.d.ts.map +1 -0
  302. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.js +401 -0
  303. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.js.map +1 -0
  304. package/hedhog/frontend/src/app/(app)/(libraries)/operations/departments/page.tsx +607 -0
  305. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.d.ts +5 -0
  306. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.d.ts.map +1 -0
  307. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.js +7 -0
  308. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.js.map +1 -0
  309. package/hedhog/frontend/src/app/(app)/(libraries)/operations/layout.tsx +9 -0
  310. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.d.ts +6 -0
  311. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.d.ts.map +1 -0
  312. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.js +9 -0
  313. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.js.map +1 -0
  314. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/[id]/page.tsx +11 -0
  315. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.d.ts +2 -0
  316. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.d.ts.map +1 -0
  317. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.js +321 -0
  318. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.js.map +1 -0
  319. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-projects/page.tsx +440 -0
  320. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.d.ts +2 -0
  321. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.d.ts.map +1 -0
  322. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.js +939 -0
  323. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.js.map +1 -0
  324. package/hedhog/frontend/src/app/(app)/(libraries)/operations/my-tasks/page.tsx +1499 -0
  325. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.d.ts +29 -0
  326. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.d.ts.map +1 -0
  327. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.js +95 -0
  328. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.js.map +1 -0
  329. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/async-options-combobox.tsx +233 -0
  330. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.d.ts +10 -0
  331. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.d.ts.map +1 -0
  332. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.js +577 -0
  333. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.js.map +1 -0
  334. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-costs-section.tsx +868 -0
  335. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.d.ts +4 -0
  336. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.d.ts.map +1 -0
  337. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.js +337 -0
  338. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.js.map +1 -0
  339. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-details-screen.tsx +476 -0
  340. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.d.ts +9 -0
  341. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.d.ts.map +1 -0
  342. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.js +1348 -0
  343. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.js.map +1 -0
  344. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-form-screen.tsx +2233 -0
  345. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.d.ts +12 -0
  346. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.d.ts.map +1 -0
  347. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.js +162 -0
  348. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.js.map +1 -0
  349. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/collaborator-select-with-create.tsx +261 -0
  350. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.d.ts +18 -0
  351. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.d.ts.map +1 -0
  352. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.js +145 -0
  353. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.js.map +1 -0
  354. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-content-editor.tsx +258 -0
  355. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.d.ts +4 -0
  356. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.d.ts.map +1 -0
  357. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.js +223 -0
  358. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.js.map +1 -0
  359. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-details-screen.tsx +342 -0
  360. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.d.ts +58 -0
  361. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.d.ts.map +1 -0
  362. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.js +438 -0
  363. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.js.map +1 -0
  364. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/contract-form-screen.tsx +698 -0
  365. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.d.ts +20 -0
  366. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.d.ts.map +1 -0
  367. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.js +233 -0
  368. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.js.map +1 -0
  369. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/department-select-with-create.tsx +392 -0
  370. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.d.ts +4 -0
  371. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.d.ts.map +1 -0
  372. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.js +814 -0
  373. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.js.map +1 -0
  374. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/my-project-summary-screen.tsx +1288 -0
  375. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.d.ts +21 -0
  376. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.d.ts.map +1 -0
  377. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.js +174 -0
  378. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.js.map +1 -0
  379. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-calendar-view.tsx +306 -0
  380. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.d.ts +10 -0
  381. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.d.ts.map +1 -0
  382. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.js +12 -0
  383. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.js.map +1 -0
  384. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/operations-header.tsx +29 -0
  385. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.d.ts +15 -0
  386. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.d.ts.map +1 -0
  387. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.js +501 -0
  388. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.js.map +1 -0
  389. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/person-select-with-create.tsx +853 -0
  390. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.d.ts +6 -0
  391. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.d.ts.map +1 -0
  392. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.js +459 -0
  393. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.js.map +1 -0
  394. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-cost-report-screen.tsx +598 -0
  395. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.d.ts +6 -0
  396. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.d.ts.map +1 -0
  397. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.js +876 -0
  398. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.js.map +1 -0
  399. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-costs-section.tsx +1368 -0
  400. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.d.ts +4 -0
  401. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.d.ts.map +1 -0
  402. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.js +2930 -0
  403. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.js.map +1 -0
  404. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-details-screen.tsx +4378 -0
  405. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.d.ts +9 -0
  406. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.d.ts.map +1 -0
  407. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.js +1013 -0
  408. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.js.map +1 -0
  409. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/project-form-screen.tsx +1745 -0
  410. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.d.ts +13 -0
  411. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.d.ts.map +1 -0
  412. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.js +38 -0
  413. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.js.map +1 -0
  414. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/section-card.tsx +74 -0
  415. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.d.ts +7 -0
  416. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.d.ts.map +1 -0
  417. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.js +11 -0
  418. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.js.map +1 -0
  419. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/status-badge.tsx +15 -0
  420. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.d.ts +18 -0
  421. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.d.ts.map +1 -0
  422. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.js +406 -0
  423. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.js.map +1 -0
  424. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/system-user-select-with-create.tsx +660 -0
  425. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.d.ts +26 -0
  426. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.d.ts.map +1 -0
  427. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.js +332 -0
  428. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.js.map +1 -0
  429. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-detail-sheet.tsx +518 -0
  430. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.d.ts +6 -0
  431. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.d.ts.map +1 -0
  432. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.js +255 -0
  433. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.js.map +1 -0
  434. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/task-file-attachments.tsx +388 -0
  435. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.d.ts +10 -0
  436. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.d.ts.map +1 -0
  437. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.js +131 -0
  438. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.js.map +1 -0
  439. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_components/timesheet-task-create-sheet.tsx +214 -0
  440. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.d.ts +108 -0
  441. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.d.ts.map +1 -0
  442. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.js +162 -0
  443. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.js.map +1 -0
  444. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/api.ts +428 -0
  445. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.d.ts +8 -0
  446. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.d.ts.map +1 -0
  447. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.js +36 -0
  448. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.js.map +1 -0
  449. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/hooks/use-operations-access.ts +44 -0
  450. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts +836 -0
  451. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.d.ts.map +1 -0
  452. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.js +3 -0
  453. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.js.map +1 -0
  454. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/types.ts +860 -0
  455. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.d.ts +16 -0
  456. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.d.ts.map +1 -0
  457. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.js +182 -0
  458. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.js.map +1 -0
  459. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/format.ts +250 -0
  460. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.d.ts +4 -0
  461. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.d.ts.map +1 -0
  462. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.js +51 -0
  463. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.js.map +1 -0
  464. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/_lib/utils/forms.ts +61 -0
  465. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.d.ts +2 -0
  466. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.d.ts.map +1 -0
  467. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.js +954 -0
  468. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.js.map +1 -0
  469. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/approvals/page.tsx +1277 -0
  470. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.d.ts +2 -0
  471. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.d.ts.map +1 -0
  472. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.js +488 -0
  473. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.js.map +1 -0
  474. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborator-types/page.tsx +805 -0
  475. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.d.ts +6 -0
  476. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.d.ts.map +1 -0
  477. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.js +9 -0
  478. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.js.map +1 -0
  479. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/edit/page.tsx +11 -0
  480. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.d.ts +6 -0
  481. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.d.ts.map +1 -0
  482. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.js +9 -0
  483. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.js.map +1 -0
  484. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/[id]/page.tsx +11 -0
  485. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.d.ts +2 -0
  486. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.d.ts.map +1 -0
  487. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.js +8 -0
  488. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.js.map +1 -0
  489. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/new/page.tsx +5 -0
  490. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.d.ts +2 -0
  491. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.d.ts.map +1 -0
  492. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.js +612 -0
  493. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.js.map +1 -0
  494. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/collaborators/page.tsx +939 -0
  495. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.d.ts +6 -0
  496. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.d.ts.map +1 -0
  497. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.js +9 -0
  498. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.js.map +1 -0
  499. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/edit/page.tsx +11 -0
  500. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.d.ts +6 -0
  501. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.d.ts.map +1 -0
  502. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.js +9 -0
  503. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.js.map +1 -0
  504. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/[id]/page.tsx +11 -0
  505. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.d.ts +6 -0
  506. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.d.ts.map +1 -0
  507. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.js +9 -0
  508. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.js.map +1 -0
  509. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/new/page.tsx +17 -0
  510. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.d.ts +2 -0
  511. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.d.ts.map +1 -0
  512. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.js +348 -0
  513. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.js.map +1 -0
  514. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/contracts/page.tsx +536 -0
  515. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.d.ts +2 -0
  516. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.d.ts.map +1 -0
  517. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.js +401 -0
  518. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.js.map +1 -0
  519. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/departments/page.tsx +607 -0
  520. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.d.ts +5 -0
  521. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.d.ts.map +1 -0
  522. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.js +7 -0
  523. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.js.map +1 -0
  524. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/layout.tsx +9 -0
  525. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.d.ts +6 -0
  526. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.d.ts.map +1 -0
  527. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.js +9 -0
  528. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.js.map +1 -0
  529. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/[id]/page.tsx +11 -0
  530. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.d.ts +2 -0
  531. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.d.ts.map +1 -0
  532. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.js +321 -0
  533. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.js.map +1 -0
  534. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-projects/page.tsx +440 -0
  535. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.d.ts +2 -0
  536. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.d.ts.map +1 -0
  537. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.js +939 -0
  538. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.js.map +1 -0
  539. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/my-tasks/page.tsx +1499 -0
  540. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.d.ts +2 -0
  541. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.d.ts.map +1 -0
  542. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.js +8 -0
  543. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.js.map +1 -0
  544. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/page.tsx +5 -0
  545. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.d.ts +2 -0
  546. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.d.ts.map +1 -0
  547. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.js +436 -0
  548. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.js.map +1 -0
  549. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-categories/page.tsx +675 -0
  550. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.d.ts +2 -0
  551. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.d.ts.map +1 -0
  552. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.js +563 -0
  553. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.js.map +1 -0
  554. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/project-cost-types/page.tsx +846 -0
  555. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.d.ts +6 -0
  556. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.d.ts.map +1 -0
  557. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.js +9 -0
  558. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.js.map +1 -0
  559. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/costs-report/page.tsx +10 -0
  560. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.d.ts +6 -0
  561. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.d.ts.map +1 -0
  562. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.js +9 -0
  563. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.js.map +1 -0
  564. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/edit/page.tsx +11 -0
  565. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.d.ts +6 -0
  566. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.d.ts.map +1 -0
  567. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.js +9 -0
  568. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.js.map +1 -0
  569. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/[id]/page.tsx +11 -0
  570. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.d.ts +2 -0
  571. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.d.ts.map +1 -0
  572. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.js +8 -0
  573. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.js.map +1 -0
  574. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/new/page.tsx +5 -0
  575. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.d.ts +2 -0
  576. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.d.ts.map +1 -0
  577. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.js +492 -0
  578. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.js.map +1 -0
  579. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/projects/page.tsx +757 -0
  580. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.d.ts +2 -0
  581. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.d.ts.map +1 -0
  582. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.js +342 -0
  583. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.js.map +1 -0
  584. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/collaborators/page.tsx +430 -0
  585. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.d.ts +2 -0
  586. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.d.ts.map +1 -0
  587. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.js +338 -0
  588. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.js.map +1 -0
  589. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/reports/projects/page.tsx +428 -0
  590. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.d.ts +2 -0
  591. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.d.ts.map +1 -0
  592. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.js +660 -0
  593. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.js.map +1 -0
  594. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/schedule-adjustments/page.tsx +992 -0
  595. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.d.ts +2 -0
  596. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.d.ts.map +1 -0
  597. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.js +515 -0
  598. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.js.map +1 -0
  599. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/time-off/page.tsx +707 -0
  600. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.d.ts +2 -0
  601. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.d.ts.map +1 -0
  602. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.js +1141 -0
  603. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.js.map +1 -0
  604. package/hedhog/frontend/src/app/(app)/(libraries)/operations/operations/timesheets/page.tsx +1705 -0
  605. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.d.ts +2 -0
  606. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.d.ts.map +1 -0
  607. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.js +8 -0
  608. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.js.map +1 -0
  609. package/hedhog/frontend/src/app/(app)/(libraries)/operations/page.tsx +5 -0
  610. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.d.ts +2 -0
  611. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.d.ts.map +1 -0
  612. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.js +436 -0
  613. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.js.map +1 -0
  614. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-categories/page.tsx +675 -0
  615. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.d.ts +2 -0
  616. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.d.ts.map +1 -0
  617. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.js +563 -0
  618. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.js.map +1 -0
  619. package/hedhog/frontend/src/app/(app)/(libraries)/operations/project-cost-types/page.tsx +846 -0
  620. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.d.ts +6 -0
  621. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.d.ts.map +1 -0
  622. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.js +9 -0
  623. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.js.map +1 -0
  624. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/edit/page.tsx +11 -0
  625. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.d.ts +6 -0
  626. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.d.ts.map +1 -0
  627. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.js +9 -0
  628. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.js.map +1 -0
  629. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/[id]/page.tsx +11 -0
  630. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.d.ts +2 -0
  631. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.d.ts.map +1 -0
  632. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.js +8 -0
  633. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.js.map +1 -0
  634. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/new/page.tsx +5 -0
  635. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.d.ts +2 -0
  636. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.d.ts.map +1 -0
  637. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.js +492 -0
  638. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.js.map +1 -0
  639. package/hedhog/frontend/src/app/(app)/(libraries)/operations/projects/page.tsx +757 -0
  640. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.d.ts +2 -0
  641. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.d.ts.map +1 -0
  642. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.js +342 -0
  643. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.js.map +1 -0
  644. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/collaborators/page.tsx +430 -0
  645. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.d.ts +2 -0
  646. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.d.ts.map +1 -0
  647. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.js +338 -0
  648. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.js.map +1 -0
  649. package/hedhog/frontend/src/app/(app)/(libraries)/operations/reports/projects/page.tsx +428 -0
  650. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.d.ts +2 -0
  651. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.d.ts.map +1 -0
  652. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.js +660 -0
  653. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.js.map +1 -0
  654. package/hedhog/frontend/src/app/(app)/(libraries)/operations/schedule-adjustments/page.tsx +992 -0
  655. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.d.ts +2 -0
  656. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.d.ts.map +1 -0
  657. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.js +515 -0
  658. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.js.map +1 -0
  659. package/hedhog/frontend/src/app/(app)/(libraries)/operations/time-off/page.tsx +707 -0
  660. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.d.ts +2 -0
  661. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.d.ts.map +1 -0
  662. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.js +1141 -0
  663. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.js.map +1 -0
  664. package/hedhog/frontend/src/app/(app)/(libraries)/operations/timesheets/page.tsx +1705 -0
  665. package/hedhog/table/operations_project_assignment.yaml +1 -0
  666. package/hedhog/table/operations_project_cost.yaml +93 -0
  667. package/hedhog/table/operations_project_cost_category.yaml +37 -0
  668. package/hedhog/table/operations_project_cost_type.yaml +55 -0
  669. package/hedhog/table/operations_task_comment.yaml +26 -0
  670. package/package.json +6 -6
  671. package/src/controllers/operations-collaborators.controller.ts +26 -0
  672. package/src/controllers/operations-project-costs.controller.ts +249 -0
  673. package/src/controllers/operations-tasks.controller.ts +49 -0
  674. package/src/dto/create-collaborator-project-assignment.dto.ts +14 -0
  675. package/src/dto/create-project-cost-category.dto.ts +37 -0
  676. package/src/dto/create-project-cost-type.dto.ts +64 -0
  677. package/src/dto/create-project-cost.dto.ts +126 -0
  678. package/src/dto/get-project-cost-report.dto.ts +46 -0
  679. package/src/dto/list-project-cost-categories.dto.ts +17 -0
  680. package/src/dto/list-project-cost-types.dto.ts +28 -0
  681. package/src/dto/list-project-costs.dto.ts +59 -0
  682. package/src/dto/list-tasks.dto.ts +7 -0
  683. package/src/dto/list-timesheets.dto.ts +7 -1
  684. package/src/dto/update-collaborator-project-assignment.dto.ts +58 -0
  685. package/src/dto/update-project-cost-category.dto.ts +4 -0
  686. package/src/dto/update-project-cost-type.dto.ts +4 -0
  687. package/src/dto/update-project-cost.dto.ts +4 -0
  688. package/src/operations.module.ts +2 -0
  689. package/src/operations.service.ts +2274 -39
@@ -1143,6 +1143,62 @@ let OperationsService = OperationsService_1 = class OperationsService {
1143
1143
  });
1144
1144
  return this.getCollaboratorByIdForUser(userId, collaboratorId);
1145
1145
  }
1146
+ async updateCollaboratorProjectAssignment(collaboratorId, projectId, data) {
1147
+ var _a, _b, _c, _d, _e, _f;
1148
+ const sets = [];
1149
+ const params = [collaboratorId, projectId];
1150
+ let idx = 3;
1151
+ if ('projectRoleId' in data) {
1152
+ sets.push(`project_role_id = $${idx++}`);
1153
+ params.push((_a = data.projectRoleId) !== null && _a !== void 0 ? _a : null);
1154
+ }
1155
+ if ('roleLabel' in data) {
1156
+ sets.push(`role_label = $${idx++}`);
1157
+ params.push((_b = data.roleLabel) !== null && _b !== void 0 ? _b : null);
1158
+ }
1159
+ if ('allocationPercent' in data) {
1160
+ sets.push(`allocation_percent = $${idx++}`);
1161
+ params.push((_c = data.allocationPercent) !== null && _c !== void 0 ? _c : null);
1162
+ }
1163
+ if ('weeklyHours' in data) {
1164
+ sets.push(`weekly_hours = $${idx++}`);
1165
+ params.push((_d = data.weeklyHours) !== null && _d !== void 0 ? _d : null);
1166
+ }
1167
+ if ('startDate' in data) {
1168
+ sets.push(`start_date = $${idx++}::date`);
1169
+ params.push((_e = data.startDate) !== null && _e !== void 0 ? _e : null);
1170
+ }
1171
+ if ('endDate' in data) {
1172
+ sets.push(`end_date = $${idx++}::date`);
1173
+ params.push((_f = data.endDate) !== null && _f !== void 0 ? _f : null);
1174
+ }
1175
+ if ('status' in data) {
1176
+ sets.push(`status = $${idx++}::operations_project_assignment_status_155b459bbf_enum`);
1177
+ params.push(data.status);
1178
+ }
1179
+ if (!sets.length)
1180
+ return { updated: false };
1181
+ sets.push(`updated_at = NOW()`);
1182
+ await this.prisma.$executeRawUnsafe(`UPDATE operations_project_assignment
1183
+ SET ${sets.join(', ')}
1184
+ WHERE collaborator_id = $1
1185
+ AND project_id = $2
1186
+ AND deleted_at IS NULL`, ...params);
1187
+ return { updated: true };
1188
+ }
1189
+ async addCollaboratorProjectAssignment(collaboratorId, data) {
1190
+ var _a;
1191
+ const existing = await this.querySingle(`SELECT id FROM operations_project_assignment
1192
+ WHERE collaborator_id = $1 AND project_id = $2 AND deleted_at IS NULL`, [collaboratorId, data.projectId]);
1193
+ if (existing) {
1194
+ return { id: existing.id, created: false };
1195
+ }
1196
+ const row = await this.querySingle(`INSERT INTO operations_project_assignment
1197
+ (collaborator_id, project_id, role_label, status)
1198
+ VALUES ($1, $2, $3, 'active')
1199
+ RETURNING id`, [collaboratorId, data.projectId, (_a = data.roleLabel) !== null && _a !== void 0 ? _a : '']);
1200
+ return { id: row.id, created: true };
1201
+ }
1146
1202
  async getCollaboratorCompensationHistory(userId, collaboratorId) {
1147
1203
  const actor = await this.getActorContext(userId);
1148
1204
  this.ensureDirector(actor);
@@ -1589,6 +1645,10 @@ let OperationsService = OperationsService_1 = class OperationsService {
1589
1645
  if (paginationParams.status) {
1590
1646
  filters.push(`t.status::text = ${this.param(params, paginationParams.status)}`);
1591
1647
  }
1648
+ if (paginationParams.collaboratorId) {
1649
+ const colId = paginationParams.collaboratorId;
1650
+ filters.push(`(pa.collaborator_id = ${this.param(params, colId)} OR t.assignee_collaborator_id = ${this.param(params, colId)})`);
1651
+ }
1592
1652
  const whereClause = filters.join(' AND ');
1593
1653
  const totalRow = await this.querySingle(`SELECT COUNT(*)::text AS total
1594
1654
  FROM operations_task t
@@ -1621,6 +1681,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
1621
1681
  ac.display_name AS "assigneeName",
1622
1682
  au.photo_id AS "assigneeUserPhotoId",
1623
1683
  ap.avatar_id AS "assigneePersonAvatarId",
1684
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
1685
+ COALESCE(task_files.count, 0)::int AS "fileCount",
1624
1686
  t.created_at AS "createdAt",
1625
1687
  t.deleted_at AS "deletedAt"
1626
1688
  FROM operations_task t
@@ -1633,6 +1695,16 @@ let OperationsService = OperationsService_1 = class OperationsService {
1633
1695
  ON au.id = ac.user_id
1634
1696
  LEFT JOIN person ap
1635
1697
  ON ap.id = ac.person_id
1698
+ LEFT JOIN LATERAL (
1699
+ SELECT COUNT(*) AS count
1700
+ FROM operations_task_comment tc
1701
+ WHERE tc.task_id = t.id
1702
+ ) task_comments ON TRUE
1703
+ LEFT JOIN LATERAL (
1704
+ SELECT COUNT(*) AS count
1705
+ FROM operations_task_file tf
1706
+ WHERE tf.operations_task_id = t.id
1707
+ ) task_files ON TRUE
1636
1708
  JOIN operations_project p
1637
1709
  ON p.id = COALESCE(t.project_id, pa.project_id)
1638
1710
  WHERE ${whereClause}
@@ -1844,6 +1916,109 @@ let OperationsService = OperationsService_1 = class OperationsService {
1844
1916
  }
1845
1917
  return { success: true };
1846
1918
  }
1919
+ async listTaskComments(userId, taskId) {
1920
+ const actor = await this.getActorContext(userId);
1921
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
1922
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
1923
+ }
1924
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
1925
+ await this.assertProjectAccess(actor, current.projectId);
1926
+ return this.queryRows(`SELECT tc.id,
1927
+ tc.task_id AS "taskId",
1928
+ tc.content,
1929
+ tc.actor_collaborator_id AS "actorCollaboratorId",
1930
+ actor.display_name AS "actorName",
1931
+ actor_user.photo_id AS "actorUserPhotoId",
1932
+ actor_person.avatar_id AS "actorPersonAvatarId",
1933
+ tc.created_at AS "createdAt",
1934
+ tc.updated_at AS "updatedAt"
1935
+ FROM operations_task_comment tc
1936
+ LEFT JOIN operations_collaborator actor
1937
+ ON actor.id = tc.actor_collaborator_id
1938
+ AND actor.deleted_at IS NULL
1939
+ LEFT JOIN "user" actor_user
1940
+ ON actor_user.id = actor.user_id
1941
+ LEFT JOIN person actor_person
1942
+ ON actor_person.id = actor.person_id
1943
+ WHERE tc.task_id = $1
1944
+ ORDER BY tc.created_at ASC, tc.id ASC`, [taskId]);
1945
+ }
1946
+ async addTaskComment(userId, taskId, content) {
1947
+ var _a, _b;
1948
+ const actor = await this.getActorContext(userId);
1949
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
1950
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
1951
+ }
1952
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
1953
+ await this.assertProjectAccess(actor, current.projectId);
1954
+ const normalizedContent = this.normalizeOptionalText(content);
1955
+ if (!normalizedContent) {
1956
+ throw new common_1.BadRequestException('Comment content is required.');
1957
+ }
1958
+ const inserted = await this.queryRows(`INSERT INTO operations_task_comment (
1959
+ task_id,
1960
+ actor_collaborator_id,
1961
+ content,
1962
+ created_at,
1963
+ updated_at
1964
+ ) VALUES ($1, $2, $3, NOW(), NOW())
1965
+ RETURNING id`, [taskId, (_a = actor.collaboratorId) !== null && _a !== void 0 ? _a : null, normalizedContent]);
1966
+ const commentId = (_b = inserted[0]) === null || _b === void 0 ? void 0 : _b.id;
1967
+ const comments = await this.listTaskComments(userId, taskId);
1968
+ const createdComment = comments.find((comment) => comment.id === commentId);
1969
+ if (!createdComment) {
1970
+ throw new common_1.NotFoundException('Task comment could not be loaded.');
1971
+ }
1972
+ return createdComment;
1973
+ }
1974
+ async updateTaskComment(userId, taskId, commentId, content) {
1975
+ var _a;
1976
+ const actor = await this.getActorContext(userId);
1977
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
1978
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
1979
+ }
1980
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
1981
+ await this.assertProjectAccess(actor, current.projectId);
1982
+ const normalizedContent = this.normalizeOptionalText(content);
1983
+ if (!normalizedContent) {
1984
+ throw new common_1.BadRequestException('Comment content is required.');
1985
+ }
1986
+ const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId"
1987
+ FROM operations_task_comment
1988
+ WHERE id = $1 AND task_id = $2`, [commentId, taskId]);
1989
+ const row = rows[0];
1990
+ if (!row) {
1991
+ throw new common_1.NotFoundException('Comment not found.');
1992
+ }
1993
+ if (row.actorCollaboratorId !== actor.collaboratorId) {
1994
+ throw new common_1.ForbiddenException('You can only edit your own comments.');
1995
+ }
1996
+ await this.queryRows(`UPDATE operations_task_comment
1997
+ SET content = $1, updated_at = NOW()
1998
+ WHERE id = $2`, [normalizedContent, commentId]);
1999
+ const comments = await this.listTaskComments(userId, taskId);
2000
+ return (_a = comments.find((c) => c.id === commentId)) !== null && _a !== void 0 ? _a : null;
2001
+ }
2002
+ async removeTaskComment(userId, taskId, commentId) {
2003
+ const actor = await this.getActorContext(userId);
2004
+ if (!actor.isCollaborator && !actor.isDirector && !actor.isSupervisor) {
2005
+ throw new common_1.ForbiddenException('Operations collaborator access is required.');
2006
+ }
2007
+ const current = await this.getTaskRecordForActor(this.prisma, actor, taskId);
2008
+ await this.assertProjectAccess(actor, current.projectId);
2009
+ const rows = await this.queryRows(`SELECT id, actor_collaborator_id AS "actorCollaboratorId"
2010
+ FROM operations_task_comment
2011
+ WHERE id = $1 AND task_id = $2`, [commentId, taskId]);
2012
+ const row = rows[0];
2013
+ if (!row) {
2014
+ throw new common_1.NotFoundException('Comment not found.');
2015
+ }
2016
+ if (row.actorCollaboratorId !== actor.collaboratorId) {
2017
+ throw new common_1.ForbiddenException('You can only delete your own comments.');
2018
+ }
2019
+ await this.queryRows(`DELETE FROM operations_task_comment WHERE id = $1`, [commentId]);
2020
+ return { success: true };
2021
+ }
1847
2022
  async listTimesheetEntries(userId, paginationParams) {
1848
2023
  var _a, _b;
1849
2024
  const actor = await this.getActorContext(userId);
@@ -3055,6 +3230,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
3055
3230
  if (filters.dateTo) {
3056
3231
  where.push(`t.week_start_date <= ${this.param(params, filters.dateTo)}::date`);
3057
3232
  }
3233
+ if (filters.collaboratorId) {
3234
+ where.push(`t.collaborator_id = ${this.param(params, filters.collaboratorId)}`);
3235
+ }
3058
3236
  if (pagination === null || pagination === void 0 ? void 0 : pagination.search) {
3059
3237
  const searchPlaceholder = this.param(params, `%${pagination.search}%`);
3060
3238
  where.push(`(
@@ -3088,7 +3266,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
3088
3266
  t.submitted_at AS "submittedAt",
3089
3267
  t.reviewed_at AS "reviewedAt",
3090
3268
  t.notes,
3091
- approval.decision_note AS "decisionNote"
3269
+ approval.decision_note AS "decisionNote",
3270
+ approval.id AS "approvalId"
3092
3271
  FROM operations_timesheet t
3093
3272
  JOIN operations_collaborator c ON c.id = t.collaborator_id
3094
3273
  LEFT JOIN operations_collaborator a ON a.id = t.approver_collaborator_id
@@ -4882,6 +5061,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
4882
5061
  au.photo_id AS "assigneeUserPhotoId",
4883
5062
  ap.avatar_id AS "assigneePersonAvatarId",
4884
5063
  t.project_assignment_id AS "projectAssignmentId",
5064
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
4885
5065
  t.created_at AS "createdAt"
4886
5066
  FROM operations_task t
4887
5067
  LEFT JOIN operations_collaborator ac
@@ -4890,6 +5070,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
4890
5070
  ON au.id = ac.user_id
4891
5071
  LEFT JOIN person ap
4892
5072
  ON ap.id = ac.person_id
5073
+ LEFT JOIN LATERAL (
5074
+ SELECT COUNT(*) AS count
5075
+ FROM operations_task_comment tc
5076
+ WHERE tc.task_id = t.id
5077
+ ) task_comments ON TRUE
4893
5078
  WHERE COALESCE(t.project_id, (
4894
5079
  SELECT pa.project_id FROM operations_project_assignment pa
4895
5080
  WHERE pa.id = t.project_assignment_id AND pa.deleted_at IS NULL
@@ -4916,6 +5101,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
4916
5101
  ap.avatar_id AS "assigneePersonAvatarId",
4917
5102
  t.project_assignment_id AS "projectAssignmentId",
4918
5103
  COALESCE(t.project_id, pa.project_id) AS "projectId",
5104
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
4919
5105
  t.created_at AS "createdAt",
4920
5106
  t.deleted_at AS "deletedAt"
4921
5107
  FROM operations_task t
@@ -4925,6 +5111,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
4925
5111
  LEFT JOIN person ap ON ap.id = ac.person_id
4926
5112
  LEFT JOIN operations_project_assignment pa
4927
5113
  ON pa.id = t.project_assignment_id AND pa.deleted_at IS NULL
5114
+ LEFT JOIN LATERAL (
5115
+ SELECT COUNT(*) AS count
5116
+ FROM operations_task_comment tc
5117
+ WHERE tc.task_id = t.id
5118
+ ) task_comments ON TRUE
4928
5119
  WHERE t.id = $1`, [taskId]);
4929
5120
  return (_a = rows[0]) !== null && _a !== void 0 ? _a : null;
4930
5121
  }
@@ -6919,12 +7110,18 @@ let OperationsService = OperationsService_1 = class OperationsService {
6919
7110
  au.photo_id AS "assigneeUserPhotoId",
6920
7111
  ap.avatar_id AS "assigneePersonAvatarId",
6921
7112
  t.project_assignment_id AS "projectAssignmentId",
7113
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
6922
7114
  t.created_at AS "createdAt"
6923
7115
  FROM operations_task t
6924
7116
  LEFT JOIN operations_collaborator ac
6925
7117
  ON ac.id = t.assignee_collaborator_id AND ac.deleted_at IS NULL
6926
7118
  LEFT JOIN "user" au ON au.id = ac.user_id
6927
7119
  LEFT JOIN person ap ON ap.id = ac.person_id
7120
+ LEFT JOIN LATERAL (
7121
+ SELECT COUNT(*) AS count
7122
+ FROM operations_task_comment tc
7123
+ WHERE tc.task_id = t.id
7124
+ ) task_comments ON TRUE
6928
7125
  WHERE COALESCE(t.project_id, (
6929
7126
  SELECT pa.project_id FROM operations_project_assignment pa
6930
7127
  WHERE pa.id = t.project_assignment_id AND pa.deleted_at IS NULL
@@ -6964,7 +7161,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
6964
7161
  )`,
6965
7162
  ];
6966
7163
  if (actor.collaboratorId) {
6967
- filters.push(`pa.collaborator_id = ${this.param(params, actor.collaboratorId)}`);
7164
+ const p1 = this.param(params, actor.collaboratorId);
7165
+ const p2 = this.param(params, actor.collaboratorId);
7166
+ filters.push(`(pa.collaborator_id = ${p1} OR t.assignee_collaborator_id = ${p2})`);
6968
7167
  }
6969
7168
  if (pagination.search) {
6970
7169
  const searchPlaceholder = this.param(params, `%${pagination.search}%`);
@@ -7010,6 +7209,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
7010
7209
  ac.display_name AS "assigneeName",
7011
7210
  au.photo_id AS "assigneeUserPhotoId",
7012
7211
  ap.avatar_id AS "assigneePersonAvatarId",
7212
+ COALESCE(task_comments.count, 0)::int AS "commentCount",
7013
7213
  t.created_at AS "createdAt",
7014
7214
  t.deleted_at AS "deletedAt"
7015
7215
  FROM operations_task t
@@ -7022,6 +7222,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
7022
7222
  ON au.id = ac.user_id
7023
7223
  LEFT JOIN person ap
7024
7224
  ON ap.id = ac.person_id
7225
+ LEFT JOIN LATERAL (
7226
+ SELECT COUNT(*) AS count
7227
+ FROM operations_task_comment tc
7228
+ WHERE tc.task_id = t.id
7229
+ ) task_comments ON TRUE
7025
7230
  JOIN operations_project p
7026
7231
  ON p.id = COALESCE(t.project_id, pa.project_id)
7027
7232
  WHERE ${whereClause}
@@ -7173,7 +7378,12 @@ let OperationsService = OperationsService_1 = class OperationsService {
7173
7378
  : scenario === 'conservative'
7174
7379
  ? { revenue: 0.9, cost: 0.96, backlog: 0.82 }
7175
7380
  : { revenue: 1, cost: 1, backlog: 1 };
7176
- const params = [from, to];
7381
+ const fromDate = new Date(`${from}T00:00:00`);
7382
+ const toDate = new Date(`${to}T00:00:00`);
7383
+ const periodDays = Math.max(1, Math.floor((toDate.getTime() - fromDate.getTime()) / 86400000) + 1);
7384
+ const periodWeeks = Math.max(1, Math.ceil(periodDays / 7));
7385
+ const periodMonths = periodDays / 30.4375;
7386
+ const params = [from, to, periodMonths, periodWeeks];
7177
7387
  const where = [
7178
7388
  'p.deleted_at IS NULL',
7179
7389
  '(p.end_date IS NULL OR p.end_date >= $1::date)',
@@ -7196,6 +7406,8 @@ let OperationsService = OperationsService_1 = class OperationsService {
7196
7406
  COALESCE(assignment_stats.weekly_hours, 0)::text AS "weeklyHours",
7197
7407
  COALESCE(time_stats.actual_hours, 0)::text AS "actualHours",
7198
7408
  COALESCE(time_stats.billable_hours, 0)::text AS "billableHours",
7409
+ COALESCE(cost_stats.realized_cost, 0)::text AS "realizedCost",
7410
+ COALESCE(alloc_cost_stats.allocated_cost, 0)::text AS "allocatedCost",
7199
7411
  COALESCE(task_stats.open_tasks, 0)::text AS "openTasks",
7200
7412
  COALESCE(task_stats.backlog_hours, 0)::text AS "backlogHours",
7201
7413
  COALESCE(task_stats.future_deliveries, 0)::text AS "futureDeliveries"
@@ -7224,6 +7436,146 @@ let OperationsService = OperationsService_1 = class OperationsService {
7224
7436
  AND entry.deleted_at IS NULL
7225
7437
  AND entry.work_date BETWEEN $1::date AND $2::date
7226
7438
  ) time_stats ON TRUE
7439
+ LEFT JOIN LATERAL (
7440
+ SELECT COALESCE(
7441
+ SUM(
7442
+ entry.hours
7443
+ * (
7444
+ (
7445
+ COALESCE(collaborator_costs.salary_cost, 0)
7446
+ + COALESCE(collaborator_costs.benefits_cost, 0)
7447
+ + COALESCE(collaborator_costs.taxes_cost, 0)
7448
+ + COALESCE(collaborator_costs.tools_cost, 0)
7449
+ )
7450
+ * $3::numeric
7451
+ / GREATEST(
7452
+ COALESCE(collaborator_record.weekly_capacity_hours, 40)::numeric * $4::numeric,
7453
+ COALESCE(collaborator_hours.total_hours, 0),
7454
+ 1
7455
+ )
7456
+ )
7457
+ ),
7458
+ 0
7459
+ ) AS realized_cost
7460
+ FROM operations_timesheet_entry entry
7461
+ JOIN operations_project_assignment pa
7462
+ ON pa.id = entry.project_assignment_id
7463
+ AND pa.deleted_at IS NULL
7464
+ JOIN operations_collaborator collaborator_record
7465
+ ON collaborator_record.id = pa.collaborator_id
7466
+ AND collaborator_record.deleted_at IS NULL
7467
+ LEFT JOIN LATERAL (
7468
+ SELECT COALESCE(NULLIF(cost_totals.salary_cost, 0), compensation_history.amount, hiring_contract.budget_amount, 0) AS salary_cost,
7469
+ cost_totals.benefits_cost,
7470
+ cost_totals.taxes_cost,
7471
+ cost_totals.tools_cost
7472
+ FROM (
7473
+ SELECT COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('salario-base', 'pro-labore')), 0) AS salary_cost,
7474
+ 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,
7475
+ 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,
7476
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('software-licenca', 'equipamento')), 0) AS tools_cost
7477
+ FROM operations_collaborator_cost cost
7478
+ LEFT JOIN operations_cost_type cost_type
7479
+ ON cost_type.id = cost.cost_type_id
7480
+ WHERE cost.collaborator_id = collaborator_record.id
7481
+ AND (cost.start_date IS NULL OR cost.start_date <= $2::date)
7482
+ AND (cost.end_date IS NULL OR cost.end_date >= $1::date)
7483
+ ) cost_totals
7484
+ LEFT JOIN LATERAL (
7485
+ SELECT h.amount
7486
+ FROM operations_collaborator_compensation_history h
7487
+ WHERE h.collaborator_id = collaborator_record.id
7488
+ AND (h.effective_date IS NULL OR h.effective_date <= $2::date)
7489
+ ORDER BY h.effective_date DESC NULLS LAST, h.created_at DESC
7490
+ LIMIT 1
7491
+ ) compensation_history ON TRUE
7492
+ LEFT JOIN LATERAL (
7493
+ SELECT oc.budget_amount
7494
+ FROM operations_contract oc
7495
+ WHERE oc.related_collaborator_id = collaborator_record.id
7496
+ AND oc.deleted_at IS NULL
7497
+ ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
7498
+ oc.created_at DESC
7499
+ LIMIT 1
7500
+ ) hiring_contract ON TRUE
7501
+ ) collaborator_costs ON TRUE
7502
+ LEFT JOIN LATERAL (
7503
+ SELECT COALESCE(SUM(entry2.hours), 0) AS total_hours
7504
+ FROM operations_timesheet_entry entry2
7505
+ JOIN operations_project_assignment pa2
7506
+ ON pa2.id = entry2.project_assignment_id
7507
+ AND pa2.deleted_at IS NULL
7508
+ WHERE pa2.collaborator_id = collaborator_record.id
7509
+ AND entry2.deleted_at IS NULL
7510
+ AND entry2.work_date BETWEEN $1::date AND $2::date
7511
+ ) collaborator_hours ON TRUE
7512
+ WHERE pa.project_id = p.id
7513
+ AND entry.deleted_at IS NULL
7514
+ AND entry.work_date BETWEEN $1::date AND $2::date
7515
+ ) cost_stats ON TRUE
7516
+ LEFT JOIN LATERAL (
7517
+ SELECT COALESCE(
7518
+ SUM(
7519
+ pa.weekly_hours
7520
+ * (
7521
+ (
7522
+ COALESCE(alloc_costs.salary_cost, 0)
7523
+ + COALESCE(alloc_costs.benefits_cost, 0)
7524
+ + COALESCE(alloc_costs.taxes_cost, 0)
7525
+ + COALESCE(alloc_costs.tools_cost, 0)
7526
+ )
7527
+ * $3::numeric
7528
+ / GREATEST(
7529
+ COALESCE(alloc_col.weekly_capacity_hours, 40)::numeric,
7530
+ 1
7531
+ )
7532
+ )
7533
+ ),
7534
+ 0
7535
+ ) AS allocated_cost
7536
+ FROM operations_project_assignment pa
7537
+ JOIN operations_collaborator alloc_col
7538
+ ON alloc_col.id = pa.collaborator_id
7539
+ AND alloc_col.deleted_at IS NULL
7540
+ LEFT JOIN LATERAL (
7541
+ SELECT COALESCE(NULLIF(ct.salary_cost, 0), ch.amount, hc.budget_amount, 0) AS salary_cost,
7542
+ ct.benefits_cost,
7543
+ ct.taxes_cost,
7544
+ ct.tools_cost
7545
+ FROM (
7546
+ SELECT COALESCE(SUM(c.amount) FILTER (WHERE c.recurrence::text = 'monthly' AND ct2.slug IN ('salario-base', 'pro-labore')), 0) AS salary_cost,
7547
+ 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,
7548
+ 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,
7549
+ COALESCE(SUM(c.amount) FILTER (WHERE c.recurrence::text = 'monthly' AND ct2.slug IN ('software-licenca', 'equipamento')), 0) AS tools_cost
7550
+ FROM operations_collaborator_cost c
7551
+ LEFT JOIN operations_cost_type ct2
7552
+ ON ct2.id = c.cost_type_id
7553
+ WHERE c.collaborator_id = alloc_col.id
7554
+ AND (c.start_date IS NULL OR c.start_date <= $2::date)
7555
+ AND (c.end_date IS NULL OR c.end_date >= $1::date)
7556
+ ) ct
7557
+ LEFT JOIN LATERAL (
7558
+ SELECT h.amount
7559
+ FROM operations_collaborator_compensation_history h
7560
+ WHERE h.collaborator_id = alloc_col.id
7561
+ AND (h.effective_date IS NULL OR h.effective_date <= $2::date)
7562
+ ORDER BY h.effective_date DESC NULLS LAST, h.created_at DESC
7563
+ LIMIT 1
7564
+ ) ch ON TRUE
7565
+ LEFT JOIN LATERAL (
7566
+ SELECT oc.budget_amount
7567
+ FROM operations_contract oc
7568
+ WHERE oc.related_collaborator_id = alloc_col.id
7569
+ AND oc.deleted_at IS NULL
7570
+ ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
7571
+ oc.created_at DESC
7572
+ LIMIT 1
7573
+ ) hc ON TRUE
7574
+ ) alloc_costs ON TRUE
7575
+ WHERE pa.project_id = p.id
7576
+ AND pa.deleted_at IS NULL
7577
+ AND pa.status IN ('planned', 'active')
7578
+ ) alloc_cost_stats ON TRUE
7227
7579
  LEFT JOIN LATERAL (
7228
7580
  SELECT COUNT(*) FILTER (WHERE task.status IN ('todo', 'doing', 'review')) AS open_tasks,
7229
7581
  COALESCE(SUM(task.estimate_hours) FILTER (WHERE task.status IN ('todo', 'doing', 'review')), 0) AS backlog_hours,
@@ -7234,18 +7586,20 @@ let OperationsService = OperationsService_1 = class OperationsService {
7234
7586
  ) task_stats ON TRUE
7235
7587
  WHERE ${where.join(' AND ')}
7236
7588
  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
7589
  const rows = dbRows
7241
7590
  .map((row) => {
7242
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
7591
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
7243
7592
  const progress = Number((_a = row.progressPercent) !== null && _a !== void 0 ? _a : 0);
7244
7593
  const contractedRevenue = Number((_b = row.contractedRevenue) !== null && _b !== void 0 ? _b : 0);
7245
7594
  const recognizedRevenue = contractedRevenue * (progress / 100);
7246
7595
  const actualHours = Number((_c = row.actualHours) !== null && _c !== void 0 ? _c : 0);
7247
7596
  const plannedHours = Math.max(Number((_d = row.weeklyHours) !== null && _d !== void 0 ? _d : 0) * periodWeeks, actualHours);
7248
- const realizedCost = 0;
7597
+ const realizedCost = Number((_e = row.realizedCost) !== null && _e !== void 0 ? _e : 0);
7598
+ const allocatedCost = Number((_f = row.allocatedCost) !== null && _f !== void 0 ? _f : 0);
7599
+ const consumedHoursCost = realizedCost;
7600
+ const idlenessHours = Math.max(plannedHours - actualHours, 0);
7601
+ const idlenessRate = plannedHours > 0 ? (idlenessHours / plannedHours) * 100 : 0;
7602
+ const idlenessCost = Math.max(allocatedCost - consumedHoursCost, 0);
7249
7603
  const reportStatus = row.status === 'paused'
7250
7604
  ? 'paused'
7251
7605
  : row.status === 'at_risk'
@@ -7261,9 +7615,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
7261
7615
  return {
7262
7616
  id: Number(row.id),
7263
7617
  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, ' '),
7618
+ client: (_g = row.client) !== null && _g !== void 0 ? _g : '-',
7619
+ manager: (_h = row.manager) !== null && _h !== void 0 ? _h : '-',
7620
+ squad: String((_j = row.squad) !== null && _j !== void 0 ? _j : '-').replace(/_/g, ' '),
7267
7621
  status: reportStatus,
7268
7622
  contractType: row.contractType === 'monthly_retainer'
7269
7623
  ? 'retainer'
@@ -7276,7 +7630,7 @@ let OperationsService = OperationsService_1 = class OperationsService {
7276
7630
  contractedRevenue,
7277
7631
  recognizedRevenue,
7278
7632
  realizedCost,
7279
- forecastCost: realizedCost,
7633
+ forecastCost: realizedCost * multiplier.cost,
7280
7634
  teamCost: realizedCost,
7281
7635
  infraCost: 0,
7282
7636
  licenseCost: 0,
@@ -7284,14 +7638,18 @@ let OperationsService = OperationsService_1 = class OperationsService {
7284
7638
  reworkCost: 0,
7285
7639
  plannedHours,
7286
7640
  actualHours,
7287
- billableHours: Number((_h = row.billableHours) !== null && _h !== void 0 ? _h : 0),
7641
+ billableHours: Number((_k = row.billableHours) !== null && _k !== void 0 ? _k : 0),
7288
7642
  reworkHours: 0,
7289
- internalHours: Math.max(actualHours - Number((_j = row.billableHours) !== null && _j !== void 0 ? _j : 0), 0),
7643
+ internalHours: Math.max(actualHours - Number((_l = row.billableHours) !== null && _l !== void 0 ? _l : 0), 0),
7290
7644
  allocatedCapacity: plannedHours ? (actualHours / plannedHours) * 100 : 0,
7291
7645
  physicalProgress: progress,
7292
7646
  financialProgress: contractedRevenue ? (recognizedRevenue / contractedRevenue) * 100 : 0,
7293
7647
  backlogValue: Math.max(contractedRevenue - recognizedRevenue, 0),
7294
- futureDeliveries: Number((_k = row.futureDeliveries) !== null && _k !== void 0 ? _k : 0),
7648
+ futureDeliveries: Number((_m = row.futureDeliveries) !== null && _m !== void 0 ? _m : 0),
7649
+ allocatedCost,
7650
+ consumedHoursCost,
7651
+ idlenessRate,
7652
+ idlenessCost,
7295
7653
  risk,
7296
7654
  recommendation: risk === 'alto'
7297
7655
  ? 'Revisar escopo, prazo ou capacidade alocada.'
@@ -7314,6 +7672,9 @@ let OperationsService = OperationsService_1 = class OperationsService {
7314
7672
  acc.avgDeadline += row.physicalProgress;
7315
7673
  acc.avgAllocation += row.allocatedCapacity;
7316
7674
  acc.atRisk += row.risk === 'alto' ? 1 : 0;
7675
+ acc.allocatedCost += row.allocatedCost;
7676
+ acc.consumedHoursCost += row.consumedHoursCost;
7677
+ acc.idlenessCost += row.idlenessCost;
7317
7678
  return acc;
7318
7679
  }, {
7319
7680
  contractedRevenue: 0,
@@ -7331,12 +7692,21 @@ let OperationsService = OperationsService_1 = class OperationsService {
7331
7692
  avgAllocation: 0,
7332
7693
  atRisk: 0,
7333
7694
  burnRate: 0,
7695
+ allocatedCost: 0,
7696
+ consumedHoursCost: 0,
7697
+ idlenessCost: 0,
7698
+ idlenessRate: 0,
7699
+ plannedProfit: 0,
7334
7700
  });
7335
7701
  summary.profit = summary.recognizedRevenue - summary.realizedCost;
7336
7702
  summary.margin = summary.recognizedRevenue ? (summary.profit / summary.recognizedRevenue) * 100 : 0;
7337
7703
  summary.avgDeadline = rows.length ? summary.avgDeadline / rows.length : 0;
7338
7704
  summary.avgAllocation = rows.length ? summary.avgAllocation / rows.length : 0;
7339
7705
  summary.burnRate = summary.plannedHours ? (summary.actualHours / summary.plannedHours) * 100 : 0;
7706
+ summary.plannedProfit = summary.contractedRevenue - summary.allocatedCost;
7707
+ summary.idlenessRate = summary.plannedHours > 0
7708
+ ? Math.max(0, (summary.plannedHours - summary.actualHours) / summary.plannedHours * 100)
7709
+ : 0;
7340
7710
  const forecast = Array.from({ length: 12 }, (_, index) => {
7341
7711
  const monthDate = new Date(fromDate);
7342
7712
  monthDate.setMonth(fromDate.getMonth() + index);
@@ -7425,6 +7795,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
7425
7795
  : scenario === 'conservative'
7426
7796
  ? { revenue: 0.9, cost: 0.96, capacity: 0.94 }
7427
7797
  : { revenue: 1, cost: 1, capacity: 1 };
7798
+ const fromDate = new Date(`${from}T00:00:00`);
7799
+ const toDate = new Date(`${to}T00:00:00`);
7800
+ const periodDays = Math.max(1, Math.floor((toDate.getTime() - fromDate.getTime()) / 86400000) + 1);
7801
+ const periodWeeks = Math.max(1, Math.ceil(periodDays / 7));
7802
+ const periodMonths = periodDays / 30.4375;
7428
7803
  const params = [from, to];
7429
7804
  const where = [
7430
7805
  'c.deleted_at IS NULL',
@@ -7451,9 +7826,14 @@ let OperationsService = OperationsService_1 = class OperationsService {
7451
7826
  COALESCE(cost_stats.taxes_cost, 0)::text AS "taxesCost",
7452
7827
  COALESCE(cost_stats.tools_cost, 0)::text AS "toolsCost",
7453
7828
  COALESCE(value_stats.billable_value, 0)::text AS "billableValue",
7829
+ COALESCE(assignment_stats.planned_allocated_hours, 0)::text AS "plannedAllocatedHours",
7830
+ COALESCE(assignment_stats.planned_billable_hours, 0)::text AS "plannedBillableHours",
7831
+ COALESCE(task_stats.open_task_hours, 0)::text AS "openTaskHours",
7832
+ COALESCE(task_stats.open_task_billable_hours, 0)::text AS "openTaskBillableHours",
7833
+ COALESCE(task_stats.open_tasks, 0)::text AS "openTasks",
7454
7834
  COALESCE(value_stats.allocated_hours, 0)::text AS "allocatedHours",
7455
7835
  COALESCE(value_stats.billable_hours, 0)::text AS "billableHours",
7456
- COALESCE(project_stats.projects, 0)::text AS projects
7836
+ COALESCE(assignment_stats.projects, 0)::text AS projects
7457
7837
  FROM operations_collaborator c
7458
7838
  LEFT JOIN person person_record ON person_record.id = c.person_id
7459
7839
  LEFT JOIN operations_department department_record
@@ -7466,16 +7846,85 @@ let OperationsService = OperationsService_1 = class OperationsService {
7466
7846
  ON collaborator_type.id = c.collaborator_type_id
7467
7847
  AND collaborator_type.deleted_at IS NULL
7468
7848
  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)
7849
+ SELECT COALESCE(NULLIF(cost_totals.salary_cost, 0), compensation_history.amount, hiring_contract.budget_amount, 0) AS salary_cost,
7850
+ cost_totals.benefits_cost,
7851
+ cost_totals.taxes_cost,
7852
+ cost_totals.tools_cost
7853
+ FROM (
7854
+ SELECT COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('salario-base', 'pro-labore')), 0) AS salary_cost,
7855
+ 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,
7856
+ 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,
7857
+ COALESCE(SUM(cost.amount) FILTER (WHERE cost.recurrence::text = 'monthly' AND cost_type.slug IN ('software-licenca', 'equipamento')), 0) AS tools_cost
7858
+ FROM operations_collaborator_cost cost
7859
+ LEFT JOIN operations_cost_type cost_type
7860
+ ON cost_type.id = cost.cost_type_id
7861
+ WHERE cost.collaborator_id = c.id
7862
+ AND (cost.start_date IS NULL OR cost.start_date <= $2::date)
7863
+ AND (cost.end_date IS NULL OR cost.end_date >= $1::date)
7864
+ ) cost_totals
7865
+ LEFT JOIN LATERAL (
7866
+ SELECT h.amount
7867
+ FROM operations_collaborator_compensation_history h
7868
+ WHERE h.collaborator_id = c.id
7869
+ AND (h.effective_date IS NULL OR h.effective_date <= $2::date)
7870
+ ORDER BY h.effective_date DESC NULLS LAST, h.created_at DESC
7871
+ LIMIT 1
7872
+ ) compensation_history ON TRUE
7873
+ LEFT JOIN LATERAL (
7874
+ SELECT oc.budget_amount
7875
+ FROM operations_contract oc
7876
+ WHERE oc.related_collaborator_id = c.id
7877
+ AND oc.deleted_at IS NULL
7878
+ ORDER BY CASE WHEN oc.origin_type = 'employee_hiring' THEN 0 ELSE 1 END,
7879
+ oc.created_at DESC
7880
+ LIMIT 1
7881
+ ) hiring_contract ON TRUE
7478
7882
  ) cost_stats ON TRUE
7883
+ LEFT JOIN LATERAL (
7884
+ SELECT COALESCE(
7885
+ SUM(
7886
+ COALESCE(
7887
+ pa.weekly_hours,
7888
+ COALESCE(c.weekly_capacity_hours, 40) * COALESCE(pa.allocation_percent, 0) / 100
7889
+ ) * GREATEST(
7890
+ CEIL(
7891
+ (
7892
+ LEAST(COALESCE(pa.end_date, $2::date), $2::date)
7893
+ - GREATEST(COALESCE(pa.start_date, $1::date), $1::date)
7894
+ + 1
7895
+ ) / 7.0
7896
+ ),
7897
+ 0
7898
+ )
7899
+ ),
7900
+ 0
7901
+ ) AS planned_allocated_hours,
7902
+ COALESCE(
7903
+ SUM(
7904
+ COALESCE(
7905
+ pa.weekly_hours,
7906
+ COALESCE(c.weekly_capacity_hours, 40) * COALESCE(pa.allocation_percent, 0) / 100
7907
+ ) * GREATEST(
7908
+ CEIL(
7909
+ (
7910
+ LEAST(COALESCE(pa.end_date, $2::date), $2::date)
7911
+ - GREATEST(COALESCE(pa.start_date, $1::date), $1::date)
7912
+ + 1
7913
+ ) / 7.0
7914
+ ),
7915
+ 0
7916
+ )
7917
+ ) FILTER (WHERE pa.is_billable = true),
7918
+ 0
7919
+ ) AS planned_billable_hours,
7920
+ COUNT(DISTINCT pa.project_id) AS projects
7921
+ FROM operations_project_assignment pa
7922
+ WHERE pa.collaborator_id = c.id
7923
+ AND pa.deleted_at IS NULL
7924
+ AND pa.status IN ('planned', 'active')
7925
+ AND (pa.start_date IS NULL OR pa.start_date <= $2::date)
7926
+ AND (pa.end_date IS NULL OR pa.end_date >= $1::date)
7927
+ ) assignment_stats ON TRUE
7479
7928
  LEFT JOIN LATERAL (
7480
7929
  SELECT COALESCE(SUM(entry.hours), 0) AS allocated_hours,
7481
7930
  COALESCE(SUM(entry.hours) FILTER (WHERE pa.is_billable = true), 0) AS billable_hours,
@@ -7489,48 +7938,62 @@ let OperationsService = OperationsService_1 = class OperationsService {
7489
7938
  AND entry.work_date BETWEEN $1::date AND $2::date
7490
7939
  ) value_stats ON TRUE
7491
7940
  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
7941
+ SELECT COUNT(*) AS open_tasks,
7942
+ COALESCE(SUM(COALESCE(task.estimate_hours, 0)), 0) AS open_task_hours,
7943
+ COALESCE(
7944
+ SUM(COALESCE(task.estimate_hours, 0)) FILTER (WHERE pa.is_billable = true),
7945
+ 0
7946
+ ) AS open_task_billable_hours
7947
+ FROM operations_task task
7948
+ LEFT JOIN operations_project_assignment pa
7949
+ ON pa.id = task.project_assignment_id
7495
7950
  AND pa.deleted_at IS NULL
7496
- AND pa.status IN ('planned', 'active')
7497
- ) project_stats ON TRUE
7951
+ WHERE task.deleted_at IS NULL
7952
+ AND task.status IN ('todo', 'doing', 'review')
7953
+ AND (
7954
+ task.assignee_collaborator_id = c.id
7955
+ OR pa.collaborator_id = c.id
7956
+ )
7957
+ ) task_stats ON TRUE
7498
7958
  WHERE ${where.join(' AND ')}
7499
7959
  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
7960
  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);
7961
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
7962
+ const salaryCost = Number((_a = row.salaryCost) !== null && _a !== void 0 ? _a : 0) * periodMonths;
7963
+ const benefitsCost = Number((_b = row.benefitsCost) !== null && _b !== void 0 ? _b : 0) * periodMonths;
7964
+ const taxesCost = Number((_c = row.taxesCost) !== null && _c !== void 0 ? _c : 0) * periodMonths;
7965
+ const toolsCost = Number((_d = row.toolsCost) !== null && _d !== void 0 ? _d : 0) * periodMonths;
7509
7966
  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);
7967
+ const plannedAllocatedHours = Number((_f = row.plannedAllocatedHours) !== null && _f !== void 0 ? _f : 0);
7968
+ const plannedBillableHours = Number((_g = row.plannedBillableHours) !== null && _g !== void 0 ? _g : 0);
7969
+ const openTaskHours = Number((_h = row.openTaskHours) !== null && _h !== void 0 ? _h : 0);
7970
+ const openTaskBillableHours = Number((_j = row.openTaskBillableHours) !== null && _j !== void 0 ? _j : 0);
7971
+ const actualAllocatedHours = Number((_k = row.allocatedHours) !== null && _k !== void 0 ? _k : 0);
7972
+ const actualBillableHours = Number((_l = row.billableHours) !== null && _l !== void 0 ? _l : 0);
7973
+ const allocatedHours = Math.max(actualAllocatedHours, plannedAllocatedHours, openTaskHours);
7974
+ const billableHours = Math.max(actualBillableHours, plannedBillableHours, openTaskBillableHours);
7512
7975
  const allocation = availableHours ? (allocatedHours / availableHours) * 100 : 0;
7513
7976
  const risk = allocation >= 98 ? 'alto' : allocation < 75 ? 'médio' : 'baixo';
7514
7977
  return {
7515
7978
  id: Number(row.id),
7516
7979
  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 : '-',
7980
+ role: (_m = row.role) !== null && _m !== void 0 ? _m : '-',
7981
+ seniority: (_o = row.seniority) !== null && _o !== void 0 ? _o : '-',
7982
+ department: (_p = row.department) !== null && _p !== void 0 ? _p : '-',
7983
+ contractType: (_q = row.contractType) !== null && _q !== void 0 ? _q : '-',
7521
7984
  startDate: row.startDate,
7522
7985
  endDate: row.endDate,
7523
7986
  salaryCost,
7524
7987
  benefitsCost,
7525
7988
  taxesCost,
7526
7989
  toolsCost,
7527
- billableValue: Number((_m = row.billableValue) !== null && _m !== void 0 ? _m : 0),
7990
+ billableValue: Number((_r = row.billableValue) !== null && _r !== void 0 ? _r : 0),
7528
7991
  availableHours,
7529
7992
  allocatedHours,
7530
7993
  billableHours,
7531
7994
  internalHours: Math.max(allocatedHours - billableHours, 0),
7532
7995
  overtimeHours: Math.max(allocatedHours - availableHours, 0),
7533
- projects: Number((_o = row.projects) !== null && _o !== void 0 ? _o : 0),
7996
+ projects: Number((_s = row.projects) !== null && _s !== void 0 ? _s : 0),
7534
7997
  risk,
7535
7998
  recommendation: risk === 'alto'
7536
7999
  ? 'Reduzir sobrecarga ou redistribuir entregas.'
@@ -7578,7 +8041,11 @@ let OperationsService = OperationsService_1 = class OperationsService {
7578
8041
  summary.freeHours = Math.max(summary.availableHours - summary.allocatedHours, 0);
7579
8042
  summary.allocation = summary.availableHours ? (summary.allocatedHours / summary.availableHours) * 100 : 0;
7580
8043
  summary.utilization = summary.availableHours ? (summary.billableHours / summary.availableHours) * 100 : 0;
7581
- summary.hourlyCost = summary.allocatedHours ? summary.cost / summary.allocatedHours : 0;
8044
+ summary.hourlyCost = summary.allocatedHours
8045
+ ? summary.cost / summary.allocatedHours
8046
+ : summary.availableHours
8047
+ ? summary.cost / summary.availableHours
8048
+ : 0;
7582
8049
  const forecast = Array.from({ length: 12 }, (_, index) => {
7583
8050
  const monthDate = new Date(fromDate);
7584
8051
  monthDate.setMonth(fromDate.getMonth() + index);
@@ -7764,6 +8231,1149 @@ let OperationsService = OperationsService_1 = class OperationsService {
7764
8231
  await this.prisma.$queryRawUnsafe(`DELETE FROM operations_collaborator_cost WHERE id = $1`, costId);
7765
8232
  return { success: true };
7766
8233
  }
8234
+ // ──────────────────────────────────────────────────────────────────────────
8235
+ // Project Cost Categories
8236
+ // ──────────────────────────────────────────────────────────────────────────
8237
+ async listProjectCostCategories(userId, filters = {}) {
8238
+ var _a;
8239
+ await this.getActorContext(userId);
8240
+ const localeId = await this.resolvePreferredLocaleId();
8241
+ const params = [localeId];
8242
+ const where = ['pcc.deleted_at IS NULL'];
8243
+ if (filters.is_active === true) {
8244
+ where.push('pcc.is_active = true');
8245
+ }
8246
+ if ((_a = filters.search) === null || _a === void 0 ? void 0 : _a.trim()) {
8247
+ const p = this.param(params, `%${filters.search.trim()}%`);
8248
+ where.push(`(COALESCE(pccl.name, pcc.slug) ILIKE ${p} OR COALESCE(pcc.slug, '') ILIKE ${p})`);
8249
+ }
8250
+ const whereClause = `WHERE ${where.join(' AND ')}`;
8251
+ return this.queryRows(`SELECT pcc.id,
8252
+ pcc.slug,
8253
+ COALESCE(pccl.name, pcc.slug) AS name,
8254
+ pccl.description,
8255
+ pcc.icon,
8256
+ pcc.color,
8257
+ pcc.is_active AS "isActive",
8258
+ pcc.sort_order AS "sortOrder",
8259
+ pcc.created_at AS "createdAt"
8260
+ FROM operations_project_cost_category pcc
8261
+ LEFT JOIN LATERAL (
8262
+ SELECT l.name, l.description
8263
+ FROM operations_project_cost_category_locale l
8264
+ WHERE l.operations_project_cost_category_id = pcc.id
8265
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8266
+ l.id ASC
8267
+ LIMIT 1
8268
+ ) pccl ON TRUE
8269
+ ${whereClause}
8270
+ ORDER BY pcc.sort_order ASC, COALESCE(pccl.name, pcc.slug) ASC`, params);
8271
+ }
8272
+ async createProjectCostCategory(userId, data) {
8273
+ var _a;
8274
+ const actor = await this.getActorContext(userId);
8275
+ this.ensureDirector(actor);
8276
+ const slug = (_a = data.slug) === null || _a === void 0 ? void 0 : _a.trim();
8277
+ if (!slug) {
8278
+ throw new common_1.BadRequestException('Cost category slug is required.');
8279
+ }
8280
+ return this.prisma.$transaction(async (tx) => {
8281
+ var _a, _b, _c, _d, _e, _f;
8282
+ const localeId = await this.resolvePreferredLocaleId(tx);
8283
+ const created = (await tx.$queryRawUnsafe(`INSERT INTO operations_project_cost_category (slug, icon, color, is_active, sort_order, created_at, updated_at)
8284
+ VALUES ($1, $2, $3, $4, $5, NOW(), NOW())
8285
+ 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));
8286
+ const createdId = (_e = created[0]) === null || _e === void 0 ? void 0 : _e.id;
8287
+ if (!createdId) {
8288
+ throw new common_1.BadRequestException('Unable to create project cost category.');
8289
+ }
8290
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : slug);
8291
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8292
+ if (localeId && name) {
8293
+ await tx.$executeRawUnsafe(`INSERT INTO operations_project_cost_category_locale (operations_project_cost_category_id, locale_id, name, description)
8294
+ VALUES ($1, $2, $3, $4)`, createdId, localeId, name, description !== null && description !== void 0 ? description : null);
8295
+ }
8296
+ const rows = (await tx.$queryRawUnsafe(`SELECT pcc.id,
8297
+ pcc.slug,
8298
+ COALESCE(pccl.name, pcc.slug) AS name,
8299
+ pccl.description,
8300
+ pcc.icon,
8301
+ pcc.color,
8302
+ pcc.is_active AS "isActive",
8303
+ pcc.sort_order AS "sortOrder",
8304
+ pcc.created_at AS "createdAt"
8305
+ FROM operations_project_cost_category pcc
8306
+ LEFT JOIN operations_project_cost_category_locale pccl
8307
+ ON pccl.operations_project_cost_category_id = pcc.id AND pccl.locale_id = $2
8308
+ WHERE pcc.id = $1`, createdId, localeId));
8309
+ return (_f = rows[0]) !== null && _f !== void 0 ? _f : null;
8310
+ });
8311
+ }
8312
+ async updateProjectCostCategory(userId, id, data) {
8313
+ const actor = await this.getActorContext(userId);
8314
+ this.ensureDirector(actor);
8315
+ const category = await this.querySingle(`SELECT id FROM operations_project_cost_category WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8316
+ if (!category) {
8317
+ throw new common_1.NotFoundException('Project cost category not found.');
8318
+ }
8319
+ const sets = [];
8320
+ const params = [];
8321
+ if (data.slug !== undefined)
8322
+ sets.push(`slug = ${this.param(params, data.slug)}`);
8323
+ if (data.icon !== undefined)
8324
+ sets.push(`icon = ${this.param(params, data.icon)}`);
8325
+ if (data.color !== undefined)
8326
+ sets.push(`color = ${this.param(params, data.color)}`);
8327
+ if (data.is_active !== undefined)
8328
+ sets.push(`is_active = ${this.param(params, data.is_active)}`);
8329
+ if (data.sort_order !== undefined)
8330
+ sets.push(`sort_order = ${this.param(params, data.sort_order)}`);
8331
+ if (sets.length > 0) {
8332
+ sets.push(`updated_at = NOW()`);
8333
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_category SET ${sets.join(', ')} WHERE id = ${this.param(params, id)}`, ...params);
8334
+ }
8335
+ if (data.name !== undefined || data.description !== undefined) {
8336
+ const localeId = await this.resolvePreferredLocaleId();
8337
+ if (localeId) {
8338
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : undefined);
8339
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8340
+ 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]);
8341
+ if (existing) {
8342
+ const localeSets = [];
8343
+ const localeParams = [];
8344
+ if (name !== undefined)
8345
+ localeSets.push(`name = ${this.param(localeParams, name)}`);
8346
+ if (description !== undefined)
8347
+ localeSets.push(`description = ${this.param(localeParams, description)}`);
8348
+ if (localeSets.length > 0) {
8349
+ 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);
8350
+ }
8351
+ }
8352
+ else if (name) {
8353
+ 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);
8354
+ }
8355
+ }
8356
+ }
8357
+ return this.querySingle(`SELECT id, slug FROM operations_project_cost_category WHERE id = $1`, [id]);
8358
+ }
8359
+ async deleteProjectCostCategory(userId, id) {
8360
+ const actor = await this.getActorContext(userId);
8361
+ this.ensureDirector(actor);
8362
+ const category = await this.querySingle(`SELECT id FROM operations_project_cost_category WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8363
+ if (!category) {
8364
+ throw new common_1.NotFoundException('Project cost category not found.');
8365
+ }
8366
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_category SET deleted_at = NOW() WHERE id = $1`, id);
8367
+ return { success: true };
8368
+ }
8369
+ async getProjectCostCategory(userId, id) {
8370
+ await this.getActorContext(userId);
8371
+ const localeId = await this.resolvePreferredLocaleId();
8372
+ const row = await this.querySingle(`SELECT pcc.id,
8373
+ pcc.slug,
8374
+ COALESCE(pccl.name, pcc.slug) AS name,
8375
+ pccl.description,
8376
+ pcc.icon,
8377
+ pcc.color,
8378
+ pcc.is_active AS "isActive",
8379
+ pcc.sort_order AS "sortOrder",
8380
+ pcc.created_at AS "createdAt"
8381
+ FROM operations_project_cost_category pcc
8382
+ LEFT JOIN LATERAL (
8383
+ SELECT l.name, l.description
8384
+ FROM operations_project_cost_category_locale l
8385
+ WHERE l.operations_project_cost_category_id = pcc.id
8386
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8387
+ l.id ASC
8388
+ LIMIT 1
8389
+ ) pccl ON TRUE
8390
+ WHERE pcc.id = $2 AND pcc.deleted_at IS NULL`, [localeId, id]);
8391
+ if (!row) {
8392
+ throw new common_1.NotFoundException('Project cost category not found.');
8393
+ }
8394
+ return row;
8395
+ }
8396
+ // ──────────────────────────────────────────────────────────────────────────
8397
+ // Project Cost Types
8398
+ // ──────────────────────────────────────────────────────────────────────────
8399
+ async listProjectCostTypes(userId, filters = {}) {
8400
+ var _a;
8401
+ await this.getActorContext(userId);
8402
+ const localeId = await this.resolvePreferredLocaleId();
8403
+ const params = [localeId];
8404
+ const where = ['pct.deleted_at IS NULL'];
8405
+ if (filters.is_active === true) {
8406
+ where.push('pct.is_active = true');
8407
+ }
8408
+ if (filters.category_id) {
8409
+ where.push(`pct.category_id = ${this.param(params, filters.category_id)}`);
8410
+ }
8411
+ if (filters.default_calculation_type) {
8412
+ where.push(`pct.default_calculation_type = ${this.param(params, filters.default_calculation_type)}`);
8413
+ }
8414
+ if ((_a = filters.search) === null || _a === void 0 ? void 0 : _a.trim()) {
8415
+ const p = this.param(params, `%${filters.search.trim()}%`);
8416
+ where.push(`(COALESCE(pctl.name, pct.slug) ILIKE ${p} OR COALESCE(pct.code, '') ILIKE ${p} OR COALESCE(pct.slug, '') ILIKE ${p})`);
8417
+ }
8418
+ const whereClause = `WHERE ${where.join(' AND ')}`;
8419
+ return this.queryRows(`SELECT pct.id,
8420
+ pct.slug,
8421
+ pct.code,
8422
+ COALESCE(pctl.name, pct.slug) AS name,
8423
+ pctl.description,
8424
+ pct.category_id AS "categoryId",
8425
+ pcc.slug AS "categorySlug",
8426
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
8427
+ pct.default_unit AS "defaultUnit",
8428
+ pct.default_calculation_type AS "defaultCalculationType",
8429
+ pct.is_recurring_allowed AS "isRecurringAllowed",
8430
+ pct.is_active AS "isActive",
8431
+ pct.sort_order AS "sortOrder",
8432
+ pct.created_at AS "createdAt"
8433
+ FROM operations_project_cost_type pct
8434
+ LEFT JOIN operations_project_cost_category pcc
8435
+ ON pcc.id = pct.category_id AND pcc.deleted_at IS NULL
8436
+ LEFT JOIN LATERAL (
8437
+ SELECT l.name, l.description
8438
+ FROM operations_project_cost_category_locale l
8439
+ WHERE l.operations_project_cost_category_id = pcc.id
8440
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8441
+ l.id ASC
8442
+ LIMIT 1
8443
+ ) pccl ON TRUE
8444
+ LEFT JOIN LATERAL (
8445
+ SELECT l.name, l.description
8446
+ FROM operations_project_cost_type_locale l
8447
+ WHERE l.operations_project_cost_type_id = pct.id
8448
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8449
+ l.id ASC
8450
+ LIMIT 1
8451
+ ) pctl ON TRUE
8452
+ ${whereClause}
8453
+ ORDER BY pct.sort_order ASC, COALESCE(pctl.name, pct.slug) ASC`, params);
8454
+ }
8455
+ async createProjectCostType(userId, data) {
8456
+ var _a, _b, _c;
8457
+ const actor = await this.getActorContext(userId);
8458
+ this.ensureDirector(actor);
8459
+ const slug = (_a = data.slug) === null || _a === void 0 ? void 0 : _a.trim();
8460
+ if (!slug) {
8461
+ throw new common_1.BadRequestException('Cost type slug is required.');
8462
+ }
8463
+ if (data.category_id) {
8464
+ 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]);
8465
+ if (!category) {
8466
+ throw new common_1.BadRequestException(`Category with id ${data.category_id} not found.`);
8467
+ }
8468
+ }
8469
+ const existingSlug = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE slug = $1 AND deleted_at IS NULL LIMIT 1`, [slug]);
8470
+ if (existingSlug) {
8471
+ throw new common_1.ConflictException(`A cost type with slug '${slug}' already exists.`);
8472
+ }
8473
+ const code = (_c = (_b = data.code) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : slug;
8474
+ const existingCode = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE code = $1 AND deleted_at IS NULL LIMIT 1`, [code]);
8475
+ if (existingCode) {
8476
+ throw new common_1.ConflictException(`A cost type with code '${code}' already exists.`);
8477
+ }
8478
+ return this.prisma.$transaction(async (tx) => {
8479
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
8480
+ const localeId = await this.resolvePreferredLocaleId(tx);
8481
+ 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)
8482
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW())
8483
+ 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));
8484
+ const createdId = (_j = created[0]) === null || _j === void 0 ? void 0 : _j.id;
8485
+ if (!createdId) {
8486
+ throw new common_1.BadRequestException('Unable to create project cost type.');
8487
+ }
8488
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : slug);
8489
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8490
+ if (localeId && name) {
8491
+ await tx.$executeRawUnsafe(`INSERT INTO operations_project_cost_type_locale (operations_project_cost_type_id, locale_id, name, description)
8492
+ VALUES ($1, $2, $3, $4)`, createdId, localeId, name, description !== null && description !== void 0 ? description : null);
8493
+ }
8494
+ const rows = (await tx.$queryRawUnsafe(`SELECT pct.id,
8495
+ pct.slug,
8496
+ pct.code,
8497
+ COALESCE(pctl.name, pct.slug) AS name,
8498
+ pctl.description,
8499
+ pct.category_id AS "categoryId",
8500
+ pct.default_unit AS "defaultUnit",
8501
+ pct.default_calculation_type AS "defaultCalculationType",
8502
+ pct.is_recurring_allowed AS "isRecurringAllowed",
8503
+ pct.is_active AS "isActive",
8504
+ pct.sort_order AS "sortOrder",
8505
+ pct.created_at AS "createdAt"
8506
+ FROM operations_project_cost_type pct
8507
+ LEFT JOIN operations_project_cost_type_locale pctl
8508
+ ON pctl.operations_project_cost_type_id = pct.id AND pctl.locale_id = $2
8509
+ WHERE pct.id = $1`, createdId, localeId));
8510
+ return (_k = rows[0]) !== null && _k !== void 0 ? _k : null;
8511
+ });
8512
+ }
8513
+ async updateProjectCostType(userId, id, data) {
8514
+ const actor = await this.getActorContext(userId);
8515
+ this.ensureDirector(actor);
8516
+ const costType = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8517
+ if (!costType) {
8518
+ throw new common_1.NotFoundException('Project cost type not found.');
8519
+ }
8520
+ if (data.category_id !== undefined && data.category_id !== null) {
8521
+ 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]);
8522
+ if (!category) {
8523
+ throw new common_1.BadRequestException(`Category with id ${data.category_id} not found.`);
8524
+ }
8525
+ }
8526
+ if (data.slug !== undefined) {
8527
+ 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]);
8528
+ if (existingSlug) {
8529
+ throw new common_1.ConflictException(`A cost type with slug '${data.slug}' already exists.`);
8530
+ }
8531
+ }
8532
+ if (data.code !== undefined) {
8533
+ 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]);
8534
+ if (existingCode) {
8535
+ throw new common_1.ConflictException(`A cost type with code '${data.code}' already exists.`);
8536
+ }
8537
+ }
8538
+ const sets = [];
8539
+ const params = [];
8540
+ if (data.category_id !== undefined)
8541
+ sets.push(`category_id = ${this.param(params, data.category_id)}`);
8542
+ if (data.slug !== undefined)
8543
+ sets.push(`slug = ${this.param(params, data.slug)}`);
8544
+ if (data.code !== undefined)
8545
+ sets.push(`code = ${this.param(params, data.code)}`);
8546
+ if (data.default_unit !== undefined)
8547
+ sets.push(`default_unit = ${this.param(params, data.default_unit)}`);
8548
+ if (data.default_calculation_type !== undefined)
8549
+ sets.push(`default_calculation_type = ${this.param(params, data.default_calculation_type)}`);
8550
+ if (data.is_recurring_allowed !== undefined)
8551
+ sets.push(`is_recurring_allowed = ${this.param(params, data.is_recurring_allowed)}`);
8552
+ if (data.is_active !== undefined)
8553
+ sets.push(`is_active = ${this.param(params, data.is_active)}`);
8554
+ if (data.sort_order !== undefined)
8555
+ sets.push(`sort_order = ${this.param(params, data.sort_order)}`);
8556
+ if (sets.length > 0) {
8557
+ sets.push(`updated_at = NOW()`);
8558
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_type SET ${sets.join(', ')} WHERE id = ${this.param(params, id)}`, ...params);
8559
+ }
8560
+ if (data.name !== undefined || data.description !== undefined) {
8561
+ const localeId = await this.resolvePreferredLocaleId();
8562
+ if (localeId) {
8563
+ const name = typeof data.name === 'string' ? data.name : (data.name ? JSON.stringify(data.name) : undefined);
8564
+ const description = typeof data.description === 'string' ? data.description : (data.description ? JSON.stringify(data.description) : null);
8565
+ 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]);
8566
+ if (existing) {
8567
+ const localeSets = [];
8568
+ const localeParams = [];
8569
+ if (name !== undefined)
8570
+ localeSets.push(`name = ${this.param(localeParams, name)}`);
8571
+ if (description !== undefined)
8572
+ localeSets.push(`description = ${this.param(localeParams, description)}`);
8573
+ if (localeSets.length > 0) {
8574
+ 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);
8575
+ }
8576
+ }
8577
+ else if (name) {
8578
+ 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);
8579
+ }
8580
+ }
8581
+ }
8582
+ return this.querySingle(`SELECT id, slug FROM operations_project_cost_type WHERE id = $1`, [id]);
8583
+ }
8584
+ async deleteProjectCostType(userId, id) {
8585
+ const actor = await this.getActorContext(userId);
8586
+ this.ensureDirector(actor);
8587
+ const costType = await this.querySingle(`SELECT id FROM operations_project_cost_type WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
8588
+ if (!costType) {
8589
+ throw new common_1.NotFoundException('Project cost type not found.');
8590
+ }
8591
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost_type SET deleted_at = NOW() WHERE id = $1`, id);
8592
+ return { success: true };
8593
+ }
8594
+ async getProjectCostType(userId, id) {
8595
+ await this.getActorContext(userId);
8596
+ const localeId = await this.resolvePreferredLocaleId();
8597
+ const row = await this.querySingle(`SELECT pct.id,
8598
+ pct.slug,
8599
+ pct.code,
8600
+ COALESCE(pctl.name, pct.slug) AS name,
8601
+ pctl.description,
8602
+ pct.default_unit,
8603
+ pct.default_calculation_type,
8604
+ pct.is_recurring_allowed,
8605
+ pct.is_active,
8606
+ pct.sort_order,
8607
+ pct.category_id,
8608
+ CASE WHEN pcc.id IS NOT NULL THEN
8609
+ jsonb_build_object(
8610
+ 'id', pcc.id,
8611
+ 'slug', pcc.slug,
8612
+ 'name', COALESCE(pccl.name, pcc.slug),
8613
+ 'color', pcc.color,
8614
+ 'icon', pcc.icon
8615
+ )
8616
+ ELSE NULL END AS category
8617
+ FROM operations_project_cost_type pct
8618
+ LEFT JOIN operations_project_cost_category pcc
8619
+ ON pcc.id = pct.category_id AND pcc.deleted_at IS NULL
8620
+ LEFT JOIN LATERAL (
8621
+ SELECT l.name, l.description
8622
+ FROM operations_project_cost_category_locale l
8623
+ WHERE l.operations_project_cost_category_id = pcc.id
8624
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8625
+ l.id ASC
8626
+ LIMIT 1
8627
+ ) pccl ON TRUE
8628
+ LEFT JOIN LATERAL (
8629
+ SELECT l.name, l.description
8630
+ FROM operations_project_cost_type_locale l
8631
+ WHERE l.operations_project_cost_type_id = pct.id
8632
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8633
+ l.id ASC
8634
+ LIMIT 1
8635
+ ) pctl ON TRUE
8636
+ WHERE pct.id = $2 AND pct.deleted_at IS NULL`, [localeId, id]);
8637
+ if (!row) {
8638
+ throw new common_1.NotFoundException('Project cost type not found.');
8639
+ }
8640
+ return row;
8641
+ }
8642
+ // ──────────────────────────────────────────────────────────────────────────
8643
+ // Project Costs
8644
+ // ──────────────────────────────────────────────────────────────────────────
8645
+ async listProjectCosts(userId, projectId, filters = {}) {
8646
+ var _a;
8647
+ await this.getActorContext(userId);
8648
+ const localeId = await this.resolvePreferredLocaleId();
8649
+ const params = [localeId, projectId];
8650
+ const where = ['pc.deleted_at IS NULL', 'pc.project_id = $2'];
8651
+ if (filters.cost_type_id) {
8652
+ where.push(`pc.cost_type_id = ${this.param(params, filters.cost_type_id)}`);
8653
+ }
8654
+ if (filters.category_id) {
8655
+ where.push(`COALESCE(pc.category_id, pct.category_id) = ${this.param(params, filters.category_id)}`);
8656
+ }
8657
+ if (filters.recurrence_type) {
8658
+ where.push(`pc.recurrence_type = ${this.param(params, filters.recurrence_type)}`);
8659
+ }
8660
+ if (filters.calculation_type) {
8661
+ where.push(`pc.calculation_type = ${this.param(params, filters.calculation_type)}`);
8662
+ }
8663
+ if (filters.status) {
8664
+ where.push(`pc.status = ${this.param(params, filters.status)}`);
8665
+ }
8666
+ if (filters.is_billable !== undefined) {
8667
+ where.push(`pc.is_billable = ${this.param(params, filters.is_billable)}`);
8668
+ }
8669
+ if (filters.is_reimbursable !== undefined) {
8670
+ where.push(`pc.is_reimbursable = ${this.param(params, filters.is_reimbursable)}`);
8671
+ }
8672
+ if (filters.date_from) {
8673
+ where.push(`pc.cost_date >= ${this.param(params, filters.date_from)}::date`);
8674
+ }
8675
+ if (filters.date_to) {
8676
+ where.push(`pc.cost_date <= ${this.param(params, filters.date_to)}::date`);
8677
+ }
8678
+ if ((_a = filters.search) === null || _a === void 0 ? void 0 : _a.trim()) {
8679
+ const p = this.param(params, `%${filters.search.trim()}%`);
8680
+ where.push(`(COALESCE(pc.description, '') ILIKE ${p} OR COALESCE(pc.notes, '') ILIKE ${p})`);
8681
+ }
8682
+ const whereClause = `WHERE ${where.join(' AND ')}`;
8683
+ const rows = await this.queryRows(`SELECT pc.id,
8684
+ pc.project_id AS "projectId",
8685
+ pc.cost_type_id AS "costTypeId",
8686
+ pct.slug AS "costTypeSlug",
8687
+ pct.code AS "costTypeCode",
8688
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
8689
+ pc.category_id AS "categoryId",
8690
+ COALESCE(pc.category_id, pct.category_id) AS "resolvedCategoryId",
8691
+ pcc.slug AS "categorySlug",
8692
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
8693
+ pcc.color AS "categoryColor",
8694
+ pcc.icon AS "categoryIcon",
8695
+ pc.description,
8696
+ pc.amount::text AS amount,
8697
+ pc.quantity::text AS quantity,
8698
+ pc.unit_amount::text AS "unitAmount",
8699
+ pc.currency,
8700
+ TO_CHAR(pc.cost_date, 'YYYY-MM-DD') AS "costDate",
8701
+ TO_CHAR(pc.period_start, 'YYYY-MM-DD') AS "periodStart",
8702
+ TO_CHAR(pc.period_end, 'YYYY-MM-DD') AS "periodEnd",
8703
+ pc.calculation_type AS "calculationType",
8704
+ pc.recurrence_type AS "recurrenceType",
8705
+ pc.is_billable AS "isBillable",
8706
+ pc.is_reimbursable AS "isReimbursable",
8707
+ pc.notes,
8708
+ pc.status,
8709
+ pc.created_at AS "createdAt"
8710
+ FROM operations_project_cost pc
8711
+ LEFT JOIN operations_project_cost_type pct
8712
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
8713
+ LEFT JOIN operations_project_cost_category pcc
8714
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
8715
+ LEFT JOIN LATERAL (
8716
+ SELECT l.name
8717
+ FROM operations_project_cost_type_locale l
8718
+ WHERE l.operations_project_cost_type_id = pct.id
8719
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8720
+ l.id ASC
8721
+ LIMIT 1
8722
+ ) pctl ON TRUE
8723
+ LEFT JOIN LATERAL (
8724
+ SELECT l.name
8725
+ FROM operations_project_cost_category_locale l
8726
+ WHERE l.operations_project_cost_category_id = pcc.id
8727
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8728
+ l.id ASC
8729
+ LIMIT 1
8730
+ ) pccl ON TRUE
8731
+ ${whereClause}
8732
+ ORDER BY pc.created_at DESC`, params);
8733
+ return rows.map((row) => ({
8734
+ id: row.id,
8735
+ project_id: row.projectId,
8736
+ cost_type_id: row.costTypeId,
8737
+ category_id: row.categoryId,
8738
+ description: row.description,
8739
+ amount: row.amount,
8740
+ quantity: row.quantity,
8741
+ unit_amount: row.unitAmount,
8742
+ currency: row.currency,
8743
+ cost_date: row.costDate,
8744
+ period_start: row.periodStart,
8745
+ period_end: row.periodEnd,
8746
+ calculation_type: row.calculationType,
8747
+ recurrence_type: row.recurrenceType,
8748
+ is_billable: row.isBillable,
8749
+ is_reimbursable: row.isReimbursable,
8750
+ notes: row.notes,
8751
+ status: row.status,
8752
+ created_at: row.createdAt,
8753
+ cost_type: row.costTypeId
8754
+ ? { id: row.costTypeId, slug: row.costTypeSlug, name: row.costTypeName, code: row.costTypeCode }
8755
+ : null,
8756
+ category: row.resolvedCategoryId
8757
+ ? { id: row.resolvedCategoryId, slug: row.categorySlug, name: row.categoryName, color: row.categoryColor, icon: row.categoryIcon }
8758
+ : null,
8759
+ }));
8760
+ }
8761
+ async getProjectCostsSummaryGrouped(userId, projectId) {
8762
+ var _a, _b;
8763
+ const items = await this.listProjectCosts(userId, projectId, {});
8764
+ // Group by resolved category
8765
+ const categoryMap = new Map();
8766
+ for (const cost of items) {
8767
+ const cat = (_a = cost.category) !== null && _a !== void 0 ? _a : null;
8768
+ const key = (_b = cat === null || cat === void 0 ? void 0 : cat.id) !== null && _b !== void 0 ? _b : null;
8769
+ if (!categoryMap.has(key)) {
8770
+ categoryMap.set(key, { category: cat, items: [], total_amount: 0 });
8771
+ }
8772
+ const group = categoryMap.get(key);
8773
+ group.items.push(cost);
8774
+ group.total_amount += (parseFloat(String(cost.amount)) || 0) * (parseFloat(String(cost.quantity)) || 1);
8775
+ }
8776
+ const grand_total = Array.from(categoryMap.values()).reduce((sum, g) => sum + g.total_amount, 0);
8777
+ return {
8778
+ categories: Array.from(categoryMap.values()).map((g) => ({
8779
+ category: g.category,
8780
+ items: g.items,
8781
+ total_amount: Math.round(g.total_amount * 100) / 100,
8782
+ count: g.items.length,
8783
+ })),
8784
+ grand_total: Math.round(grand_total * 100) / 100,
8785
+ };
8786
+ }
8787
+ async getProjectCost(userId, projectId, id) {
8788
+ const rows = await this.listProjectCosts(userId, projectId, {});
8789
+ const cost = rows.find((r) => r.id === id);
8790
+ if (!cost) {
8791
+ throw new common_1.NotFoundException('Project cost not found.');
8792
+ }
8793
+ return cost;
8794
+ }
8795
+ async getProjectCostsSummary(userId, projectId) {
8796
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
8797
+ await this.getActorContext(userId);
8798
+ const localeId = await this.resolvePreferredLocaleId();
8799
+ // ── 1. Verify project exists and fetch budget_amount ──────────────────
8800
+ const project = await this.querySingle(`SELECT id, budget_amount::text AS "budgetAmount"
8801
+ FROM operations_project
8802
+ WHERE id = $1 AND deleted_at IS NULL
8803
+ LIMIT 1`, [projectId]);
8804
+ if (!project) {
8805
+ throw new common_1.NotFoundException('Project not found.');
8806
+ }
8807
+ const budgetAmount = parseFloat((_a = project.budgetAmount) !== null && _a !== void 0 ? _a : '0') || 0;
8808
+ // ── 2. Aggregated cost totals ─────────────────────────────────────────
8809
+ const totals = await this.querySingle(`SELECT
8810
+ COALESCE(SUM(CASE WHEN status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "extraCostTotal",
8811
+ COALESCE(SUM(CASE WHEN status = 'planned' THEN amount * quantity ELSE 0 END), 0)::text AS "plannedTotal",
8812
+ COALESCE(SUM(CASE WHEN status = 'approved' THEN amount * quantity ELSE 0 END), 0)::text AS "approvedTotal",
8813
+ COALESCE(SUM(CASE WHEN status = 'realized' THEN amount * quantity ELSE 0 END), 0)::text AS "realizedTotal",
8814
+ COALESCE(SUM(CASE WHEN status = 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "cancelledTotal",
8815
+ COALESCE(SUM(CASE WHEN is_billable = true AND status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "billableTotal",
8816
+ COALESCE(SUM(CASE WHEN is_billable = false AND status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "nonBillableTotal",
8817
+ COALESCE(SUM(CASE WHEN is_reimbursable = true AND status != 'cancelled' THEN amount * quantity ELSE 0 END), 0)::text AS "reimbursableTotal"
8818
+ FROM operations_project_cost
8819
+ WHERE deleted_at IS NULL
8820
+ AND project_id = $1`, [projectId]);
8821
+ const extraCostTotal = Math.round((parseFloat((_b = totals === null || totals === void 0 ? void 0 : totals.extraCostTotal) !== null && _b !== void 0 ? _b : '0') || 0) * 100) / 100;
8822
+ const plannedTotal = Math.round((parseFloat((_c = totals === null || totals === void 0 ? void 0 : totals.plannedTotal) !== null && _c !== void 0 ? _c : '0') || 0) * 100) / 100;
8823
+ const approvedTotal = Math.round((parseFloat((_d = totals === null || totals === void 0 ? void 0 : totals.approvedTotal) !== null && _d !== void 0 ? _d : '0') || 0) * 100) / 100;
8824
+ const realizedTotal = Math.round((parseFloat((_e = totals === null || totals === void 0 ? void 0 : totals.realizedTotal) !== null && _e !== void 0 ? _e : '0') || 0) * 100) / 100;
8825
+ const cancelledTotal = Math.round((parseFloat((_f = totals === null || totals === void 0 ? void 0 : totals.cancelledTotal) !== null && _f !== void 0 ? _f : '0') || 0) * 100) / 100;
8826
+ const billableTotal = Math.round((parseFloat((_g = totals === null || totals === void 0 ? void 0 : totals.billableTotal) !== null && _g !== void 0 ? _g : '0') || 0) * 100) / 100;
8827
+ const nonBillableTotal = Math.round((parseFloat((_h = totals === null || totals === void 0 ? void 0 : totals.nonBillableTotal) !== null && _h !== void 0 ? _h : '0') || 0) * 100) / 100;
8828
+ const reimbursableTotal = Math.round((parseFloat((_j = totals === null || totals === void 0 ? void 0 : totals.reimbursableTotal) !== null && _j !== void 0 ? _j : '0') || 0) * 100) / 100;
8829
+ const teamCostTotal = 0;
8830
+ const totalProjectCost = Math.round((teamCostTotal + extraCostTotal) * 100) / 100;
8831
+ const remainingBudget = Math.round((budgetAmount - totalProjectCost) * 100) / 100;
8832
+ const budgetUsagePercent = budgetAmount > 0
8833
+ ? Math.round((totalProjectCost / budgetAmount) * 10000) / 100
8834
+ : 0;
8835
+ // ── 3. cost_by_category ───────────────────────────────────────────────
8836
+ const costByCategory = await this.queryRows(`SELECT
8837
+ COALESCE(pc.category_id, pct.category_id) AS "categoryId",
8838
+ pcc.slug AS "categorySlug",
8839
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
8840
+ pcc.color AS "categoryColor",
8841
+ pcc.icon AS "categoryIcon",
8842
+ SUM(pc.amount * pc.quantity)::text AS total,
8843
+ COUNT(*)::int AS count
8844
+ FROM operations_project_cost pc
8845
+ LEFT JOIN operations_project_cost_type pct
8846
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
8847
+ LEFT JOIN operations_project_cost_category pcc
8848
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
8849
+ LEFT JOIN LATERAL (
8850
+ SELECT l.name
8851
+ FROM operations_project_cost_category_locale l
8852
+ WHERE l.operations_project_cost_category_id = pcc.id
8853
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8854
+ l.id ASC
8855
+ LIMIT 1
8856
+ ) pccl ON TRUE
8857
+ WHERE pc.deleted_at IS NULL
8858
+ AND pc.project_id = $2
8859
+ AND pc.status != 'cancelled'
8860
+ GROUP BY COALESCE(pc.category_id, pct.category_id), pcc.slug, pcc.color, pcc.icon, pccl.name
8861
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, projectId]);
8862
+ // ── 4. cost_by_type ───────────────────────────────────────────────────
8863
+ const costByType = await this.queryRows(`SELECT
8864
+ pc.cost_type_id AS "costTypeId",
8865
+ pct.slug AS "costTypeSlug",
8866
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
8867
+ pct.code AS "costTypeCode",
8868
+ SUM(pc.amount * pc.quantity)::text AS total,
8869
+ COUNT(*)::int AS count
8870
+ FROM operations_project_cost pc
8871
+ LEFT JOIN operations_project_cost_type pct
8872
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
8873
+ LEFT JOIN LATERAL (
8874
+ SELECT l.name
8875
+ FROM operations_project_cost_type_locale l
8876
+ WHERE l.operations_project_cost_type_id = pct.id
8877
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC,
8878
+ l.id ASC
8879
+ LIMIT 1
8880
+ ) pctl ON TRUE
8881
+ WHERE pc.deleted_at IS NULL
8882
+ AND pc.project_id = $2
8883
+ AND pc.status != 'cancelled'
8884
+ GROUP BY pc.cost_type_id, pct.slug, pct.code, pctl.name
8885
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, projectId]);
8886
+ // ── 5. cost_by_month ──────────────────────────────────────────────────
8887
+ const costByMonth = await this.queryRows(`SELECT
8888
+ TO_CHAR(COALESCE(pc.cost_date, pc.created_at), 'YYYY-MM') AS month,
8889
+ SUM(pc.amount * pc.quantity)::text AS total,
8890
+ COUNT(*)::int AS count
8891
+ FROM operations_project_cost pc
8892
+ WHERE pc.deleted_at IS NULL
8893
+ AND pc.project_id = $1
8894
+ AND pc.status != 'cancelled'
8895
+ GROUP BY TO_CHAR(COALESCE(pc.cost_date, pc.created_at), 'YYYY-MM')
8896
+ ORDER BY month ASC`, [projectId]);
8897
+ // ── 6. top_cost_types (top 5) ─────────────────────────────────────────
8898
+ const topCostTypes = costByType.slice(0, 5).map((ct) => {
8899
+ const typeTotal = Math.round((parseFloat(ct.total) || 0) * 100) / 100;
8900
+ const percentage = extraCostTotal > 0
8901
+ ? Math.round((typeTotal / extraCostTotal) * 10000) / 100
8902
+ : 0;
8903
+ return {
8904
+ cost_type_id: ct.costTypeId,
8905
+ cost_type_slug: ct.costTypeSlug,
8906
+ cost_type_name: ct.costTypeName,
8907
+ cost_type_code: ct.costTypeCode,
8908
+ total: typeTotal,
8909
+ percentage,
8910
+ };
8911
+ });
8912
+ return {
8913
+ project_id: projectId,
8914
+ budget_amount: budgetAmount,
8915
+ team_cost_total: teamCostTotal,
8916
+ extra_cost_total: extraCostTotal,
8917
+ total_project_cost: totalProjectCost,
8918
+ remaining_budget: remainingBudget,
8919
+ budget_usage_percent: budgetUsagePercent,
8920
+ planned_total: plannedTotal,
8921
+ approved_total: approvedTotal,
8922
+ realized_total: realizedTotal,
8923
+ cancelled_total: cancelledTotal,
8924
+ billable_total: billableTotal,
8925
+ non_billable_total: nonBillableTotal,
8926
+ reimbursable_total: reimbursableTotal,
8927
+ cost_by_category: costByCategory.map((c) => ({
8928
+ category_id: c.categoryId,
8929
+ category_slug: c.categorySlug,
8930
+ category_name: c.categoryName,
8931
+ category_color: c.categoryColor,
8932
+ category_icon: c.categoryIcon,
8933
+ total: Math.round((parseFloat(c.total) || 0) * 100) / 100,
8934
+ count: Number(c.count),
8935
+ })),
8936
+ cost_by_type: costByType.map((t) => ({
8937
+ cost_type_id: t.costTypeId,
8938
+ cost_type_slug: t.costTypeSlug,
8939
+ cost_type_name: t.costTypeName,
8940
+ cost_type_code: t.costTypeCode,
8941
+ total: Math.round((parseFloat(t.total) || 0) * 100) / 100,
8942
+ count: Number(t.count),
8943
+ })),
8944
+ cost_by_month: costByMonth.map((m) => ({
8945
+ month: m.month,
8946
+ total: Math.round((parseFloat(m.total) || 0) * 100) / 100,
8947
+ count: Number(m.count),
8948
+ })),
8949
+ top_cost_types: topCostTypes,
8950
+ };
8951
+ }
8952
+ async getProjectCostReport(userId, projectId, filters) {
8953
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
8954
+ await this.getActorContext(userId);
8955
+ const localeId = await this.resolvePreferredLocaleId();
8956
+ // ── Verify project ───────────────────────────────────────────────────
8957
+ const project = await this.querySingle(`SELECT id, budget_amount::text AS "budgetAmount"
8958
+ FROM operations_project
8959
+ WHERE id = $1 AND deleted_at IS NULL
8960
+ LIMIT 1`, [projectId]);
8961
+ if (!project) {
8962
+ throw new common_1.NotFoundException('Project not found.');
8963
+ }
8964
+ const budgetAmount = parseFloat((_a = project.budgetAmount) !== null && _a !== void 0 ? _a : '0') || 0;
8965
+ // ── Build dynamic WHERE clause ────────────────────────────────────────
8966
+ const conditions = [
8967
+ 'pc.deleted_at IS NULL',
8968
+ 'pc.project_id = $1',
8969
+ ];
8970
+ const params = [projectId];
8971
+ if (filters.date_from) {
8972
+ params.push(filters.date_from);
8973
+ conditions.push(`COALESCE(pc.cost_date, pc.created_at::date) >= $${params.length}::date`);
8974
+ }
8975
+ if (filters.date_to) {
8976
+ params.push(filters.date_to);
8977
+ conditions.push(`COALESCE(pc.cost_date, pc.created_at::date) <= $${params.length}::date`);
8978
+ }
8979
+ if (filters.category_id !== undefined) {
8980
+ params.push(filters.category_id);
8981
+ conditions.push(`(pc.category_id = $${params.length} OR (pc.category_id IS NULL AND EXISTS (
8982
+ SELECT 1 FROM operations_project_cost_type pct2
8983
+ WHERE pct2.id = pc.cost_type_id AND pct2.category_id = $${params.length} AND pct2.deleted_at IS NULL
8984
+ )))`);
8985
+ }
8986
+ if (filters.cost_type_id !== undefined) {
8987
+ params.push(filters.cost_type_id);
8988
+ conditions.push(`pc.cost_type_id = $${params.length}`);
8989
+ }
8990
+ if (filters.status !== undefined) {
8991
+ params.push(filters.status);
8992
+ conditions.push(`pc.status = $${params.length}`);
8993
+ }
8994
+ if (filters.is_billable !== undefined) {
8995
+ params.push(filters.is_billable);
8996
+ conditions.push(`pc.is_billable = $${params.length}`);
8997
+ }
8998
+ if (filters.is_reimbursable !== undefined) {
8999
+ params.push(filters.is_reimbursable);
9000
+ conditions.push(`pc.is_reimbursable = $${params.length}`);
9001
+ }
9002
+ const whereClause = conditions.join(' AND ');
9003
+ // ── Totals ────────────────────────────────────────────────────────────
9004
+ const totals = await this.querySingle(`SELECT
9005
+ COALESCE(SUM(pc.amount * pc.quantity), 0)::text AS "grandTotal",
9006
+ COALESCE(SUM(CASE WHEN pc.status = 'planned' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "plannedTotal",
9007
+ COALESCE(SUM(CASE WHEN pc.status = 'approved' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "approvedTotal",
9008
+ COALESCE(SUM(CASE WHEN pc.status = 'realized' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "realizedTotal",
9009
+ COALESCE(SUM(CASE WHEN pc.status = 'cancelled' THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "cancelledTotal",
9010
+ COALESCE(SUM(CASE WHEN pc.is_billable = true THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "billableTotal",
9011
+ COALESCE(SUM(CASE WHEN pc.is_billable = false THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "nonBillableTotal",
9012
+ COALESCE(SUM(CASE WHEN pc.is_reimbursable = true THEN pc.amount * pc.quantity ELSE 0 END), 0)::text AS "reimbursableTotal",
9013
+ COUNT(*)::int AS "totalCount"
9014
+ FROM operations_project_cost pc
9015
+ WHERE ${whereClause}`, params);
9016
+ const round2 = (v) => Math.round((parseFloat(v !== null && v !== void 0 ? v : '0') || 0) * 100) / 100;
9017
+ const grandTotal = round2(totals === null || totals === void 0 ? void 0 : totals.grandTotal);
9018
+ const plannedTotal = round2(totals === null || totals === void 0 ? void 0 : totals.plannedTotal);
9019
+ const approvedTotal = round2(totals === null || totals === void 0 ? void 0 : totals.approvedTotal);
9020
+ const realizedTotal = round2(totals === null || totals === void 0 ? void 0 : totals.realizedTotal);
9021
+ const cancelledTotal = round2(totals === null || totals === void 0 ? void 0 : totals.cancelledTotal);
9022
+ const billableTotal = round2(totals === null || totals === void 0 ? void 0 : totals.billableTotal);
9023
+ const nonBillableTotal = round2(totals === null || totals === void 0 ? void 0 : totals.nonBillableTotal);
9024
+ const reimbursableTotal = round2(totals === null || totals === void 0 ? void 0 : totals.reimbursableTotal);
9025
+ // ── By category ───────────────────────────────────────────────────────
9026
+ const costByCategory = await this.queryRows(`SELECT
9027
+ COALESCE(pc.category_id, pct.category_id) AS "categoryId",
9028
+ pcc.slug AS "categorySlug",
9029
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
9030
+ pcc.color AS "categoryColor",
9031
+ pcc.icon AS "categoryIcon",
9032
+ SUM(pc.amount * pc.quantity)::text AS total,
9033
+ COUNT(*)::int AS count,
9034
+ COALESCE(SUM(CASE WHEN pc.status='planned' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "plannedSubtotal",
9035
+ COALESCE(SUM(CASE WHEN pc.status='realized' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "realizedSubtotal"
9036
+ FROM operations_project_cost pc
9037
+ LEFT JOIN operations_project_cost_type pct
9038
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9039
+ LEFT JOIN operations_project_cost_category pcc
9040
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
9041
+ LEFT JOIN LATERAL (
9042
+ SELECT l.name
9043
+ FROM operations_project_cost_category_locale l
9044
+ WHERE l.operations_project_cost_category_id = pcc.id
9045
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9046
+ LIMIT 1
9047
+ ) pccl ON TRUE
9048
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9049
+ GROUP BY COALESCE(pc.category_id, pct.category_id), pcc.slug, pcc.color, pcc.icon, pccl.name
9050
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, ...params]);
9051
+ // ── By type ───────────────────────────────────────────────────────────
9052
+ const costByType = await this.queryRows(`SELECT
9053
+ pc.cost_type_id AS "costTypeId",
9054
+ pct.slug AS "costTypeSlug",
9055
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
9056
+ pct.code AS "costTypeCode",
9057
+ SUM(pc.amount * pc.quantity)::text AS total,
9058
+ COUNT(*)::int AS count,
9059
+ COALESCE(SUM(CASE WHEN pc.status='planned' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "plannedSubtotal",
9060
+ COALESCE(SUM(CASE WHEN pc.status='realized' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "realizedSubtotal"
9061
+ FROM operations_project_cost pc
9062
+ LEFT JOIN operations_project_cost_type pct
9063
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9064
+ LEFT JOIN LATERAL (
9065
+ SELECT l.name
9066
+ FROM operations_project_cost_type_locale l
9067
+ WHERE l.operations_project_cost_type_id = pct.id
9068
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9069
+ LIMIT 1
9070
+ ) pctl ON TRUE
9071
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9072
+ GROUP BY pc.cost_type_id, pct.slug, pct.code, pctl.name
9073
+ ORDER BY SUM(pc.amount * pc.quantity) DESC`, [localeId, ...params]);
9074
+ // ── By month ──────────────────────────────────────────────────────────
9075
+ const costByMonth = await this.queryRows(`SELECT
9076
+ TO_CHAR(COALESCE(pc.cost_date, pc.created_at::date), 'YYYY-MM') AS month,
9077
+ SUM(pc.amount * pc.quantity)::text AS total,
9078
+ COALESCE(SUM(CASE WHEN pc.status='planned' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "plannedSubtotal",
9079
+ COALESCE(SUM(CASE WHEN pc.status='realized' THEN pc.amount*pc.quantity ELSE 0 END),0)::text AS "realizedSubtotal",
9080
+ COUNT(*)::int AS count
9081
+ FROM operations_project_cost pc
9082
+ WHERE ${whereClause}
9083
+ GROUP BY TO_CHAR(COALESCE(pc.cost_date, pc.created_at::date), 'YYYY-MM')
9084
+ ORDER BY month ASC`, params);
9085
+ // ── Top 5 individual costs ────────────────────────────────────────────
9086
+ const top5Costs = await this.queryRows(`SELECT
9087
+ pc.id,
9088
+ pc.description,
9089
+ pc.amount::text,
9090
+ pc.quantity::text,
9091
+ pc.status,
9092
+ pc.cost_date AS "costDate",
9093
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
9094
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
9095
+ pcc.color AS "categoryColor"
9096
+ FROM operations_project_cost pc
9097
+ LEFT JOIN operations_project_cost_type pct
9098
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9099
+ LEFT JOIN LATERAL (
9100
+ SELECT l.name
9101
+ FROM operations_project_cost_type_locale l
9102
+ WHERE l.operations_project_cost_type_id = pct.id
9103
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9104
+ LIMIT 1
9105
+ ) pctl ON TRUE
9106
+ LEFT JOIN operations_project_cost_category pcc
9107
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
9108
+ LEFT JOIN LATERAL (
9109
+ SELECT l.name
9110
+ FROM operations_project_cost_category_locale l
9111
+ WHERE l.operations_project_cost_category_id = pcc.id
9112
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9113
+ LIMIT 1
9114
+ ) pccl ON TRUE
9115
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9116
+ ORDER BY (pc.amount * pc.quantity) DESC
9117
+ LIMIT 5`, [localeId, ...params]);
9118
+ // ── Detailed list ─────────────────────────────────────────────────────
9119
+ const detailedList = await this.queryRows(`SELECT
9120
+ pc.id,
9121
+ pc.description,
9122
+ pc.amount::text,
9123
+ pc.quantity::text,
9124
+ pc.unit_amount::text AS "unitAmount",
9125
+ pc.currency,
9126
+ pc.calculation_type AS "calculationType",
9127
+ pc.recurrence_type AS "recurrenceType",
9128
+ pc.status,
9129
+ pc.is_billable AS "isBillable",
9130
+ pc.is_reimbursable AS "isReimbursable",
9131
+ pc.cost_date AS "costDate",
9132
+ pc.period_start AS "periodStart",
9133
+ pc.period_end AS "periodEnd",
9134
+ pc.notes,
9135
+ pc.cost_type_id AS "costTypeId",
9136
+ COALESCE(pctl.name, pct.slug) AS "costTypeName",
9137
+ pct.code AS "costTypeCode",
9138
+ COALESCE(pc.category_id, pct.category_id) AS "categoryId",
9139
+ COALESCE(pccl.name, pcc.slug) AS "categoryName",
9140
+ pcc.color AS "categoryColor",
9141
+ pc.created_at::text AS "createdAt"
9142
+ FROM operations_project_cost pc
9143
+ LEFT JOIN operations_project_cost_type pct
9144
+ ON pct.id = pc.cost_type_id AND pct.deleted_at IS NULL
9145
+ LEFT JOIN LATERAL (
9146
+ SELECT l.name
9147
+ FROM operations_project_cost_type_locale l
9148
+ WHERE l.operations_project_cost_type_id = pct.id
9149
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9150
+ LIMIT 1
9151
+ ) pctl ON TRUE
9152
+ LEFT JOIN operations_project_cost_category pcc
9153
+ ON pcc.id = COALESCE(pc.category_id, pct.category_id) AND pcc.deleted_at IS NULL
9154
+ LEFT JOIN LATERAL (
9155
+ SELECT l.name
9156
+ FROM operations_project_cost_category_locale l
9157
+ WHERE l.operations_project_cost_category_id = pcc.id
9158
+ ORDER BY CASE WHEN $1::int IS NOT NULL AND l.locale_id = $1 THEN 0 ELSE 1 END ASC, l.id ASC
9159
+ LIMIT 1
9160
+ ) pccl ON TRUE
9161
+ WHERE ${whereClause.replace(/\$(\d+)/g, (m, n) => '$' + (Number(n) + 1))}
9162
+ ORDER BY (pc.amount * pc.quantity) DESC, pc.cost_date DESC NULLS LAST`, [localeId, ...params]);
9163
+ return {
9164
+ project_id: projectId,
9165
+ budget_amount: budgetAmount,
9166
+ filters_applied: {
9167
+ date_from: (_b = filters.date_from) !== null && _b !== void 0 ? _b : null,
9168
+ date_to: (_c = filters.date_to) !== null && _c !== void 0 ? _c : null,
9169
+ category_id: (_d = filters.category_id) !== null && _d !== void 0 ? _d : null,
9170
+ cost_type_id: (_e = filters.cost_type_id) !== null && _e !== void 0 ? _e : null,
9171
+ status: (_f = filters.status) !== null && _f !== void 0 ? _f : null,
9172
+ is_billable: (_g = filters.is_billable) !== null && _g !== void 0 ? _g : null,
9173
+ is_reimbursable: (_h = filters.is_reimbursable) !== null && _h !== void 0 ? _h : null,
9174
+ },
9175
+ totals: {
9176
+ grand_total: grandTotal,
9177
+ planned_total: plannedTotal,
9178
+ approved_total: approvedTotal,
9179
+ realized_total: realizedTotal,
9180
+ cancelled_total: cancelledTotal,
9181
+ billable_total: billableTotal,
9182
+ non_billable_total: nonBillableTotal,
9183
+ reimbursable_total: reimbursableTotal,
9184
+ total_count: Number((_j = totals === null || totals === void 0 ? void 0 : totals.totalCount) !== null && _j !== void 0 ? _j : 0),
9185
+ },
9186
+ cost_by_category: costByCategory.map((c) => ({
9187
+ category_id: c.categoryId,
9188
+ category_slug: c.categorySlug,
9189
+ category_name: c.categoryName,
9190
+ category_color: c.categoryColor,
9191
+ category_icon: c.categoryIcon,
9192
+ total: round2(c.total),
9193
+ count: Number(c.count),
9194
+ planned_subtotal: round2(c.plannedSubtotal),
9195
+ realized_subtotal: round2(c.realizedSubtotal),
9196
+ })),
9197
+ cost_by_type: costByType.map((t) => ({
9198
+ cost_type_id: t.costTypeId,
9199
+ cost_type_slug: t.costTypeSlug,
9200
+ cost_type_name: t.costTypeName,
9201
+ cost_type_code: t.costTypeCode,
9202
+ total: round2(t.total),
9203
+ count: Number(t.count),
9204
+ planned_subtotal: round2(t.plannedSubtotal),
9205
+ realized_subtotal: round2(t.realizedSubtotal),
9206
+ })),
9207
+ cost_by_month: costByMonth.map((m) => ({
9208
+ month: m.month,
9209
+ total: round2(m.total),
9210
+ planned_subtotal: round2(m.plannedSubtotal),
9211
+ realized_subtotal: round2(m.realizedSubtotal),
9212
+ count: Number(m.count),
9213
+ })),
9214
+ top_5_costs: top5Costs.map((c) => ({
9215
+ id: c.id,
9216
+ description: c.description,
9217
+ total: round2(String(parseFloat(c.amount) * parseFloat(c.quantity))),
9218
+ amount: round2(c.amount),
9219
+ quantity: parseFloat(c.quantity),
9220
+ status: c.status,
9221
+ cost_type_name: c.costTypeName,
9222
+ category_name: c.categoryName,
9223
+ category_color: c.categoryColor,
9224
+ cost_date: c.costDate,
9225
+ })),
9226
+ detailed_list: detailedList.map((c) => ({
9227
+ id: c.id,
9228
+ description: c.description,
9229
+ amount: round2(c.amount),
9230
+ quantity: parseFloat(c.quantity),
9231
+ unit_amount: c.unitAmount ? round2(c.unitAmount) : null,
9232
+ total: round2(String(parseFloat(c.amount) * parseFloat(c.quantity))),
9233
+ currency: c.currency,
9234
+ calculation_type: c.calculationType,
9235
+ recurrence_type: c.recurrenceType,
9236
+ status: c.status,
9237
+ is_billable: c.isBillable,
9238
+ is_reimbursable: c.isReimbursable,
9239
+ cost_date: c.costDate,
9240
+ period_start: c.periodStart,
9241
+ period_end: c.periodEnd,
9242
+ notes: c.notes,
9243
+ cost_type_id: c.costTypeId,
9244
+ cost_type_name: c.costTypeName,
9245
+ cost_type_code: c.costTypeCode,
9246
+ category_id: c.categoryId,
9247
+ category_name: c.categoryName,
9248
+ category_color: c.categoryColor,
9249
+ created_at: c.createdAt,
9250
+ })),
9251
+ };
9252
+ }
9253
+ async createProjectCost(userId, projectId, data) {
9254
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
9255
+ const actor = await this.getActorContext(userId);
9256
+ this.ensureSupervisor(actor);
9257
+ const project = await this.querySingle(`SELECT id FROM operations_project WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [projectId]);
9258
+ if (!project) {
9259
+ throw new common_1.NotFoundException('Project not found.');
9260
+ }
9261
+ if (data.cost_type_id) {
9262
+ 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]);
9263
+ if (!costType) {
9264
+ throw new common_1.BadRequestException(`Cost type with id ${data.cost_type_id} not found.`);
9265
+ }
9266
+ }
9267
+ if (data.category_id) {
9268
+ 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]);
9269
+ if (!category) {
9270
+ throw new common_1.BadRequestException(`Cost category with id ${data.category_id} not found.`);
9271
+ }
9272
+ }
9273
+ const calcType = (_a = data.calculation_type) !== null && _a !== void 0 ? _a : 'fixed';
9274
+ let effectiveAmount = data.amount;
9275
+ if (['unit', 'hourly', 'monthly'].includes(calcType) && data.unit_amount !== undefined && data.unit_amount !== null) {
9276
+ const qty = (_b = data.quantity) !== null && _b !== void 0 ? _b : 1;
9277
+ effectiveAmount = Math.round(qty * data.unit_amount * 100) / 100;
9278
+ }
9279
+ const created = await this.querySingle(`INSERT INTO operations_project_cost
9280
+ (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)
9281
+ 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())
9282
+ RETURNING id`, [
9283
+ projectId,
9284
+ (_c = data.cost_type_id) !== null && _c !== void 0 ? _c : null,
9285
+ (_d = data.category_id) !== null && _d !== void 0 ? _d : null,
9286
+ (_e = data.description) !== null && _e !== void 0 ? _e : null,
9287
+ effectiveAmount,
9288
+ (_f = data.quantity) !== null && _f !== void 0 ? _f : 1,
9289
+ (_g = data.unit_amount) !== null && _g !== void 0 ? _g : null,
9290
+ (_h = data.currency) !== null && _h !== void 0 ? _h : 'BRL',
9291
+ (_j = data.cost_date) !== null && _j !== void 0 ? _j : null,
9292
+ (_k = data.period_start) !== null && _k !== void 0 ? _k : null,
9293
+ (_l = data.period_end) !== null && _l !== void 0 ? _l : null,
9294
+ calcType,
9295
+ (_m = data.recurrence_type) !== null && _m !== void 0 ? _m : 'none',
9296
+ (_o = data.is_billable) !== null && _o !== void 0 ? _o : false,
9297
+ (_p = data.is_reimbursable) !== null && _p !== void 0 ? _p : false,
9298
+ (_q = data.notes) !== null && _q !== void 0 ? _q : null,
9299
+ (_r = data.status) !== null && _r !== void 0 ? _r : 'planned',
9300
+ ]);
9301
+ if (!(created === null || created === void 0 ? void 0 : created.id)) {
9302
+ throw new common_1.BadRequestException('Unable to create project cost.');
9303
+ }
9304
+ const rows = await this.listProjectCosts(userId, projectId, {});
9305
+ return (_s = rows.find((r) => r.id === created.id)) !== null && _s !== void 0 ? _s : null;
9306
+ }
9307
+ async updateProjectCost(userId, id, data) {
9308
+ var _a, _b, _c;
9309
+ const actor = await this.getActorContext(userId);
9310
+ this.ensureSupervisor(actor);
9311
+ 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]);
9312
+ if (!cost) {
9313
+ throw new common_1.NotFoundException('Project cost not found.');
9314
+ }
9315
+ // Auto-calculate amount when applicable
9316
+ const effectiveCalcType = (_a = data.calculation_type) !== null && _a !== void 0 ? _a : cost.calculationType;
9317
+ if (['unit', 'hourly', 'monthly'].includes(effectiveCalcType)) {
9318
+ const ua = data.unit_amount !== undefined ? data.unit_amount : (cost.unitAmount !== null ? parseFloat(cost.unitAmount) : null);
9319
+ const qty = data.quantity !== undefined ? data.quantity : parseFloat(cost.quantity);
9320
+ if (ua !== null && ua !== undefined) {
9321
+ data = Object.assign(Object.assign({}, data), { amount: Math.round(qty * ua * 100) / 100 });
9322
+ }
9323
+ }
9324
+ const sets = [];
9325
+ const params = [];
9326
+ if (data.cost_type_id !== undefined)
9327
+ sets.push(`cost_type_id = ${this.param(params, data.cost_type_id)}`);
9328
+ if (data.category_id !== undefined)
9329
+ sets.push(`category_id = ${this.param(params, data.category_id)}`);
9330
+ if (data.description !== undefined)
9331
+ sets.push(`description = ${this.param(params, data.description)}`);
9332
+ if (data.amount !== undefined)
9333
+ sets.push(`amount = ${this.param(params, data.amount)}`);
9334
+ if (data.currency !== undefined)
9335
+ sets.push(`currency = ${this.param(params, data.currency)}`);
9336
+ if (data.quantity !== undefined)
9337
+ sets.push(`quantity = ${this.param(params, data.quantity)}`);
9338
+ if (data.unit_amount !== undefined)
9339
+ sets.push(`unit_amount = ${this.param(params, data.unit_amount)}`);
9340
+ if (data.calculation_type !== undefined)
9341
+ sets.push(`calculation_type = ${this.param(params, data.calculation_type)}::operations_project_cost_calculation_type_134cdfb49c_enum`);
9342
+ if (data.recurrence_type !== undefined)
9343
+ sets.push(`recurrence_type = ${this.param(params, data.recurrence_type)}::operations_project_cost_recurrence_type_09baf0f043_enum`);
9344
+ if (data.is_billable !== undefined)
9345
+ sets.push(`is_billable = ${this.param(params, data.is_billable)}`);
9346
+ if (data.is_reimbursable !== undefined)
9347
+ sets.push(`is_reimbursable = ${this.param(params, data.is_reimbursable)}`);
9348
+ if (data.cost_date !== undefined)
9349
+ sets.push(`cost_date = ${this.param(params, data.cost_date)}::date`);
9350
+ if (data.period_start !== undefined)
9351
+ sets.push(`period_start = ${this.param(params, data.period_start)}::date`);
9352
+ if (data.period_end !== undefined)
9353
+ sets.push(`period_end = ${this.param(params, data.period_end)}::date`);
9354
+ if (data.notes !== undefined)
9355
+ sets.push(`notes = ${this.param(params, data.notes)}`);
9356
+ if (data.status !== undefined)
9357
+ sets.push(`status = ${this.param(params, data.status)}::operations_project_cost_status_153e8592ce_enum`);
9358
+ if (sets.length === 0) {
9359
+ const rows = await this.listProjectCosts(userId, cost.projectId, {});
9360
+ return (_b = rows.find((r) => r.id === id)) !== null && _b !== void 0 ? _b : null;
9361
+ }
9362
+ sets.push(`updated_at = NOW()`);
9363
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost SET ${sets.join(', ')} WHERE id = ${this.param(params, id)}`, ...params);
9364
+ const rows = await this.listProjectCosts(userId, cost.projectId, {});
9365
+ return (_c = rows.find((r) => r.id === id)) !== null && _c !== void 0 ? _c : null;
9366
+ }
9367
+ async deleteProjectCost(userId, id) {
9368
+ const actor = await this.getActorContext(userId);
9369
+ this.ensureSupervisor(actor);
9370
+ const cost = await this.querySingle(`SELECT id FROM operations_project_cost WHERE id = $1 AND deleted_at IS NULL LIMIT 1`, [id]);
9371
+ if (!cost) {
9372
+ throw new common_1.NotFoundException('Project cost not found.');
9373
+ }
9374
+ await this.prisma.$queryRawUnsafe(`UPDATE operations_project_cost SET deleted_at = NOW() WHERE id = $1`, id);
9375
+ return { success: true };
9376
+ }
7767
9377
  };
7768
9378
  exports.OperationsService = OperationsService;
7769
9379
  exports.OperationsService = OperationsService = OperationsService_1 = __decorate([