@open-mercato/core 0.6.4-develop.4210.1.d412061cfe → 0.6.4-develop.4236.1.9fa6806b34

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 (370) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/staff_time_entry/index.js +37 -0
  3. package/dist/generated/entities/staff_time_entry/index.js.map +7 -0
  4. package/dist/generated/entities/staff_time_entry_segment/index.js +23 -0
  5. package/dist/generated/entities/staff_time_entry_segment/index.js.map +7 -0
  6. package/dist/generated/entities/staff_time_project/index.js +35 -0
  7. package/dist/generated/entities/staff_time_project/index.js.map +7 -0
  8. package/dist/generated/entities/staff_time_project_member/index.js +29 -0
  9. package/dist/generated/entities/staff_time_project_member/index.js.map +7 -0
  10. package/dist/generated/entities.ids.generated.js +5 -1
  11. package/dist/generated/entities.ids.generated.js.map +2 -2
  12. package/dist/generated/entity-fields-registry.js +64 -0
  13. package/dist/generated/entity-fields-registry.js.map +2 -2
  14. package/dist/helpers/integration/timesheetFixtures.js +50 -0
  15. package/dist/helpers/integration/timesheetFixtures.js.map +7 -0
  16. package/dist/modules/attachments/api/library/[id]/route.js +20 -16
  17. package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
  18. package/dist/modules/attachments/api/route.js +18 -14
  19. package/dist/modules/attachments/api/route.js.map +2 -2
  20. package/dist/modules/auth/api/roles/acl/route.js +10 -4
  21. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  22. package/dist/modules/auth/api/sidebar/preferences/route.js +27 -20
  23. package/dist/modules/auth/api/sidebar/preferences/route.js.map +2 -2
  24. package/dist/modules/auth/api/users/acl/route.js +16 -11
  25. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  26. package/dist/modules/auth/commands/users.js +87 -71
  27. package/dist/modules/auth/commands/users.js.map +2 -2
  28. package/dist/modules/auth/services/sidebarPreferencesService.js +39 -30
  29. package/dist/modules/auth/services/sidebarPreferencesService.js.map +2 -2
  30. package/dist/modules/catalog/commands/categories.js +61 -12
  31. package/dist/modules/catalog/commands/categories.js.map +2 -2
  32. package/dist/modules/catalog/commands/products.js +79 -54
  33. package/dist/modules/catalog/commands/products.js.map +2 -2
  34. package/dist/modules/catalog/commands/variants.js +29 -16
  35. package/dist/modules/catalog/commands/variants.js.map +2 -2
  36. package/dist/modules/currencies/commands/currencies.js +15 -8
  37. package/dist/modules/currencies/commands/currencies.js.map +2 -2
  38. package/dist/modules/customer_accounts/api/admin/users.js +27 -26
  39. package/dist/modules/customer_accounts/api/admin/users.js.map +2 -2
  40. package/dist/modules/customer_accounts/api/password/reset-confirm.js +5 -5
  41. package/dist/modules/customer_accounts/api/password/reset-confirm.js.map +2 -2
  42. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +11 -10
  43. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
  44. package/dist/modules/customers/commands/addresses.js +35 -21
  45. package/dist/modules/customers/commands/addresses.js.map +2 -2
  46. package/dist/modules/customers/commands/companies.js +163 -162
  47. package/dist/modules/customers/commands/companies.js.map +2 -2
  48. package/dist/modules/customers/commands/deals.js +3 -4
  49. package/dist/modules/customers/commands/deals.js.map +2 -2
  50. package/dist/modules/customers/commands/interactions.js +19 -22
  51. package/dist/modules/customers/commands/interactions.js.map +2 -2
  52. package/dist/modules/customers/commands/people.js +18 -15
  53. package/dist/modules/customers/commands/people.js.map +2 -2
  54. package/dist/modules/customers/commands/personCompanyLinks.js +105 -94
  55. package/dist/modules/customers/commands/personCompanyLinks.js.map +2 -2
  56. package/dist/modules/customers/commands/pipeline-stages.js +30 -23
  57. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  58. package/dist/modules/customers/commands/pipelines.js +27 -20
  59. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  60. package/dist/modules/customers/commands/tags.js +13 -5
  61. package/dist/modules/customers/commands/tags.js.map +2 -2
  62. package/dist/modules/dashboards/api/users/widgets/route.js +0 -1
  63. package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
  64. package/dist/modules/dashboards/api/widgets/data/route.js +29 -1
  65. package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
  66. package/dist/modules/data_sync/lib/sync-engine.js +4 -4
  67. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  68. package/dist/modules/data_sync/lib/sync-run-service.js +51 -27
  69. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  70. package/dist/modules/directory/commands/organizations.js +192 -158
  71. package/dist/modules/directory/commands/organizations.js.map +3 -3
  72. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js +22 -16
  73. package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js.map +2 -2
  74. package/dist/modules/messages/commands/messages.js +77 -75
  75. package/dist/modules/messages/commands/messages.js.map +2 -2
  76. package/dist/modules/messages/commands/shared.js +132 -132
  77. package/dist/modules/messages/commands/shared.js.map +2 -2
  78. package/dist/modules/perspectives/api/[tableId]/route.js +37 -26
  79. package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
  80. package/dist/modules/resources/commands/resources.js +125 -117
  81. package/dist/modules/resources/commands/resources.js.map +2 -2
  82. package/dist/modules/resources/commands/tags.js +7 -3
  83. package/dist/modules/resources/commands/tags.js.map +2 -2
  84. package/dist/modules/sales/api/quotes/send/route.js +12 -11
  85. package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
  86. package/dist/modules/sales/commands/documents.js +629 -478
  87. package/dist/modules/sales/commands/documents.js.map +2 -2
  88. package/dist/modules/sales/commands/payments.js +146 -146
  89. package/dist/modules/sales/commands/payments.js.map +2 -2
  90. package/dist/modules/sales/commands/returns.js +68 -60
  91. package/dist/modules/sales/commands/returns.js.map +2 -2
  92. package/dist/modules/staff/acl.js +10 -1
  93. package/dist/modules/staff/acl.js.map +2 -2
  94. package/dist/modules/staff/analytics.js +33 -0
  95. package/dist/modules/staff/analytics.js.map +7 -0
  96. package/dist/modules/staff/api/guards.js +31 -0
  97. package/dist/modules/staff/api/guards.js.map +7 -0
  98. package/dist/modules/staff/api/interceptors.js +96 -0
  99. package/dist/modules/staff/api/interceptors.js.map +7 -0
  100. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +170 -0
  101. package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +7 -0
  102. package/dist/modules/staff/api/timesheets/my-projects/route.js +103 -0
  103. package/dist/modules/staff/api/timesheets/my-projects/route.js.map +7 -0
  104. package/dist/modules/staff/api/timesheets/projects/kpis/route.js +147 -0
  105. package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +7 -0
  106. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js +171 -0
  107. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.js.map +7 -0
  108. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +180 -0
  109. package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +7 -0
  110. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +155 -0
  111. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +7 -0
  112. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +173 -0
  113. package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +7 -0
  114. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +260 -0
  115. package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +7 -0
  116. package/dist/modules/staff/api/timesheets/time-entries/route.js +188 -0
  117. package/dist/modules/staff/api/timesheets/time-entries/route.js.map +7 -0
  118. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +159 -0
  119. package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +7 -0
  120. package/dist/modules/staff/api/timesheets/time-projects/route.js +230 -0
  121. package/dist/modules/staff/api/timesheets/time-projects/route.js.map +7 -0
  122. package/dist/modules/staff/backend/staff/timesheets/page.js +710 -0
  123. package/dist/modules/staff/backend/staff/timesheets/page.js.map +7 -0
  124. package/dist/modules/staff/backend/staff/timesheets/page.meta.js +22 -0
  125. package/dist/modules/staff/backend/staff/timesheets/page.meta.js.map +7 -0
  126. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js +125 -0
  127. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.js.map +7 -0
  128. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js +16 -0
  129. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.js.map +7 -0
  130. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +418 -0
  131. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +7 -0
  132. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js +16 -0
  133. package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.js.map +7 -0
  134. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js +79 -0
  135. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.js.map +7 -0
  136. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js +16 -0
  137. package/dist/modules/staff/backend/staff/timesheets/projects/create/page.meta.js.map +7 -0
  138. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +602 -0
  139. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +7 -0
  140. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js +25 -0
  141. package/dist/modules/staff/backend/staff/timesheets/projects/page.meta.js.map +7 -0
  142. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js +123 -0
  143. package/dist/modules/staff/backend/staff/timesheets/projects/projectFormConfig.js.map +7 -0
  144. package/dist/modules/staff/cli.js +38 -1
  145. package/dist/modules/staff/cli.js.map +2 -2
  146. package/dist/modules/staff/commands/index.js +2 -0
  147. package/dist/modules/staff/commands/index.js.map +2 -2
  148. package/dist/modules/staff/commands/leave-requests.js +30 -28
  149. package/dist/modules/staff/commands/leave-requests.js.map +3 -3
  150. package/dist/modules/staff/commands/team-members.js +21 -20
  151. package/dist/modules/staff/commands/team-members.js.map +2 -2
  152. package/dist/modules/staff/commands/timesheets-entries.js +409 -0
  153. package/dist/modules/staff/commands/timesheets-entries.js.map +7 -0
  154. package/dist/modules/staff/commands/timesheets-projects.js +618 -0
  155. package/dist/modules/staff/commands/timesheets-projects.js.map +7 -0
  156. package/dist/modules/staff/data/enrichers.js +104 -0
  157. package/dist/modules/staff/data/enrichers.js.map +7 -0
  158. package/dist/modules/staff/data/entities.js +226 -1
  159. package/dist/modules/staff/data/entities.js.map +2 -2
  160. package/dist/modules/staff/data/validators.js +113 -1
  161. package/dist/modules/staff/data/validators.js.map +2 -2
  162. package/dist/modules/staff/events.js +13 -1
  163. package/dist/modules/staff/events.js.map +2 -2
  164. package/dist/modules/staff/lib/crud.js +7 -1
  165. package/dist/modules/staff/lib/crud.js.map +2 -2
  166. package/dist/modules/staff/lib/staffMemberResolver.js +15 -0
  167. package/dist/modules/staff/lib/staffMemberResolver.js.map +7 -0
  168. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js +60 -0
  169. package/dist/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.js.map +7 -0
  170. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js +260 -0
  171. package/dist/modules/staff/lib/timesheets-projects/computeProjectsKpis.js.map +7 -0
  172. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js +41 -0
  173. package/dist/modules/staff/lib/timesheets-projects/dateBuckets.js.map +7 -0
  174. package/dist/modules/staff/lib/timesheets-projects/initials.js +10 -0
  175. package/dist/modules/staff/lib/timesheets-projects/initials.js.map +7 -0
  176. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js +12 -0
  177. package/dist/modules/staff/lib/timesheets-projects/kpiMath.js.map +7 -0
  178. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js +55 -0
  179. package/dist/modules/staff/lib/timesheets-projects/listProjectMembersPreview.js.map +7 -0
  180. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js +66 -0
  181. package/dist/modules/staff/lib/timesheets-projects-ui/HoursSparkline.js.map +7 -0
  182. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js +81 -0
  183. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectCard.js.map +7 -0
  184. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js +58 -0
  185. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.js.map +7 -0
  186. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js +152 -0
  187. package/dist/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.js.map +7 -0
  188. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +37 -0
  189. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +7 -0
  190. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js +57 -0
  191. package/dist/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.js.map +7 -0
  192. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js +50 -0
  193. package/dist/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.js.map +7 -0
  194. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js +163 -0
  195. package/dist/modules/staff/lib/timesheets-ui/AddRowDropdown.js.map +7 -0
  196. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js +209 -0
  197. package/dist/modules/staff/lib/timesheets-ui/CalendarPicker.js.map +7 -0
  198. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js +52 -0
  199. package/dist/modules/staff/lib/timesheets-ui/ColorPicker.js.map +7 -0
  200. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js +77 -0
  201. package/dist/modules/staff/lib/timesheets-ui/CreateProjectDialog.js.map +7 -0
  202. package/dist/modules/staff/lib/timesheets-ui/ListView.js +173 -0
  203. package/dist/modules/staff/lib/timesheets-ui/ListView.js.map +7 -0
  204. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js +32 -0
  205. package/dist/modules/staff/lib/timesheets-ui/ProjectColorDot.js.map +7 -0
  206. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js +270 -0
  207. package/dist/modules/staff/lib/timesheets-ui/TimerBar.js.map +7 -0
  208. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js +57 -0
  209. package/dist/modules/staff/lib/timesheets-ui/ViewSwitcher.js.map +7 -0
  210. package/dist/modules/staff/lib/timesheets-ui/colors.js +43 -0
  211. package/dist/modules/staff/lib/timesheets-ui/colors.js.map +7 -0
  212. package/dist/modules/staff/migrations/Migration20260326135612.js +24 -0
  213. package/dist/modules/staff/migrations/Migration20260326135612.js.map +7 -0
  214. package/dist/modules/staff/migrations/Migration20260413102715.js +23 -0
  215. package/dist/modules/staff/migrations/Migration20260413102715.js.map +7 -0
  216. package/dist/modules/staff/migrations/Migration20260413111602.js +13 -0
  217. package/dist/modules/staff/migrations/Migration20260413111602.js.map +7 -0
  218. package/dist/modules/staff/migrations/Migration20260511112759.js +19 -0
  219. package/dist/modules/staff/migrations/Migration20260511112759.js.map +7 -0
  220. package/dist/modules/staff/search.js +35 -0
  221. package/dist/modules/staff/search.js.map +2 -2
  222. package/dist/modules/staff/setup.js +15 -1
  223. package/dist/modules/staff/setup.js.map +2 -2
  224. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js +16 -0
  225. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.js.map +7 -0
  226. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js +126 -0
  227. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map +7 -0
  228. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js +26 -0
  229. package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.js.map +7 -0
  230. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js +15 -0
  231. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/config.js.map +7 -0
  232. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js +238 -0
  233. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js.map +7 -0
  234. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js +26 -0
  235. package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.js.map +7 -0
  236. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js +145 -0
  237. package/dist/modules/staff/widgets/injection/timer-sidebar-indicator/widget.js.map +7 -0
  238. package/dist/modules/staff/widgets/injection-table.js +12 -0
  239. package/dist/modules/staff/widgets/injection-table.js.map +7 -0
  240. package/dist/modules/sync_excel/api/import/route.js +19 -17
  241. package/dist/modules/sync_excel/api/import/route.js.map +2 -2
  242. package/dist/modules/translations/commands/translations.js +22 -19
  243. package/dist/modules/translations/commands/translations.js.map +2 -2
  244. package/generated/entities/staff_time_entry/index.ts +17 -0
  245. package/generated/entities/staff_time_entry_segment/index.ts +10 -0
  246. package/generated/entities/staff_time_project/index.ts +16 -0
  247. package/generated/entities/staff_time_project_member/index.ts +13 -0
  248. package/generated/entities.ids.generated.ts +5 -1
  249. package/generated/entity-fields-registry.ts +64 -0
  250. package/package.json +7 -7
  251. package/src/helpers/integration/timesheetFixtures.ts +61 -0
  252. package/src/modules/attachments/api/library/[id]/route.ts +24 -17
  253. package/src/modules/attachments/api/route.ts +20 -14
  254. package/src/modules/auth/api/roles/acl/route.ts +11 -5
  255. package/src/modules/auth/api/sidebar/preferences/route.ts +33 -24
  256. package/src/modules/auth/api/users/acl/route.ts +17 -12
  257. package/src/modules/auth/commands/users.ts +96 -80
  258. package/src/modules/auth/services/sidebarPreferencesService.ts +40 -32
  259. package/src/modules/catalog/commands/categories.ts +61 -12
  260. package/src/modules/catalog/commands/products.ts +93 -60
  261. package/src/modules/catalog/commands/variants.ts +29 -16
  262. package/src/modules/currencies/commands/currencies.ts +27 -14
  263. package/src/modules/customer_accounts/api/admin/users.ts +31 -26
  264. package/src/modules/customer_accounts/api/password/reset-confirm.ts +5 -6
  265. package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +14 -13
  266. package/src/modules/customers/commands/addresses.ts +35 -23
  267. package/src/modules/customers/commands/companies.ts +166 -165
  268. package/src/modules/customers/commands/deals.ts +2 -4
  269. package/src/modules/customers/commands/interactions.ts +20 -26
  270. package/src/modules/customers/commands/people.ts +18 -15
  271. package/src/modules/customers/commands/personCompanyLinks.ts +109 -100
  272. package/src/modules/customers/commands/pipeline-stages.ts +31 -27
  273. package/src/modules/customers/commands/pipelines.ts +29 -23
  274. package/src/modules/customers/commands/tags.ts +13 -5
  275. package/src/modules/dashboards/api/users/widgets/route.ts +0 -1
  276. package/src/modules/dashboards/api/widgets/data/route.ts +36 -1
  277. package/src/modules/data_sync/lib/sync-engine.ts +4 -5
  278. package/src/modules/data_sync/lib/sync-run-service.ts +57 -28
  279. package/src/modules/directory/commands/organizations.ts +203 -166
  280. package/src/modules/inbox_ops/api/emails/[id]/reprocess/route.ts +26 -18
  281. package/src/modules/messages/commands/messages.ts +82 -80
  282. package/src/modules/messages/commands/shared.ts +138 -133
  283. package/src/modules/perspectives/api/[tableId]/route.ts +38 -27
  284. package/src/modules/resources/commands/resources.ts +127 -117
  285. package/src/modules/resources/commands/tags.ts +7 -3
  286. package/src/modules/sales/api/quotes/send/route.ts +17 -12
  287. package/src/modules/sales/commands/documents.ts +673 -481
  288. package/src/modules/sales/commands/payments.ts +158 -152
  289. package/src/modules/sales/commands/returns.ts +74 -63
  290. package/src/modules/staff/acl.ts +11 -0
  291. package/src/modules/staff/analytics.ts +30 -0
  292. package/src/modules/staff/api/guards.ts +59 -0
  293. package/src/modules/staff/api/interceptors.ts +122 -0
  294. package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +191 -0
  295. package/src/modules/staff/api/timesheets/my-projects/route.ts +115 -0
  296. package/src/modules/staff/api/timesheets/projects/kpis/route.ts +159 -0
  297. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/[segmentId]/route.ts +187 -0
  298. package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +191 -0
  299. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +168 -0
  300. package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +191 -0
  301. package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +292 -0
  302. package/src/modules/staff/api/timesheets/time-entries/route.ts +193 -0
  303. package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +167 -0
  304. package/src/modules/staff/api/timesheets/time-projects/route.ts +244 -0
  305. package/src/modules/staff/backend/staff/timesheets/page.meta.ts +20 -0
  306. package/src/modules/staff/backend/staff/timesheets/page.tsx +899 -0
  307. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.meta.ts +12 -0
  308. package/src/modules/staff/backend/staff/timesheets/projects/[id]/edit/page.tsx +141 -0
  309. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.meta.ts +12 -0
  310. package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +579 -0
  311. package/src/modules/staff/backend/staff/timesheets/projects/create/page.meta.ts +12 -0
  312. package/src/modules/staff/backend/staff/timesheets/projects/create/page.tsx +90 -0
  313. package/src/modules/staff/backend/staff/timesheets/projects/page.meta.ts +23 -0
  314. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +765 -0
  315. package/src/modules/staff/backend/staff/timesheets/projects/projectFormConfig.ts +138 -0
  316. package/src/modules/staff/cli.ts +40 -1
  317. package/src/modules/staff/commands/index.ts +2 -0
  318. package/src/modules/staff/commands/leave-requests.ts +37 -29
  319. package/src/modules/staff/commands/team-members.ts +25 -20
  320. package/src/modules/staff/commands/timesheets-entries.ts +504 -0
  321. package/src/modules/staff/commands/timesheets-projects.ts +699 -0
  322. package/src/modules/staff/data/enrichers.ts +134 -0
  323. package/src/modules/staff/data/entities.ts +198 -0
  324. package/src/modules/staff/data/validators.ts +129 -0
  325. package/src/modules/staff/events.ts +13 -0
  326. package/src/modules/staff/i18n/de.json +209 -1
  327. package/src/modules/staff/i18n/en.json +209 -1
  328. package/src/modules/staff/i18n/es.json +209 -1
  329. package/src/modules/staff/i18n/pl.json +209 -1
  330. package/src/modules/staff/lib/crud.ts +8 -0
  331. package/src/modules/staff/lib/staffMemberResolver.ts +22 -0
  332. package/src/modules/staff/lib/timesheets-projects/computeProjectHoursTrend.ts +89 -0
  333. package/src/modules/staff/lib/timesheets-projects/computeProjectsKpis.ts +311 -0
  334. package/src/modules/staff/lib/timesheets-projects/dateBuckets.ts +37 -0
  335. package/src/modules/staff/lib/timesheets-projects/initials.ts +6 -0
  336. package/src/modules/staff/lib/timesheets-projects/kpiMath.ts +8 -0
  337. package/src/modules/staff/lib/timesheets-projects/listProjectMembersPreview.ts +83 -0
  338. package/src/modules/staff/lib/timesheets-projects-ui/HoursSparkline.tsx +75 -0
  339. package/src/modules/staff/lib/timesheets-projects-ui/ProjectCard.tsx +110 -0
  340. package/src/modules/staff/lib/timesheets-projects-ui/ProjectMembersAvatarStack.tsx +73 -0
  341. package/src/modules/staff/lib/timesheets-projects-ui/ProjectsKpiStrip.tsx +185 -0
  342. package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +53 -0
  343. package/src/modules/staff/lib/timesheets-projects-ui/ViewModeToggle.tsx +63 -0
  344. package/src/modules/staff/lib/timesheets-projects-ui/useProjectsViewMode.ts +63 -0
  345. package/src/modules/staff/lib/timesheets-ui/AddRowDropdown.tsx +188 -0
  346. package/src/modules/staff/lib/timesheets-ui/CalendarPicker.tsx +229 -0
  347. package/src/modules/staff/lib/timesheets-ui/ColorPicker.tsx +65 -0
  348. package/src/modules/staff/lib/timesheets-ui/CreateProjectDialog.tsx +99 -0
  349. package/src/modules/staff/lib/timesheets-ui/ListView.tsx +230 -0
  350. package/src/modules/staff/lib/timesheets-ui/ProjectColorDot.tsx +40 -0
  351. package/src/modules/staff/lib/timesheets-ui/TimerBar.tsx +327 -0
  352. package/src/modules/staff/lib/timesheets-ui/ViewSwitcher.tsx +60 -0
  353. package/src/modules/staff/lib/timesheets-ui/colors.ts +58 -0
  354. package/src/modules/staff/migrations/.snapshot-open-mercato.json +1148 -0
  355. package/src/modules/staff/migrations/Migration20260326135612.ts +26 -0
  356. package/src/modules/staff/migrations/Migration20260413102715.ts +25 -0
  357. package/src/modules/staff/migrations/Migration20260413111602.ts +13 -0
  358. package/src/modules/staff/migrations/Migration20260511112759.ts +21 -0
  359. package/src/modules/staff/search.ts +35 -0
  360. package/src/modules/staff/setup.ts +15 -0
  361. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/config.ts +17 -0
  362. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx +158 -0
  363. package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.ts +25 -0
  364. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/config.ts +15 -0
  365. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.tsx +297 -0
  366. package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.ts +25 -0
  367. package/src/modules/staff/widgets/injection/timer-sidebar-indicator/widget.tsx +161 -0
  368. package/src/modules/staff/widgets/injection-table.ts +10 -0
  369. package/src/modules/sync_excel/api/import/route.ts +23 -18
  370. package/src/modules/translations/commands/translations.ts +49 -41
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/resources/commands/resources.ts"],
4
- "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects, parseWithCustomFields, setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { buildCustomFieldResetMap, diffCustomFieldChanges, loadCustomFieldSnapshot, type CustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { Dictionary, DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { ResourcesResource, ResourcesResourceTag, ResourcesResourceTagAssignment } from '../data/entities'\nimport {\n resourcesResourceCreateSchema,\n resourcesResourceUpdateSchema,\n type ResourcesResourceCreateInput,\n type ResourcesResourceUpdateInput,\n} from '../data/validators'\nimport { resourcesResourceCrudEvents } from '../lib/crud'\nimport { ensureOrganizationScope, ensureTenantScope, extractUndoPayload } from './shared'\nimport { RESOURCES_CAPACITY_UNIT_DICTIONARY_KEY } from '../lib/capacityUnits'\nimport { E } from '#generated/entities.ids.generated'\n\nconst resourceCrudIndexer: CrudIndexerConfig<ResourcesResource> = {\n entityType: E.resources.resources_resource,\n}\n\ntype CapacityUnitSnapshot = {\n value: string\n name: string\n color: string | null\n icon: string | null\n}\n\ntype ResourceSnapshot = {\n id: string\n tenantId: string\n organizationId: string\n name: string\n description: string | null\n resourceTypeId: string | null\n capacity: number | null\n capacityUnitValue: string | null\n capacityUnitName: string | null\n capacityUnitColor: string | null\n capacityUnitIcon: string | null\n appearanceIcon: string | null\n appearanceColor: string | null\n isActive: boolean\n availabilityRuleSetId: string | null\n tags: string[]\n deletedAt: string | null\n customFields?: CustomFieldSnapshot | null\n}\n\ntype ResourceUndoPayload = {\n before?: ResourceSnapshot | null\n after?: ResourceSnapshot | null\n customBefore?: CustomFieldSnapshot | null\n customAfter?: CustomFieldSnapshot | null\n}\n\nasync function resolveCapacityUnit(\n em: EntityManager,\n scope: { tenantId: string; organizationId: string },\n rawValue: string,\n): Promise<CapacityUnitSnapshot> {\n const trimmed = rawValue.trim()\n if (!trimmed) {\n throw new CrudHttpError(400, { error: 'Capacity unit is required.' })\n }\n const dictionary = await findOneWithDecryption(\n em,\n Dictionary,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n key: RESOURCES_CAPACITY_UNIT_DICTIONARY_KEY,\n deletedAt: null,\n isActive: true,\n },\n undefined,\n scope,\n )\n if (!dictionary) {\n throw new CrudHttpError(400, { error: 'Capacity unit dictionary is not configured.' })\n }\n const normalizedValue = trimmed.toLowerCase()\n const entry = await findOneWithDecryption(\n em,\n DictionaryEntry,\n {\n dictionary,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n normalizedValue,\n },\n { populate: ['dictionary'] },\n scope,\n )\n if (!entry) {\n throw new CrudHttpError(400, { error: 'Capacity unit not found.' })\n }\n return {\n value: entry.value,\n name: entry.label?.trim().length ? entry.label : entry.value,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }\n}\n\nfunction normalizeTagIds(tags?: Array<string | null | undefined>): string[] {\n if (!Array.isArray(tags)) return []\n const set = new Set<string>()\n tags.forEach((id) => {\n if (typeof id === 'string' && id.trim().length > 0) set.add(id.trim())\n })\n return Array.from(set)\n}\n\nasync function loadResourceSnapshot(em: EntityManager, id: string): Promise<ResourceSnapshot | null> {\n const resource = await findOneWithDecryption(\n em,\n ResourcesResource,\n { id },\n undefined,\n { tenantId: null, organizationId: null },\n )\n if (!resource) return null\n const assignments = await em.find(\n ResourcesResourceTagAssignment,\n { resource: resource.id },\n { populate: ['tag'] },\n )\n const tags = assignments\n .map((assignment) => (assignment.tag as ResourcesResourceTag | undefined)?.id ?? null)\n .filter((tagId): tagId is string => typeof tagId === 'string' && tagId.length > 0)\n .sort((a, b) => a.localeCompare(b))\n return {\n id: resource.id,\n tenantId: resource.tenantId,\n organizationId: resource.organizationId,\n name: resource.name,\n description: resource.description ?? null,\n resourceTypeId: resource.resourceTypeId ?? null,\n capacity: resource.capacity ?? null,\n capacityUnitValue: resource.capacityUnitValue ?? null,\n capacityUnitName: resource.capacityUnitName ?? null,\n capacityUnitColor: resource.capacityUnitColor ?? null,\n capacityUnitIcon: resource.capacityUnitIcon ?? null,\n appearanceIcon: resource.appearanceIcon ?? null,\n appearanceColor: resource.appearanceColor ?? null,\n isActive: resource.isActive,\n availabilityRuleSetId: resource.availabilityRuleSetId ?? null,\n tags,\n deletedAt: resource.deletedAt ? resource.deletedAt.toISOString() : null,\n }\n}\n\nasync function loadResourceCustomSnapshot(em: EntityManager, snapshot: ResourceSnapshot): Promise<CustomFieldSnapshot> {\n return loadCustomFieldSnapshot(em, {\n entityId: E.resources.resources_resource,\n recordId: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n })\n}\n\nasync function syncResourcesResourceTags(em: EntityManager, params: {\n resourceId: string\n organizationId: string\n tenantId: string\n tagIds?: Array<string | null | undefined> | null\n}) {\n if (params.tagIds === undefined) return\n const tagIds = normalizeTagIds(params.tagIds ?? [])\n if (tagIds.length === 0) {\n await em.nativeDelete(ResourcesResourceTagAssignment, { resource: params.resourceId })\n return\n }\n const tagsInScope = await em.find(ResourcesResourceTag, {\n id: { $in: tagIds },\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n })\n if (tagsInScope.length !== tagIds.length) {\n throw new CrudHttpError(400, { error: 'One or more tags not found for this scope' })\n }\n const byId = new Map(tagsInScope.map((tag) => [tag.id, tag]))\n await em.nativeDelete(ResourcesResourceTagAssignment, { resource: params.resourceId })\n const resource = em.getReference(ResourcesResource, params.resourceId)\n for (const tagId of tagIds) {\n const tag = byId.get(tagId)\n if (!tag) continue\n const assignment = em.create(ResourcesResourceTagAssignment, {\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n resource,\n tag,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(assignment)\n }\n}\n\nconst createResourceCommand: CommandHandler<ResourcesResourceCreateInput, { resourceId: string }> = {\n id: 'resources.resources.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(resourcesResourceCreateSchema, rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const now = new Date()\n const unitValue =\n typeof parsed.capacityUnitValue === 'string' ? parsed.capacityUnitValue.trim() : ''\n const unitSnapshot = unitValue\n ? await resolveCapacityUnit(em, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }, unitValue)\n : null\n const record = em.create(ResourcesResource, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n name: parsed.name,\n description: parsed.description ?? null,\n resourceTypeId: parsed.resourceTypeId ?? null,\n capacity: parsed.capacity ?? null,\n capacityUnitValue: unitSnapshot?.value ?? null,\n capacityUnitName: unitSnapshot?.name ?? null,\n capacityUnitColor: unitSnapshot?.color ?? null,\n capacityUnitIcon: unitSnapshot?.icon ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n isActive: parsed.isActive ?? true,\n availabilityRuleSetId: parsed.availabilityRuleSetId ?? null,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n await em.flush()\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n values: custom,\n })\n await syncResourcesResourceTags(em, {\n resourceId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n tagIds: parsed.tags,\n })\n await em.flush()\n await emitCrudSideEffects({\n dataEngine,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n return { resourceId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadResourceSnapshot(em, result.resourceId)\n if (!snapshot) return null\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n return { snapshot, custom }\n },\n buildLog: async ({ result, ctx }) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadResourceSnapshot(em, result?.resourceId ?? '')\n if (!snapshot) return null\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n const snapshotWithCustom: ResourceSnapshot = custom\n ? { ...snapshot, customFields: custom }\n : snapshot\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resources.create', 'Create resource'),\n resourceKind: 'resources.resource',\n resourceId: snapshotWithCustom.id,\n tenantId: snapshotWithCustom.tenantId,\n organizationId: snapshotWithCustom.organizationId,\n snapshotAfter: snapshotWithCustom,\n payload: {\n undo: {\n after: snapshotWithCustom,\n customAfter: custom,\n } satisfies ResourceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ResourceUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(ResourcesResource, { id: after.id })\n if (record) {\n record.deletedAt = new Date()\n record.updatedAt = new Date()\n await em.flush()\n\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n }\n },\n}\n\nconst updateResourceCommand: CommandHandler<ResourcesResourceUpdateInput, { resourceId: string }> = {\n id: 'resources.resources.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(resourcesResourceUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadResourceSnapshot(em, parsed.id)\n if (!snapshot) return {}\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n return { before: snapshot, customBefore: custom }\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(resourcesResourceUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(\n em,\n ResourcesResource,\n { id: parsed.id, deletedAt: null },\n undefined,\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n if (!record) throw new CrudHttpError(404, { error: 'Resources resource not found.' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n\n if (parsed.capacityUnitValue !== undefined) {\n const unitValue =\n typeof parsed.capacityUnitValue === 'string' ? parsed.capacityUnitValue.trim() : ''\n if (!unitValue) {\n record.capacityUnitValue = null\n record.capacityUnitName = null\n record.capacityUnitColor = null\n record.capacityUnitIcon = null\n } else {\n const unitSnapshot = await resolveCapacityUnit(\n em,\n { tenantId: record.tenantId, organizationId: record.organizationId },\n unitValue,\n )\n record.capacityUnitValue = unitSnapshot.value\n record.capacityUnitName = unitSnapshot.name\n record.capacityUnitColor = unitSnapshot.color\n record.capacityUnitIcon = unitSnapshot.icon\n }\n }\n if (parsed.name !== undefined) record.name = parsed.name\n if (parsed.description !== undefined) record.description = parsed.description ?? null\n if (parsed.resourceTypeId !== undefined) record.resourceTypeId = parsed.resourceTypeId ?? null\n if (parsed.capacity !== undefined) record.capacity = parsed.capacity ?? null\n if (parsed.appearanceIcon !== undefined) record.appearanceIcon = parsed.appearanceIcon ?? null\n if (parsed.appearanceColor !== undefined) record.appearanceColor = parsed.appearanceColor ?? null\n if (parsed.availabilityRuleSetId !== undefined) record.availabilityRuleSetId = parsed.availabilityRuleSetId ?? null\n record.updatedAt = new Date()\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive\n await em.flush()\n await syncResourcesResourceTags(em, {\n resourceId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n tagIds: parsed.tags,\n })\n await em.flush()\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n values: custom,\n })\n await emitCrudSideEffects({\n dataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n return { resourceId: record.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const before = snapshots.before as ResourceSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const after = await loadResourceSnapshot(em, before.id)\n if (!after) return null\n const customBefore = (snapshots as { customBefore?: CustomFieldSnapshot | null }).customBefore ?? undefined\n const customAfter = await loadResourceCustomSnapshot(em, after)\n const beforeWithCustom: ResourceSnapshot = customBefore\n ? { ...before, customFields: customBefore }\n : before\n const afterWithCustom: ResourceSnapshot = customAfter\n ? { ...after, customFields: customAfter }\n : after\n const changes = buildChanges(before as unknown as Record<string, unknown>, after as unknown as Record<string, unknown>, [\n 'name',\n 'description',\n 'resourceTypeId',\n 'capacity',\n 'capacityUnitValue',\n 'capacityUnitName',\n 'capacityUnitColor',\n 'capacityUnitIcon',\n 'appearanceIcon',\n 'appearanceColor',\n 'isActive',\n 'availabilityRuleSetId',\n 'deletedAt',\n ])\n if (before.tags.join(',') !== after.tags.join(',')) {\n changes.tags = { from: before.tags, to: after.tags }\n }\n const customChanges = diffCustomFieldChanges(customBefore, customAfter)\n if (Object.keys(customChanges).length) {\n changes.customFields = { from: customBefore ?? null, to: customAfter ?? null }\n }\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resources.update', 'Update resource'),\n resourceKind: 'resources.resource',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: beforeWithCustom,\n snapshotAfter: afterWithCustom,\n changes,\n payload: {\n undo: {\n before: beforeWithCustom,\n after: afterWithCustom,\n customBefore: customBefore ?? null,\n customAfter,\n } satisfies ResourceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ResourceUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const fallbackCustomBefore = (before as ResourceSnapshot).customFields ?? null\n const fallbackCustomAfter = (payload?.after as ResourceSnapshot | null | undefined)?.customFields ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(ResourcesResource, { id: before.id })\n if (!record) return\n record.name = before.name\n record.description = before.description ?? null\n record.resourceTypeId = before.resourceTypeId ?? null\n record.capacity = before.capacity ?? null\n record.capacityUnitValue = before.capacityUnitValue ?? null\n record.capacityUnitName = before.capacityUnitName ?? null\n record.capacityUnitColor = before.capacityUnitColor ?? null\n record.capacityUnitIcon = before.capacityUnitIcon ?? null\n record.appearanceIcon = before.appearanceIcon ?? null\n record.appearanceColor = before.appearanceColor ?? null\n record.isActive = before.isActive\n record.availabilityRuleSetId = before.availabilityRuleSetId ?? null\n record.deletedAt = before.deletedAt ? new Date(before.deletedAt) : null\n record.updatedAt = new Date()\n await em.flush()\n await syncResourcesResourceTags(em, {\n resourceId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n tagIds: before.tags,\n })\n await em.flush()\n\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n const customBefore = payload.customBefore ?? fallbackCustomBefore ?? undefined\n const customAfter = payload.customAfter ?? fallbackCustomAfter ?? undefined\n if (customBefore || customAfter) {\n const reset = buildCustomFieldResetMap(customBefore, customAfter)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n values: reset,\n })\n }\n\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n },\n}\n\nconst deleteResourceCommand: CommandHandler<{ id?: string }, { resourceId: string }> = {\n id: 'resources.resources.delete',\n async prepare(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Resource id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadResourceSnapshot(em, id)\n if (!snapshot) return {}\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n return { before: snapshot, customBefore: custom }\n },\n async execute(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Resource id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(\n em,\n ResourcesResource,\n { id, deletedAt: null },\n undefined,\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n if (!record) throw new CrudHttpError(404, { error: 'Resources resource not found.' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n record.deletedAt = new Date()\n record.updatedAt = new Date()\n await em.flush()\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n return { resourceId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as ResourceSnapshot | undefined\n if (!before) return null\n const customBefore = (snapshots as { customBefore?: CustomFieldSnapshot | null }).customBefore ?? undefined\n const beforeWithCustom: ResourceSnapshot = customBefore\n ? { ...before, customFields: customBefore }\n : before\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resources.delete', 'Delete resource'),\n resourceKind: 'resources.resource',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: beforeWithCustom,\n payload: {\n undo: {\n before: beforeWithCustom,\n customBefore: customBefore ?? null,\n } satisfies ResourceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ResourceUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const fallbackCustomBefore = (before as ResourceSnapshot).customFields ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(ResourcesResource, { id: before.id })\n if (!record) {\n record = em.create(ResourcesResource, {\n id: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n name: before.name,\n description: before.description ?? null,\n resourceTypeId: before.resourceTypeId ?? null,\n capacity: before.capacity ?? null,\n capacityUnitValue: before.capacityUnitValue ?? null,\n capacityUnitName: before.capacityUnitName ?? null,\n capacityUnitColor: before.capacityUnitColor ?? null,\n capacityUnitIcon: before.capacityUnitIcon ?? null,\n appearanceIcon: before.appearanceIcon ?? null,\n appearanceColor: before.appearanceColor ?? null,\n isActive: before.isActive,\n availabilityRuleSetId: before.availabilityRuleSetId ?? null,\n deletedAt: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.name = before.name\n record.description = before.description ?? null\n record.resourceTypeId = before.resourceTypeId ?? null\n record.capacity = before.capacity ?? null\n record.capacityUnitValue = before.capacityUnitValue ?? null\n record.capacityUnitName = before.capacityUnitName ?? null\n record.capacityUnitColor = before.capacityUnitColor ?? null\n record.capacityUnitIcon = before.capacityUnitIcon ?? null\n record.appearanceIcon = before.appearanceIcon ?? null\n record.appearanceColor = before.appearanceColor ?? null\n record.isActive = before.isActive\n record.availabilityRuleSetId = before.availabilityRuleSetId ?? null\n record.deletedAt = null\n record.updatedAt = new Date()\n }\n await em.flush()\n await syncResourcesResourceTags(em, {\n resourceId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n tagIds: before.tags,\n })\n await em.flush()\n\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n const customBefore = payload.customBefore ?? fallbackCustomBefore ?? undefined\n if (customBefore) {\n const reset = buildCustomFieldResetMap(customBefore, undefined)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n values: reset,\n })\n }\n\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n },\n}\n\nregisterCommand(createResourceCommand)\nregisterCommand(updateResourceCommand)\nregisterCommand(deleteResourceCommand)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects, parseWithCustomFields, setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { buildCustomFieldResetMap, diffCustomFieldChanges, loadCustomFieldSnapshot, type CustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { Dictionary, DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { ResourcesResource, ResourcesResourceTag, ResourcesResourceTagAssignment } from '../data/entities'\nimport {\n resourcesResourceCreateSchema,\n resourcesResourceUpdateSchema,\n type ResourcesResourceCreateInput,\n type ResourcesResourceUpdateInput,\n} from '../data/validators'\nimport { resourcesResourceCrudEvents } from '../lib/crud'\nimport { ensureOrganizationScope, ensureTenantScope, extractUndoPayload } from './shared'\nimport { RESOURCES_CAPACITY_UNIT_DICTIONARY_KEY } from '../lib/capacityUnits'\nimport { E } from '#generated/entities.ids.generated'\n\nconst resourceCrudIndexer: CrudIndexerConfig<ResourcesResource> = {\n entityType: E.resources.resources_resource,\n}\n\ntype CapacityUnitSnapshot = {\n value: string\n name: string\n color: string | null\n icon: string | null\n}\n\ntype ResourceSnapshot = {\n id: string\n tenantId: string\n organizationId: string\n name: string\n description: string | null\n resourceTypeId: string | null\n capacity: number | null\n capacityUnitValue: string | null\n capacityUnitName: string | null\n capacityUnitColor: string | null\n capacityUnitIcon: string | null\n appearanceIcon: string | null\n appearanceColor: string | null\n isActive: boolean\n availabilityRuleSetId: string | null\n tags: string[]\n deletedAt: string | null\n customFields?: CustomFieldSnapshot | null\n}\n\ntype ResourceUndoPayload = {\n before?: ResourceSnapshot | null\n after?: ResourceSnapshot | null\n customBefore?: CustomFieldSnapshot | null\n customAfter?: CustomFieldSnapshot | null\n}\n\nasync function resolveCapacityUnit(\n em: EntityManager,\n scope: { tenantId: string; organizationId: string },\n rawValue: string,\n): Promise<CapacityUnitSnapshot> {\n const trimmed = rawValue.trim()\n if (!trimmed) {\n throw new CrudHttpError(400, { error: 'Capacity unit is required.' })\n }\n const dictionary = await findOneWithDecryption(\n em,\n Dictionary,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n key: RESOURCES_CAPACITY_UNIT_DICTIONARY_KEY,\n deletedAt: null,\n isActive: true,\n },\n undefined,\n scope,\n )\n if (!dictionary) {\n throw new CrudHttpError(400, { error: 'Capacity unit dictionary is not configured.' })\n }\n const normalizedValue = trimmed.toLowerCase()\n const entry = await findOneWithDecryption(\n em,\n DictionaryEntry,\n {\n dictionary,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n normalizedValue,\n },\n { populate: ['dictionary'] },\n scope,\n )\n if (!entry) {\n throw new CrudHttpError(400, { error: 'Capacity unit not found.' })\n }\n return {\n value: entry.value,\n name: entry.label?.trim().length ? entry.label : entry.value,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n }\n}\n\nfunction normalizeTagIds(tags?: Array<string | null | undefined>): string[] {\n if (!Array.isArray(tags)) return []\n const set = new Set<string>()\n tags.forEach((id) => {\n if (typeof id === 'string' && id.trim().length > 0) set.add(id.trim())\n })\n return Array.from(set)\n}\n\nasync function loadResourceSnapshot(em: EntityManager, id: string): Promise<ResourceSnapshot | null> {\n const resource = await findOneWithDecryption(\n em,\n ResourcesResource,\n { id },\n undefined,\n { tenantId: null, organizationId: null },\n )\n if (!resource) return null\n const assignments = await em.find(\n ResourcesResourceTagAssignment,\n { resource: resource.id },\n { populate: ['tag'] },\n )\n const tags = assignments\n .map((assignment) => (assignment.tag as ResourcesResourceTag | undefined)?.id ?? null)\n .filter((tagId): tagId is string => typeof tagId === 'string' && tagId.length > 0)\n .sort((a, b) => a.localeCompare(b))\n return {\n id: resource.id,\n tenantId: resource.tenantId,\n organizationId: resource.organizationId,\n name: resource.name,\n description: resource.description ?? null,\n resourceTypeId: resource.resourceTypeId ?? null,\n capacity: resource.capacity ?? null,\n capacityUnitValue: resource.capacityUnitValue ?? null,\n capacityUnitName: resource.capacityUnitName ?? null,\n capacityUnitColor: resource.capacityUnitColor ?? null,\n capacityUnitIcon: resource.capacityUnitIcon ?? null,\n appearanceIcon: resource.appearanceIcon ?? null,\n appearanceColor: resource.appearanceColor ?? null,\n isActive: resource.isActive,\n availabilityRuleSetId: resource.availabilityRuleSetId ?? null,\n tags,\n deletedAt: resource.deletedAt ? resource.deletedAt.toISOString() : null,\n }\n}\n\nasync function loadResourceCustomSnapshot(em: EntityManager, snapshot: ResourceSnapshot): Promise<CustomFieldSnapshot> {\n return loadCustomFieldSnapshot(em, {\n entityId: E.resources.resources_resource,\n recordId: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n })\n}\n\nasync function syncResourcesResourceTags(em: EntityManager, params: {\n resourceId: string\n organizationId: string\n tenantId: string\n tagIds?: Array<string | null | undefined> | null\n}) {\n if (params.tagIds === undefined) return\n const tagIds = normalizeTagIds(params.tagIds ?? [])\n if (tagIds.length === 0) {\n await em.nativeDelete(ResourcesResourceTagAssignment, { resource: params.resourceId })\n return\n }\n const tagsInScope = await em.find(ResourcesResourceTag, {\n id: { $in: tagIds },\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n })\n if (tagsInScope.length !== tagIds.length) {\n throw new CrudHttpError(400, { error: 'One or more tags not found for this scope' })\n }\n const byId = new Map(tagsInScope.map((tag) => [tag.id, tag]))\n await em.nativeDelete(ResourcesResourceTagAssignment, { resource: params.resourceId })\n const resource = em.getReference(ResourcesResource, params.resourceId)\n for (const tagId of tagIds) {\n const tag = byId.get(tagId)\n if (!tag) continue\n const assignment = em.create(ResourcesResourceTagAssignment, {\n organizationId: params.organizationId,\n tenantId: params.tenantId,\n resource,\n tag,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(assignment)\n }\n}\n\nconst createResourceCommand: CommandHandler<ResourcesResourceCreateInput, { resourceId: string }> = {\n id: 'resources.resources.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(resourcesResourceCreateSchema, rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const now = new Date()\n const unitValue =\n typeof parsed.capacityUnitValue === 'string' ? parsed.capacityUnitValue.trim() : ''\n const unitSnapshot = unitValue\n ? await resolveCapacityUnit(em, { tenantId: parsed.tenantId, organizationId: parsed.organizationId }, unitValue)\n : null\n const record = em.create(ResourcesResource, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n name: parsed.name,\n description: parsed.description ?? null,\n resourceTypeId: parsed.resourceTypeId ?? null,\n capacity: parsed.capacity ?? null,\n capacityUnitValue: unitSnapshot?.value ?? null,\n capacityUnitName: unitSnapshot?.name ?? null,\n capacityUnitColor: unitSnapshot?.color ?? null,\n capacityUnitIcon: unitSnapshot?.icon ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n isActive: parsed.isActive ?? true,\n availabilityRuleSetId: parsed.availabilityRuleSetId ?? null,\n createdAt: now,\n updatedAt: now,\n })\n await withAtomicFlush(em, [\n async () => {\n em.persist(record)\n await em.flush()\n },\n () => syncResourcesResourceTags(em, {\n resourceId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n tagIds: parsed.tags,\n }),\n ], { transaction: true })\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n values: custom,\n })\n await emitCrudSideEffects({\n dataEngine,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n return { resourceId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadResourceSnapshot(em, result.resourceId)\n if (!snapshot) return null\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n return { snapshot, custom }\n },\n buildLog: async ({ result, ctx }) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadResourceSnapshot(em, result?.resourceId ?? '')\n if (!snapshot) return null\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n const snapshotWithCustom: ResourceSnapshot = custom\n ? { ...snapshot, customFields: custom }\n : snapshot\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resources.create', 'Create resource'),\n resourceKind: 'resources.resource',\n resourceId: snapshotWithCustom.id,\n tenantId: snapshotWithCustom.tenantId,\n organizationId: snapshotWithCustom.organizationId,\n snapshotAfter: snapshotWithCustom,\n payload: {\n undo: {\n after: snapshotWithCustom,\n customAfter: custom,\n } satisfies ResourceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ResourceUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(ResourcesResource, { id: after.id })\n if (record) {\n record.deletedAt = new Date()\n record.updatedAt = new Date()\n await em.flush()\n\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n }\n },\n}\n\nconst updateResourceCommand: CommandHandler<ResourcesResourceUpdateInput, { resourceId: string }> = {\n id: 'resources.resources.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(resourcesResourceUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadResourceSnapshot(em, parsed.id)\n if (!snapshot) return {}\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n return { before: snapshot, customBefore: custom }\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(resourcesResourceUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(\n em,\n ResourcesResource,\n { id: parsed.id, deletedAt: null },\n undefined,\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n if (!record) throw new CrudHttpError(404, { error: 'Resources resource not found.' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n\n let capacityUnit: CapacityUnitSnapshot | null | undefined\n if (parsed.capacityUnitValue !== undefined) {\n const unitValue =\n typeof parsed.capacityUnitValue === 'string' ? parsed.capacityUnitValue.trim() : ''\n capacityUnit = unitValue\n ? await resolveCapacityUnit(\n em,\n { tenantId: record.tenantId, organizationId: record.organizationId },\n unitValue,\n )\n : null\n }\n await withAtomicFlush(em, [\n () => {\n if (parsed.capacityUnitValue !== undefined) {\n record.capacityUnitValue = capacityUnit?.value ?? null\n record.capacityUnitName = capacityUnit?.name ?? null\n record.capacityUnitColor = capacityUnit?.color ?? null\n record.capacityUnitIcon = capacityUnit?.icon ?? null\n }\n if (parsed.name !== undefined) record.name = parsed.name\n if (parsed.description !== undefined) record.description = parsed.description ?? null\n if (parsed.resourceTypeId !== undefined) record.resourceTypeId = parsed.resourceTypeId ?? null\n if (parsed.capacity !== undefined) record.capacity = parsed.capacity ?? null\n if (parsed.appearanceIcon !== undefined) record.appearanceIcon = parsed.appearanceIcon ?? null\n if (parsed.appearanceColor !== undefined) record.appearanceColor = parsed.appearanceColor ?? null\n if (parsed.availabilityRuleSetId !== undefined) record.availabilityRuleSetId = parsed.availabilityRuleSetId ?? null\n record.updatedAt = new Date()\n if (parsed.isActive !== undefined) record.isActive = parsed.isActive\n },\n () => syncResourcesResourceTags(em, {\n resourceId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n tagIds: parsed.tags,\n }),\n ], { transaction: true })\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n values: custom,\n })\n await emitCrudSideEffects({\n dataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n return { resourceId: record.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const before = snapshots.before as ResourceSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const after = await loadResourceSnapshot(em, before.id)\n if (!after) return null\n const customBefore = (snapshots as { customBefore?: CustomFieldSnapshot | null }).customBefore ?? undefined\n const customAfter = await loadResourceCustomSnapshot(em, after)\n const beforeWithCustom: ResourceSnapshot = customBefore\n ? { ...before, customFields: customBefore }\n : before\n const afterWithCustom: ResourceSnapshot = customAfter\n ? { ...after, customFields: customAfter }\n : after\n const changes = buildChanges(before as unknown as Record<string, unknown>, after as unknown as Record<string, unknown>, [\n 'name',\n 'description',\n 'resourceTypeId',\n 'capacity',\n 'capacityUnitValue',\n 'capacityUnitName',\n 'capacityUnitColor',\n 'capacityUnitIcon',\n 'appearanceIcon',\n 'appearanceColor',\n 'isActive',\n 'availabilityRuleSetId',\n 'deletedAt',\n ])\n if (before.tags.join(',') !== after.tags.join(',')) {\n changes.tags = { from: before.tags, to: after.tags }\n }\n const customChanges = diffCustomFieldChanges(customBefore, customAfter)\n if (Object.keys(customChanges).length) {\n changes.customFields = { from: customBefore ?? null, to: customAfter ?? null }\n }\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resources.update', 'Update resource'),\n resourceKind: 'resources.resource',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: beforeWithCustom,\n snapshotAfter: afterWithCustom,\n changes,\n payload: {\n undo: {\n before: beforeWithCustom,\n after: afterWithCustom,\n customBefore: customBefore ?? null,\n customAfter,\n } satisfies ResourceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ResourceUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const fallbackCustomBefore = (before as ResourceSnapshot).customFields ?? null\n const fallbackCustomAfter = (payload?.after as ResourceSnapshot | null | undefined)?.customFields ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(ResourcesResource, { id: before.id })\n if (!record) return\n await withAtomicFlush(em, [\n () => {\n record.name = before.name\n record.description = before.description ?? null\n record.resourceTypeId = before.resourceTypeId ?? null\n record.capacity = before.capacity ?? null\n record.capacityUnitValue = before.capacityUnitValue ?? null\n record.capacityUnitName = before.capacityUnitName ?? null\n record.capacityUnitColor = before.capacityUnitColor ?? null\n record.capacityUnitIcon = before.capacityUnitIcon ?? null\n record.appearanceIcon = before.appearanceIcon ?? null\n record.appearanceColor = before.appearanceColor ?? null\n record.isActive = before.isActive\n record.availabilityRuleSetId = before.availabilityRuleSetId ?? null\n record.deletedAt = before.deletedAt ? new Date(before.deletedAt) : null\n record.updatedAt = new Date()\n },\n () => syncResourcesResourceTags(em, {\n resourceId: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n tagIds: before.tags,\n }),\n ], { transaction: true })\n\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n const customBefore = payload.customBefore ?? fallbackCustomBefore ?? undefined\n const customAfter = payload.customAfter ?? fallbackCustomAfter ?? undefined\n if (customBefore || customAfter) {\n const reset = buildCustomFieldResetMap(customBefore, customAfter)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n values: reset,\n })\n }\n\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n },\n}\n\nconst deleteResourceCommand: CommandHandler<{ id?: string }, { resourceId: string }> = {\n id: 'resources.resources.delete',\n async prepare(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Resource id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadResourceSnapshot(em, id)\n if (!snapshot) return {}\n const custom = await loadResourceCustomSnapshot(em, snapshot)\n return { before: snapshot, customBefore: custom }\n },\n async execute(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Resource id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await findOneWithDecryption(\n em,\n ResourcesResource,\n { id, deletedAt: null },\n undefined,\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n if (!record) throw new CrudHttpError(404, { error: 'Resources resource not found.' })\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n record.deletedAt = new Date()\n record.updatedAt = new Date()\n await em.flush()\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n return { resourceId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as ResourceSnapshot | undefined\n if (!before) return null\n const customBefore = (snapshots as { customBefore?: CustomFieldSnapshot | null }).customBefore ?? undefined\n const beforeWithCustom: ResourceSnapshot = customBefore\n ? { ...before, customFields: customBefore }\n : before\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resources.delete', 'Delete resource'),\n resourceKind: 'resources.resource',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: beforeWithCustom,\n payload: {\n undo: {\n before: beforeWithCustom,\n customBefore: customBefore ?? null,\n } satisfies ResourceUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<ResourceUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const fallbackCustomBefore = (before as ResourceSnapshot).customFields ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(ResourcesResource, { id: before.id })\n await withAtomicFlush(em, [\n async () => {\n if (!record) {\n record = em.create(ResourcesResource, {\n id: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n name: before.name,\n description: before.description ?? null,\n resourceTypeId: before.resourceTypeId ?? null,\n capacity: before.capacity ?? null,\n capacityUnitValue: before.capacityUnitValue ?? null,\n capacityUnitName: before.capacityUnitName ?? null,\n capacityUnitColor: before.capacityUnitColor ?? null,\n capacityUnitIcon: before.capacityUnitIcon ?? null,\n appearanceIcon: before.appearanceIcon ?? null,\n appearanceColor: before.appearanceColor ?? null,\n isActive: before.isActive,\n availabilityRuleSetId: before.availabilityRuleSetId ?? null,\n deletedAt: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.name = before.name\n record.description = before.description ?? null\n record.resourceTypeId = before.resourceTypeId ?? null\n record.capacity = before.capacity ?? null\n record.capacityUnitValue = before.capacityUnitValue ?? null\n record.capacityUnitName = before.capacityUnitName ?? null\n record.capacityUnitColor = before.capacityUnitColor ?? null\n record.capacityUnitIcon = before.capacityUnitIcon ?? null\n record.appearanceIcon = before.appearanceIcon ?? null\n record.appearanceColor = before.appearanceColor ?? null\n record.isActive = before.isActive\n record.availabilityRuleSetId = before.availabilityRuleSetId ?? null\n record.deletedAt = null\n record.updatedAt = new Date()\n }\n await em.flush()\n },\n () => syncResourcesResourceTags(em, {\n resourceId: (record as ResourcesResource).id,\n organizationId: (record as ResourcesResource).organizationId,\n tenantId: (record as ResourcesResource).tenantId,\n tagIds: before.tags,\n }),\n ], { transaction: true })\n const resolvedRecord = record as ResourcesResource\n\n const dataEngine = (ctx.container.resolve('dataEngine') as DataEngine)\n const customBefore = payload.customBefore ?? fallbackCustomBefore ?? undefined\n if (customBefore) {\n const reset = buildCustomFieldResetMap(customBefore, undefined)\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: E.resources.resources_resource,\n recordId: resolvedRecord.id,\n tenantId: resolvedRecord.tenantId,\n organizationId: resolvedRecord.organizationId,\n values: reset,\n })\n }\n\n await emitCrudUndoSideEffects({\n dataEngine,\n action: 'created',\n entity: resolvedRecord,\n identifiers: {\n id: resolvedRecord.id,\n organizationId: resolvedRecord.organizationId,\n tenantId: resolvedRecord.tenantId,\n },\n events: resourcesResourceCrudEvents,\n indexer: resourceCrudIndexer,\n })\n },\n}\n\nregisterCommand(createResourceCommand)\nregisterCommand(updateResourceCommand)\nregisterCommand(deleteResourceCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,6 @@
1
1
  import { registerCommand } from "@open-mercato/shared/lib/commands";
2
2
  import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
3
+ import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
3
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
4
5
  import { slugifyTagLabel } from "@open-mercato/shared/lib/utils";
5
6
  import { ResourcesResourceTag, ResourcesResourceTagAssignment } from "../data/entities.js";
@@ -95,9 +96,12 @@ const deleteTagCommand = {
95
96
  if (!tag) throw new CrudHttpError(404, { error: "Tag not found" });
96
97
  ensureTenantScope(ctx, tag.tenantId);
97
98
  ensureOrganizationScope(ctx, tag.organizationId);
98
- await em.nativeDelete(ResourcesResourceTagAssignment, { tag: tag.id });
99
- em.remove(tag);
100
- await em.flush();
99
+ await withAtomicFlush(em, [
100
+ async () => {
101
+ await em.nativeDelete(ResourcesResourceTagAssignment, { tag: tag.id });
102
+ em.remove(tag);
103
+ }
104
+ ], { transaction: true });
101
105
  return { tagId: id };
102
106
  },
103
107
  buildLog: async ({ input, result, ctx }) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/resources/commands/tags.ts"],
4
- "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { slugifyTagLabel } from '@open-mercato/shared/lib/utils'\nimport { ResourcesResourceTag, ResourcesResourceTagAssignment } from '../data/entities'\nimport {\n resourcesResourceTagCreateSchema,\n resourcesResourceTagUpdateSchema,\n type ResourcesResourceTagCreateInput,\n type ResourcesResourceTagUpdateInput,\n} from '../data/validators'\nimport { ensureOrganizationScope, ensureTenantScope } from './shared'\n\nconst createTagCommand: CommandHandler<ResourcesResourceTagCreateInput, { tagId: string }> = {\n id: 'resources.resourceTags.create',\n async execute(rawInput, ctx) {\n const parsed = resourcesResourceTagCreateSchema.parse(rawInput ?? {})\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n const slug =\n typeof parsed.slug === 'string' && parsed.slug.trim().length\n ? parsed.slug.trim()\n : slugifyTagLabel(parsed.label)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const conflict = await em.findOne(ResourcesResourceTag, {\n slug,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n if (conflict) throw new CrudHttpError(409, { error: 'Tag slug already exists for this scope' })\n const tag = em.create(ResourcesResourceTag, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n slug,\n label: parsed.label,\n color: parsed.color ?? null,\n description: parsed.description ?? null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n await em.persist(tag).flush()\n return { tagId: tag.id }\n },\n buildLog: async ({ input, result, ctx }) => {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resourceTags.create', 'Create resource tag'),\n resourceKind: 'resources.resourceTag',\n resourceId: result?.tagId ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nconst updateTagCommand: CommandHandler<ResourcesResourceTagUpdateInput, { tagId: string }> = {\n id: 'resources.resourceTags.update',\n async execute(rawInput, ctx) {\n const parsed = resourcesResourceTagUpdateSchema.parse(rawInput ?? {})\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(ResourcesResourceTag, { id: parsed.id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n if (parsed.slug && parsed.slug !== tag.slug) {\n const conflict = await em.findOne(ResourcesResourceTag, {\n slug: parsed.slug,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n })\n if (conflict && conflict.id !== tag.id) {\n throw new CrudHttpError(409, { error: 'Tag slug already exists for this scope' })\n }\n tag.slug = parsed.slug\n }\n if (parsed.label !== undefined) tag.label = parsed.label\n if (parsed.color !== undefined) tag.color = parsed.color ?? null\n if (parsed.description !== undefined) tag.description = parsed.description ?? null\n await em.flush()\n return { tagId: tag.id }\n },\n buildLog: async ({ input, result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = result?.tagId ? await em.findOne(ResourcesResourceTag, { id: result.tagId }) : null\n return {\n actionLabel: translate('resources.audit.resourceTags.update', 'Update resource tag'),\n resourceKind: 'resources.resourceTag',\n resourceId: result?.tagId ?? input?.id ?? null,\n tenantId: tag?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: tag?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nconst deleteTagCommand: CommandHandler<{ id?: string }, { tagId: string }> = {\n id: 'resources.resourceTags.delete',\n async execute(input, ctx) {\n const id = typeof input?.id === 'string' ? input.id : null\n if (!id) throw new CrudHttpError(400, { error: 'Tag id is required' })\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(ResourcesResourceTag, { id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n await em.nativeDelete(ResourcesResourceTagAssignment, { tag: tag.id })\n em.remove(tag)\n await em.flush()\n return { tagId: id }\n },\n buildLog: async ({ input, result, ctx }) => {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resourceTags.delete', 'Delete resource tag'),\n resourceKind: 'resources.resourceTag',\n resourceId: result?.tagId ?? input?.id ?? null,\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nregisterCommand(createTagCommand)\nregisterCommand(updateTagCommand)\nregisterCommand(deleteTagCommand)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { slugifyTagLabel } from '@open-mercato/shared/lib/utils'\nimport { ResourcesResourceTag, ResourcesResourceTagAssignment } from '../data/entities'\nimport {\n resourcesResourceTagCreateSchema,\n resourcesResourceTagUpdateSchema,\n type ResourcesResourceTagCreateInput,\n type ResourcesResourceTagUpdateInput,\n} from '../data/validators'\nimport { ensureOrganizationScope, ensureTenantScope } from './shared'\n\nconst createTagCommand: CommandHandler<ResourcesResourceTagCreateInput, { tagId: string }> = {\n id: 'resources.resourceTags.create',\n async execute(rawInput, ctx) {\n const parsed = resourcesResourceTagCreateSchema.parse(rawInput ?? {})\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n const slug =\n typeof parsed.slug === 'string' && parsed.slug.trim().length\n ? parsed.slug.trim()\n : slugifyTagLabel(parsed.label)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const conflict = await em.findOne(ResourcesResourceTag, {\n slug,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n })\n if (conflict) throw new CrudHttpError(409, { error: 'Tag slug already exists for this scope' })\n const tag = em.create(ResourcesResourceTag, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n slug,\n label: parsed.label,\n color: parsed.color ?? null,\n description: parsed.description ?? null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n await em.persist(tag).flush()\n return { tagId: tag.id }\n },\n buildLog: async ({ input, result, ctx }) => {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resourceTags.create', 'Create resource tag'),\n resourceKind: 'resources.resourceTag',\n resourceId: result?.tagId ?? null,\n tenantId: input?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: input?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nconst updateTagCommand: CommandHandler<ResourcesResourceTagUpdateInput, { tagId: string }> = {\n id: 'resources.resourceTags.update',\n async execute(rawInput, ctx) {\n const parsed = resourcesResourceTagUpdateSchema.parse(rawInput ?? {})\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(ResourcesResourceTag, { id: parsed.id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n if (parsed.slug && parsed.slug !== tag.slug) {\n const conflict = await em.findOne(ResourcesResourceTag, {\n slug: parsed.slug,\n organizationId: tag.organizationId,\n tenantId: tag.tenantId,\n })\n if (conflict && conflict.id !== tag.id) {\n throw new CrudHttpError(409, { error: 'Tag slug already exists for this scope' })\n }\n tag.slug = parsed.slug\n }\n if (parsed.label !== undefined) tag.label = parsed.label\n if (parsed.color !== undefined) tag.color = parsed.color ?? null\n if (parsed.description !== undefined) tag.description = parsed.description ?? null\n await em.flush()\n return { tagId: tag.id }\n },\n buildLog: async ({ input, result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = result?.tagId ? await em.findOne(ResourcesResourceTag, { id: result.tagId }) : null\n return {\n actionLabel: translate('resources.audit.resourceTags.update', 'Update resource tag'),\n resourceKind: 'resources.resourceTag',\n resourceId: result?.tagId ?? input?.id ?? null,\n tenantId: tag?.tenantId ?? ctx.auth?.tenantId ?? null,\n organizationId: tag?.organizationId ?? ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nconst deleteTagCommand: CommandHandler<{ id?: string }, { tagId: string }> = {\n id: 'resources.resourceTags.delete',\n async execute(input, ctx) {\n const id = typeof input?.id === 'string' ? input.id : null\n if (!id) throw new CrudHttpError(400, { error: 'Tag id is required' })\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tag = await em.findOne(ResourcesResourceTag, { id })\n if (!tag) throw new CrudHttpError(404, { error: 'Tag not found' })\n ensureTenantScope(ctx, tag.tenantId)\n ensureOrganizationScope(ctx, tag.organizationId)\n await withAtomicFlush(em, [\n async () => {\n await em.nativeDelete(ResourcesResourceTagAssignment, { tag: tag.id })\n em.remove(tag)\n },\n ], { transaction: true })\n return { tagId: id }\n },\n buildLog: async ({ input, result, ctx }) => {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('resources.audit.resourceTags.delete', 'Delete resource tag'),\n resourceKind: 'resources.resourceTag',\n resourceId: result?.tagId ?? input?.id ?? null,\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n },\n}\n\nregisterCommand(createTagCommand)\nregisterCommand(updateTagCommand)\nregisterCommand(deleteTagCommand)\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -118,17 +118,19 @@ async function POST(req) {
118
118
  const validUntil = new Date(now);
119
119
  validUntil.setUTCDate(validUntil.getUTCDate() + input.validForDays);
120
120
  const rawAcceptanceToken = crypto.randomUUID();
121
- quote.validUntil = validUntil;
122
- quote.acceptanceToken = hashAuthToken(rawAcceptanceToken);
123
- quote.sentAt = now;
124
- quote.status = "sent";
125
- quote.statusEntryId = await resolveStatusEntryIdByValue(em, {
126
- tenantId: quote.tenantId,
127
- organizationId: quote.organizationId,
128
- value: "sent"
121
+ await em.transactional(async (tx) => {
122
+ quote.validUntil = validUntil;
123
+ quote.acceptanceToken = hashAuthToken(rawAcceptanceToken);
124
+ quote.sentAt = now;
125
+ quote.status = "sent";
126
+ quote.statusEntryId = await resolveStatusEntryIdByValue(tx, {
127
+ tenantId: quote.tenantId,
128
+ organizationId: quote.organizationId,
129
+ value: "sent"
130
+ });
131
+ quote.updatedAt = now;
132
+ tx.persist(quote);
129
133
  });
130
- quote.updatedAt = now;
131
- em.persist(quote);
132
134
  const appUrl = process.env.APP_URL || "";
133
135
  const url = appUrl ? `${appUrl.replace(/\/$/, "")}/quote/${rawAcceptanceToken}` : `/quote/${rawAcceptanceToken}`;
134
136
  const locale = await detectLocale();
@@ -153,7 +155,6 @@ async function POST(req) {
153
155
  subject: translate("sales.quotes.email.subject", "Quote {quoteNumber}", { quoteNumber: quote.quoteNumber }),
154
156
  react: QuoteSentEmail({ url, copy })
155
157
  });
156
- await em.flush();
157
158
  if (guardResult.afterSuccessCallbacks.length) {
158
159
  await runGuardAfterSuccessCallbacks(guardResult.afterSuccessCallbacks, {
159
160
  tenantId: ctx.auth?.tenantId ?? "",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/sales/api/quotes/send/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { resolveTranslations, detectLocale } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n bridgeLegacyGuard,\n runMutationGuards,\n type MutationGuard,\n type MutationGuardInput,\n} from '@open-mercato/shared/lib/crud/mutation-guard-registry'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport crypto from 'node:crypto'\nimport { withScopedPayload } from '../../utils'\nimport { hashAuthToken } from '../../../../auth/lib/tokenHash'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { SalesQuote } from '../../../data/entities'\nimport { quoteSendSchema } from '../../../data/validators'\nimport { sendEmail } from '@open-mercato/shared/lib/email/send'\nimport { resolveStatusEntryIdByValue } from '../../../lib/statusHelpers'\nimport { QuoteSentEmail } from '../../../emails/QuoteSentEmail'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['sales.quotes.manage'] },\n}\n\ntype RequestContext = {\n ctx: CommandRuntimeContext\n}\n\nfunction resolveUserFeatures(auth: unknown): string[] {\n const features = (auth as { features?: unknown })?.features\n if (!Array.isArray(features)) return []\n return features.filter((value): value is string => typeof value === 'string')\n}\n\nasync function runGuards(\n ctx: CommandRuntimeContext,\n input: MutationGuardInput,\n): Promise<{\n ok: boolean\n errorBody?: Record<string, unknown>\n errorStatus?: number\n afterSuccessCallbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>\n}> {\n const legacyGuard = bridgeLegacyGuard(ctx.container)\n if (!legacyGuard) {\n return { ok: true, afterSuccessCallbacks: [] }\n }\n\n return runMutationGuards([legacyGuard], input, {\n userFeatures: resolveUserFeatures(ctx.auth),\n })\n}\n\nasync function runGuardAfterSuccessCallbacks(\n callbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>,\n input: {\n tenantId: string\n organizationId: string | null\n userId: string\n resourceKind: string\n resourceId: string\n operation: 'create' | 'update' | 'delete'\n requestMethod: string\n requestHeaders: Headers\n },\n): Promise<void> {\n for (const callback of callbacks) {\n if (!callback.guard.afterSuccess) continue\n await callback.guard.afterSuccess({\n ...input,\n metadata: callback.metadata ?? null,\n })\n }\n}\n\nasync function resolveRequestContext(req: Request): Promise<RequestContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.documents.errors.unauthorized', 'Unauthorized') })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, {\n error: translate('sales.documents.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n return { ctx }\n}\n\nfunction resolveQuoteEmail(quote: SalesQuote): string | null {\n const snapshot = quote.customerSnapshot && typeof quote.customerSnapshot === 'object' ? (quote.customerSnapshot as Record<string, unknown>) : null\n const metadata = quote.metadata && typeof quote.metadata === 'object' ? (quote.metadata as Record<string, unknown>) : null\n const contact = snapshot?.contact as Record<string, unknown> | undefined\n const customer = snapshot?.customer as Record<string, unknown> | undefined\n const candidate =\n (typeof contact?.email === 'string' && contact.email.trim()) ||\n (typeof customer?.primaryEmail === 'string' && customer.primaryEmail.trim()) ||\n (typeof metadata?.customerEmail === 'string' && metadata.customerEmail.trim()) ||\n null\n if (!candidate) return null\n const parsed = z.string().email().safeParse(candidate)\n return parsed.success ? parsed.data : null\n}\n\nexport async function POST(req: Request) {\n try {\n const { ctx } = await resolveRequestContext(req)\n const { translate } = await resolveTranslations()\n const payload = await req.json().catch(() => ({}))\n const scoped = withScopedPayload(payload ?? {}, ctx, translate)\n const input = quoteSendSchema.parse(scoped)\n const guardResult = await runGuards(ctx, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, { status: guardResult.errorStatus ?? 422 })\n }\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantScope = ctx.auth?.tenantId ? { tenantId: ctx.auth.tenantId } : undefined\n const quote = await findOneWithDecryption(em, SalesQuote, { id: input.quoteId, deletedAt: null }, {}, tenantScope)\n if (!quote) {\n throw new CrudHttpError(404, { error: translate('sales.documents.detail.error', 'Document not found or inaccessible.') })\n }\n if (quote.tenantId !== ctx.auth?.tenantId || quote.organizationId !== ctx.selectedOrganizationId) {\n throw new CrudHttpError(403, { error: translate('sales.documents.errors.forbidden', 'Forbidden') })\n }\n\n if ((quote.status ?? null) === 'canceled') {\n throw new CrudHttpError(400, { error: translate('sales.quotes.send.canceled', 'Canceled quotes cannot be sent.') })\n }\n\n const email = resolveQuoteEmail(quote)\n if (!email) {\n throw new CrudHttpError(400, { error: translate('sales.quotes.send.missingEmail', 'Customer email is required to send a quote.') })\n }\n\n const now = new Date()\n const validUntil = new Date(now)\n validUntil.setUTCDate(validUntil.getUTCDate() + input.validForDays)\n\n const rawAcceptanceToken = crypto.randomUUID()\n quote.validUntil = validUntil\n quote.acceptanceToken = hashAuthToken(rawAcceptanceToken)\n quote.sentAt = now\n quote.status = 'sent'\n quote.statusEntryId = await resolveStatusEntryIdByValue(em, {\n tenantId: quote.tenantId,\n organizationId: quote.organizationId,\n value: 'sent',\n })\n quote.updatedAt = now\n em.persist(quote)\n\n const appUrl = process.env.APP_URL || ''\n const url = appUrl ? `${appUrl.replace(/\\/$/, '')}/quote/${rawAcceptanceToken}` : `/quote/${rawAcceptanceToken}`\n\n const locale = await detectLocale()\n const validUntilFormatted = validUntil.toLocaleDateString(locale, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n })\n\n const copy = {\n preview: translate('sales.quotes.email.preview', 'Quote {quoteNumber} is ready for review', { quoteNumber: quote.quoteNumber }),\n heading: translate('sales.quotes.email.heading', 'Quote {quoteNumber}', { quoteNumber: quote.quoteNumber }),\n total: translate('sales.quotes.email.total', 'Total: {amount} {currency}', {\n amount: quote.grandTotalGrossAmount ?? quote.grandTotalNetAmount ?? '0',\n currency: quote.currencyCode,\n }),\n validUntil: translate('sales.quotes.email.validUntil', 'Valid until: {date}', { date: validUntilFormatted }),\n cta: translate('sales.quotes.email.cta', 'View quote'),\n footer: translate('sales.quotes.email.footer', 'Open Mercato'),\n }\n\n await sendEmail({\n to: email,\n subject: translate('sales.quotes.email.subject', 'Quote {quoteNumber}', { quoteNumber: quote.quoteNumber }),\n react: QuoteSentEmail({ url, copy }),\n })\n\n await em.flush()\n\n if (guardResult.afterSuccessCallbacks.length) {\n await runGuardAfterSuccessCallbacks(guardResult.afterSuccessCallbacks, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n }\n\n return NextResponse.json({ ok: true })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n console.error('sales.quotes.send failed', err)\n return NextResponse.json(\n { error: translate('sales.quotes.send.failed', 'Failed to send quote.') },\n { status: 400 }\n )\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Send quote to customer',\n methods: {\n POST: {\n summary: 'Send quote',\n requestBody: {\n contentType: 'application/json',\n schema: quoteSendSchema,\n },\n responses: [\n { status: 200, description: 'Email queued', schema: z.object({ ok: z.literal(true) }) },\n { status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Forbidden', schema: z.object({ error: z.string() }) },\n { status: 404, description: 'Not found', schema: z.object({ error: z.string() }) },\n { status: 409, description: 'Conflict detected', schema: z.object({ error: z.string(), code: z.string().optional() }) },\n { status: 423, description: 'Record locked', schema: z.object({ error: z.string(), code: z.string().optional() }) },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { resolveTranslations, detectLocale } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n bridgeLegacyGuard,\n runMutationGuards,\n type MutationGuard,\n type MutationGuardInput,\n} from '@open-mercato/shared/lib/crud/mutation-guard-registry'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport crypto from 'node:crypto'\nimport { withScopedPayload } from '../../utils'\nimport { hashAuthToken } from '../../../../auth/lib/tokenHash'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { SalesQuote } from '../../../data/entities'\nimport { quoteSendSchema } from '../../../data/validators'\nimport { sendEmail } from '@open-mercato/shared/lib/email/send'\nimport { resolveStatusEntryIdByValue } from '../../../lib/statusHelpers'\nimport { QuoteSentEmail } from '../../../emails/QuoteSentEmail'\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['sales.quotes.manage'] },\n}\n\ntype RequestContext = {\n ctx: CommandRuntimeContext\n}\n\nfunction resolveUserFeatures(auth: unknown): string[] {\n const features = (auth as { features?: unknown })?.features\n if (!Array.isArray(features)) return []\n return features.filter((value): value is string => typeof value === 'string')\n}\n\nasync function runGuards(\n ctx: CommandRuntimeContext,\n input: MutationGuardInput,\n): Promise<{\n ok: boolean\n errorBody?: Record<string, unknown>\n errorStatus?: number\n afterSuccessCallbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>\n}> {\n const legacyGuard = bridgeLegacyGuard(ctx.container)\n if (!legacyGuard) {\n return { ok: true, afterSuccessCallbacks: [] }\n }\n\n return runMutationGuards([legacyGuard], input, {\n userFeatures: resolveUserFeatures(ctx.auth),\n })\n}\n\nasync function runGuardAfterSuccessCallbacks(\n callbacks: Array<{ guard: MutationGuard; metadata: Record<string, unknown> | null }>,\n input: {\n tenantId: string\n organizationId: string | null\n userId: string\n resourceKind: string\n resourceId: string\n operation: 'create' | 'update' | 'delete'\n requestMethod: string\n requestHeaders: Headers\n },\n): Promise<void> {\n for (const callback of callbacks) {\n if (!callback.guard.afterSuccess) continue\n await callback.guard.afterSuccess({\n ...input,\n metadata: callback.metadata ?? null,\n })\n }\n}\n\nasync function resolveRequestContext(req: Request): Promise<RequestContext> {\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, { error: translate('sales.documents.errors.unauthorized', 'Unauthorized') })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const organizationId = scope?.selectedId ?? auth.orgId ?? null\n if (!organizationId) {\n throw new CrudHttpError(400, {\n error: translate('sales.documents.errors.organization_required', 'Organization context is required'),\n })\n }\n\n const ctx: CommandRuntimeContext = {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: organizationId,\n organizationIds: scope?.filterIds ?? (auth.orgId ? [auth.orgId] : null),\n request: req,\n }\n\n return { ctx }\n}\n\nfunction resolveQuoteEmail(quote: SalesQuote): string | null {\n const snapshot = quote.customerSnapshot && typeof quote.customerSnapshot === 'object' ? (quote.customerSnapshot as Record<string, unknown>) : null\n const metadata = quote.metadata && typeof quote.metadata === 'object' ? (quote.metadata as Record<string, unknown>) : null\n const contact = snapshot?.contact as Record<string, unknown> | undefined\n const customer = snapshot?.customer as Record<string, unknown> | undefined\n const candidate =\n (typeof contact?.email === 'string' && contact.email.trim()) ||\n (typeof customer?.primaryEmail === 'string' && customer.primaryEmail.trim()) ||\n (typeof metadata?.customerEmail === 'string' && metadata.customerEmail.trim()) ||\n null\n if (!candidate) return null\n const parsed = z.string().email().safeParse(candidate)\n return parsed.success ? parsed.data : null\n}\n\nexport async function POST(req: Request) {\n try {\n const { ctx } = await resolveRequestContext(req)\n const { translate } = await resolveTranslations()\n const payload = await req.json().catch(() => ({}))\n const scoped = withScopedPayload(payload ?? {}, ctx, translate)\n const input = quoteSendSchema.parse(scoped)\n const guardResult = await runGuards(ctx, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n if (!guardResult.ok) {\n return NextResponse.json(guardResult.errorBody ?? { error: 'Operation blocked by guard' }, { status: guardResult.errorStatus ?? 422 })\n }\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantScope = ctx.auth?.tenantId ? { tenantId: ctx.auth.tenantId } : undefined\n const quote = await findOneWithDecryption(em, SalesQuote, { id: input.quoteId, deletedAt: null }, {}, tenantScope)\n if (!quote) {\n throw new CrudHttpError(404, { error: translate('sales.documents.detail.error', 'Document not found or inaccessible.') })\n }\n if (quote.tenantId !== ctx.auth?.tenantId || quote.organizationId !== ctx.selectedOrganizationId) {\n throw new CrudHttpError(403, { error: translate('sales.documents.errors.forbidden', 'Forbidden') })\n }\n\n if ((quote.status ?? null) === 'canceled') {\n throw new CrudHttpError(400, { error: translate('sales.quotes.send.canceled', 'Canceled quotes cannot be sent.') })\n }\n\n const email = resolveQuoteEmail(quote)\n if (!email) {\n throw new CrudHttpError(400, { error: translate('sales.quotes.send.missingEmail', 'Customer email is required to send a quote.') })\n }\n\n const now = new Date()\n const validUntil = new Date(now)\n validUntil.setUTCDate(validUntil.getUTCDate() + input.validForDays)\n\n const rawAcceptanceToken = crypto.randomUUID()\n\n // Persist the send state (status/token/sentAt) atomically and commit it\n // BEFORE the email goes out, so a customer never receives a link whose\n // acceptance token was not durably stored.\n await em.transactional(async (tx) => {\n quote.validUntil = validUntil\n quote.acceptanceToken = hashAuthToken(rawAcceptanceToken)\n quote.sentAt = now\n quote.status = 'sent'\n quote.statusEntryId = await resolveStatusEntryIdByValue(tx, {\n tenantId: quote.tenantId,\n organizationId: quote.organizationId,\n value: 'sent',\n })\n quote.updatedAt = now\n tx.persist(quote)\n })\n\n const appUrl = process.env.APP_URL || ''\n const url = appUrl ? `${appUrl.replace(/\\/$/, '')}/quote/${rawAcceptanceToken}` : `/quote/${rawAcceptanceToken}`\n\n const locale = await detectLocale()\n const validUntilFormatted = validUntil.toLocaleDateString(locale, {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n })\n\n const copy = {\n preview: translate('sales.quotes.email.preview', 'Quote {quoteNumber} is ready for review', { quoteNumber: quote.quoteNumber }),\n heading: translate('sales.quotes.email.heading', 'Quote {quoteNumber}', { quoteNumber: quote.quoteNumber }),\n total: translate('sales.quotes.email.total', 'Total: {amount} {currency}', {\n amount: quote.grandTotalGrossAmount ?? quote.grandTotalNetAmount ?? '0',\n currency: quote.currencyCode,\n }),\n validUntil: translate('sales.quotes.email.validUntil', 'Valid until: {date}', { date: validUntilFormatted }),\n cta: translate('sales.quotes.email.cta', 'View quote'),\n footer: translate('sales.quotes.email.footer', 'Open Mercato'),\n }\n\n // Side effect after commit: an email failure must not roll back the send state.\n await sendEmail({\n to: email,\n subject: translate('sales.quotes.email.subject', 'Quote {quoteNumber}', { quoteNumber: quote.quoteNumber }),\n react: QuoteSentEmail({ url, copy }),\n })\n\n if (guardResult.afterSuccessCallbacks.length) {\n await runGuardAfterSuccessCallbacks(guardResult.afterSuccessCallbacks, {\n tenantId: ctx.auth?.tenantId ?? '',\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n userId: ctx.auth?.sub ?? '',\n resourceKind: 'sales.quote',\n resourceId: input.quoteId,\n operation: 'update',\n requestMethod: req.method,\n requestHeaders: req.headers,\n })\n }\n\n return NextResponse.json({ ok: true })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n console.error('sales.quotes.send failed', err)\n return NextResponse.json(\n { error: translate('sales.quotes.send.failed', 'Failed to send quote.') },\n { status: 400 }\n )\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Send quote to customer',\n methods: {\n POST: {\n summary: 'Send quote',\n requestBody: {\n contentType: 'application/json',\n schema: quoteSendSchema,\n },\n responses: [\n { status: 200, description: 'Email queued', schema: z.object({ ok: z.literal(true) }) },\n { status: 400, description: 'Invalid payload', schema: z.object({ error: z.string() }) },\n { status: 401, description: 'Unauthorized', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Forbidden', schema: z.object({ error: z.string() }) },\n { status: 404, description: 'Not found', schema: z.object({ error: z.string() }) },\n { status: 409, description: 'Conflict detected', schema: z.object({ error: z.string(), code: z.string().optional() }) },\n { status: 423, description: 'Record locked', schema: z.object({ error: z.string(), code: z.string().optional() }) },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["metadata"]
7
7
  }