@open-mercato/core 0.6.6-develop.6551.1.1511bfa890 → 0.6.6

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 (304) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities.ids.generated.js +0 -1
  3. package/dist/generated/entities.ids.generated.js.map +2 -2
  4. package/dist/generated/entity-fields-registry.js +0 -12
  5. package/dist/generated/entity-fields-registry.js.map +2 -2
  6. package/dist/modules/api_keys/api/keys/route.js +13 -30
  7. package/dist/modules/api_keys/api/keys/route.js.map +2 -2
  8. package/dist/modules/api_keys/cli.js +1 -2
  9. package/dist/modules/api_keys/cli.js.map +2 -2
  10. package/dist/modules/attachments/api/file/[id]/route.js +7 -9
  11. package/dist/modules/attachments/api/file/[id]/route.js.map +2 -2
  12. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +7 -9
  13. package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
  14. package/dist/modules/attachments/api/route.js +17 -21
  15. package/dist/modules/attachments/api/route.js.map +2 -2
  16. package/dist/modules/attachments/components/AttachmentContentPreview.js +35 -6
  17. package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
  18. package/dist/modules/audit_logs/backend/audit-logs/page.js +24 -14
  19. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  20. package/dist/modules/auth/api/users/route.js +2 -6
  21. package/dist/modules/auth/api/users/route.js.map +2 -2
  22. package/dist/modules/auth/cli.js +2 -3
  23. package/dist/modules/auth/cli.js.map +2 -2
  24. package/dist/modules/configs/lib/upgrade-actions.js +0 -22
  25. package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
  26. package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +0 -1
  27. package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +2 -2
  28. package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -17
  29. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  30. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +1 -6
  31. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
  32. package/dist/modules/customer_accounts/api/portal/users-invite.js +1 -6
  33. package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
  34. package/dist/modules/customer_accounts/services/customerInvitationService.js +0 -1
  35. package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
  36. package/dist/modules/customer_accounts/services/customerRbacService.js +1 -6
  37. package/dist/modules/customer_accounts/services/customerRbacService.js.map +2 -2
  38. package/dist/modules/customer_accounts/widgets/injection-table.js +2 -0
  39. package/dist/modules/customer_accounts/widgets/injection-table.js.map +2 -2
  40. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +1 -7
  41. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  42. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js +2 -2
  43. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js.map +2 -2
  44. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +43 -37
  45. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
  46. package/dist/modules/customers/components/detail/DealDetailTabs.js +35 -23
  47. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
  48. package/dist/modules/customers/components/detail/DetailTabsLayout.js +21 -6
  49. package/dist/modules/customers/components/detail/DetailTabsLayout.js.map +2 -2
  50. package/dist/modules/customers/components/detail/MobilePersonDetail.js +32 -26
  51. package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +2 -2
  52. package/dist/modules/customers/components/detail/PersonDetailTabs.js +39 -29
  53. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  54. package/dist/modules/dashboards/api/roles/widgets/route.js +3 -22
  55. package/dist/modules/dashboards/api/roles/widgets/route.js.map +2 -2
  56. package/dist/modules/dashboards/api/users/widgets/route.js +3 -22
  57. package/dist/modules/dashboards/api/users/widgets/route.js.map +2 -2
  58. package/dist/modules/dashboards/cli.js +3 -4
  59. package/dist/modules/dashboards/cli.js.map +2 -2
  60. package/dist/modules/dashboards/lib/widgetAssignmentScope.js +1 -9
  61. package/dist/modules/dashboards/lib/widgetAssignmentScope.js.map +2 -2
  62. package/dist/modules/dictionaries/commands/entries.js +14 -7
  63. package/dist/modules/dictionaries/commands/entries.js.map +2 -2
  64. package/dist/modules/dictionaries/commands/entry-operations.js +16 -7
  65. package/dist/modules/dictionaries/commands/entry-operations.js.map +2 -2
  66. package/dist/modules/dictionaries/commands/factory.js +3 -9
  67. package/dist/modules/dictionaries/commands/factory.js.map +2 -2
  68. package/dist/modules/dictionaries/fields/dictionary.js +41 -56
  69. package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
  70. package/dist/modules/directory/utils/organizationScope.js +3 -10
  71. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  72. package/dist/modules/entities/api/records.js +4 -5
  73. package/dist/modules/entities/api/records.js.map +2 -2
  74. package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js +0 -1
  75. package/dist/modules/entities/backend/entities/system/[entityId]/page.meta.js.map +2 -2
  76. package/dist/modules/entities/backend/entities/user/[entityId]/page.js +49 -49
  77. package/dist/modules/entities/backend/entities/user/[entityId]/page.js.map +2 -2
  78. package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js +0 -1
  79. package/dist/modules/entities/backend/entities/user/[entityId]/page.meta.js.map +2 -2
  80. package/dist/modules/entities/cli.js +1 -2
  81. package/dist/modules/entities/cli.js.map +2 -2
  82. package/dist/modules/feature_toggles/api/check/boolean/route.js +14 -0
  83. package/dist/modules/feature_toggles/api/check/boolean/route.js.map +2 -2
  84. package/dist/modules/feature_toggles/defaults.json +0 -8
  85. package/dist/modules/integrations/backend/integrations/[id]/page.js +80 -9
  86. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  87. package/dist/modules/payment_gateways/data/entities.js +0 -45
  88. package/dist/modules/payment_gateways/data/entities.js.map +2 -2
  89. package/dist/modules/payment_gateways/lib/gateway-service.js +38 -173
  90. package/dist/modules/payment_gateways/lib/gateway-service.js.map +3 -3
  91. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +14 -16
  92. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +2 -2
  93. package/dist/modules/planner/components/AvailabilityRulesEditor.js +30 -18
  94. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  95. package/dist/modules/query_index/api/status.js +8 -2
  96. package/dist/modules/query_index/api/status.js.map +2 -2
  97. package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -24
  98. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  99. package/dist/modules/sales/backend/sales/channels/create/page.js +0 -6
  100. package/dist/modules/sales/backend/sales/channels/create/page.js.map +2 -2
  101. package/dist/modules/sales/backend/sales/channels/create/page.meta.js +0 -2
  102. package/dist/modules/sales/backend/sales/channels/create/page.meta.js.map +2 -2
  103. package/dist/modules/sales/backend/sales/channels/offers/page.js +0 -6
  104. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  105. package/dist/modules/sales/backend/sales/channels/offers/page.meta.js +0 -2
  106. package/dist/modules/sales/backend/sales/channels/offers/page.meta.js.map +2 -2
  107. package/dist/modules/sales/backend/sales/channels/page.js +0 -6
  108. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  109. package/dist/modules/sales/backend/sales/channels/page.meta.js +0 -2
  110. package/dist/modules/sales/backend/sales/channels/page.meta.js.map +2 -2
  111. package/dist/modules/sales/backend/sales/documents/[id]/page.js +4 -6
  112. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  113. package/dist/modules/sales/commands/documents.js +0 -44
  114. package/dist/modules/sales/commands/documents.js.map +2 -2
  115. package/dist/modules/sales/commands/returns.js +27 -2
  116. package/dist/modules/sales/commands/returns.js.map +2 -2
  117. package/dist/modules/sales/components/documents/AddressesSection.js +2 -6
  118. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  119. package/dist/modules/sales/components/documents/ItemsSection.js +0 -1
  120. package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
  121. package/dist/modules/sales/components/documents/LineItemDialog.js +0 -9
  122. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  123. package/dist/modules/sales/components/documents/SalesDocumentForm.js +3 -51
  124. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  125. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +8 -10
  126. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  127. package/dist/modules/sales/components/documents/ShipmentDialog.js +38 -59
  128. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  129. package/dist/modules/sales/lib/shipments/snapshots.js +1 -27
  130. package/dist/modules/sales/lib/shipments/snapshots.js.map +2 -2
  131. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +25 -22
  132. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  133. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -12
  134. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  135. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +29 -10
  136. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +2 -2
  137. package/dist/modules/sync_excel/lib/adapters/customers.js +20 -19
  138. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  139. package/dist/modules/sync_excel/lib/parser.js +0 -185
  140. package/dist/modules/sync_excel/lib/parser.js.map +2 -2
  141. package/dist/modules/sync_excel/lib/upload-storage.js +1 -20
  142. package/dist/modules/sync_excel/lib/upload-storage.js.map +2 -2
  143. package/dist/modules/workflows/frontend/checkout-demo/page.js +8 -1
  144. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  145. package/dist/modules/workflows/lib/activity-executor.js +1 -1
  146. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  147. package/dist/modules/workflows/lib/find-definition.js +18 -2
  148. package/dist/modules/workflows/lib/find-definition.js.map +2 -2
  149. package/dist/modules/workflows/lib/signal-handler.js +3 -2
  150. package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
  151. package/dist/modules/workflows/lib/step-handler.js +4 -8
  152. package/dist/modules/workflows/lib/step-handler.js.map +2 -2
  153. package/dist/modules/workflows/lib/task-handler.js +3 -5
  154. package/dist/modules/workflows/lib/task-handler.js.map +2 -2
  155. package/dist/modules/workflows/lib/timer-handler.js +2 -1
  156. package/dist/modules/workflows/lib/timer-handler.js.map +2 -2
  157. package/dist/modules/workflows/lib/transition-handler.js +5 -13
  158. package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
  159. package/dist/modules/workflows/lib/workflow-executor.js +11 -9
  160. package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
  161. package/dist/modules/workflows/migrations/Migration20260715120000.js +68 -0
  162. package/dist/modules/workflows/migrations/Migration20260715120000.js.map +7 -0
  163. package/dist/modules/workflows/migrations/Migration20260716120000.js +24 -0
  164. package/dist/modules/workflows/migrations/Migration20260716120000.js.map +7 -0
  165. package/dist/modules/workflows/workflows.js +2 -0
  166. package/dist/modules/workflows/workflows.js.map +2 -2
  167. package/generated/entities.ids.generated.ts +0 -1
  168. package/generated/entity-fields-registry.ts +0 -12
  169. package/package.json +8 -9
  170. package/src/modules/api_keys/api/keys/route.ts +13 -36
  171. package/src/modules/api_keys/cli.ts +3 -2
  172. package/src/modules/attachments/api/file/[id]/route.ts +7 -11
  173. package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +7 -11
  174. package/src/modules/attachments/api/route.ts +21 -26
  175. package/src/modules/attachments/components/AttachmentContentPreview.tsx +44 -9
  176. package/src/modules/audit_logs/backend/audit-logs/page.tsx +22 -12
  177. package/src/modules/auth/api/users/route.ts +2 -11
  178. package/src/modules/auth/cli.ts +2 -3
  179. package/src/modules/configs/i18n/de.json +1 -5
  180. package/src/modules/configs/i18n/en.json +1 -5
  181. package/src/modules/configs/i18n/es.json +1 -5
  182. package/src/modules/configs/i18n/pl.json +1 -5
  183. package/src/modules/configs/lib/upgrade-actions.ts +0 -24
  184. package/src/modules/customer_accounts/AGENTS.md +6 -8
  185. package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +0 -1
  186. package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -17
  187. package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +1 -6
  188. package/src/modules/customer_accounts/api/portal/users-invite.ts +1 -6
  189. package/src/modules/customer_accounts/services/customerInvitationService.ts +0 -1
  190. package/src/modules/customer_accounts/services/customerRbacService.ts +2 -9
  191. package/src/modules/customer_accounts/widgets/injection-table.ts +2 -0
  192. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +1 -11
  193. package/src/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.tsx +2 -6
  194. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +55 -39
  195. package/src/modules/customers/components/detail/DealDetailTabs.tsx +49 -24
  196. package/src/modules/customers/components/detail/DetailTabsLayout.tsx +24 -13
  197. package/src/modules/customers/components/detail/MobilePersonDetail.tsx +31 -25
  198. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +50 -29
  199. package/src/modules/dashboards/api/roles/widgets/route.ts +3 -22
  200. package/src/modules/dashboards/api/users/widgets/route.ts +3 -22
  201. package/src/modules/dashboards/cli.ts +9 -4
  202. package/src/modules/dashboards/lib/widgetAssignmentScope.ts +0 -18
  203. package/src/modules/dictionaries/commands/entries.ts +16 -7
  204. package/src/modules/dictionaries/commands/entry-operations.ts +18 -8
  205. package/src/modules/dictionaries/commands/factory.ts +2 -8
  206. package/src/modules/dictionaries/fields/dictionary.tsx +32 -55
  207. package/src/modules/dictionaries/i18n/de.json +0 -2
  208. package/src/modules/dictionaries/i18n/en.json +0 -2
  209. package/src/modules/dictionaries/i18n/es.json +0 -2
  210. package/src/modules/dictionaries/i18n/pl.json +0 -2
  211. package/src/modules/directory/utils/organizationScope.ts +2 -36
  212. package/src/modules/entities/api/records.ts +7 -5
  213. package/src/modules/entities/backend/entities/system/[entityId]/page.meta.ts +0 -1
  214. package/src/modules/entities/backend/entities/user/[entityId]/page.meta.ts +0 -1
  215. package/src/modules/entities/backend/entities/user/[entityId]/page.tsx +49 -51
  216. package/src/modules/entities/cli.ts +1 -2
  217. package/src/modules/entities/i18n/de.json +0 -34
  218. package/src/modules/entities/i18n/en.json +0 -34
  219. package/src/modules/entities/i18n/es.json +0 -34
  220. package/src/modules/entities/i18n/pl.json +0 -34
  221. package/src/modules/feature_toggles/api/check/boolean/route.ts +15 -0
  222. package/src/modules/feature_toggles/defaults.json +0 -8
  223. package/src/modules/integrations/backend/integrations/[id]/page.tsx +59 -16
  224. package/src/modules/payment_gateways/data/entities.ts +0 -39
  225. package/src/modules/payment_gateways/lib/gateway-service.ts +40 -211
  226. package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +0 -236
  227. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +20 -14
  228. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +34 -16
  229. package/src/modules/query_index/api/status.ts +8 -2
  230. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +37 -27
  231. package/src/modules/sales/backend/sales/channels/create/page.meta.ts +0 -3
  232. package/src/modules/sales/backend/sales/channels/create/page.tsx +0 -7
  233. package/src/modules/sales/backend/sales/channels/offers/page.meta.ts +0 -3
  234. package/src/modules/sales/backend/sales/channels/offers/page.tsx +0 -7
  235. package/src/modules/sales/backend/sales/channels/page.meta.ts +0 -4
  236. package/src/modules/sales/backend/sales/channels/page.tsx +0 -7
  237. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +5 -7
  238. package/src/modules/sales/commands/documents.ts +0 -65
  239. package/src/modules/sales/commands/returns.ts +32 -2
  240. package/src/modules/sales/components/documents/AddressesSection.tsx +2 -6
  241. package/src/modules/sales/components/documents/ItemsSection.tsx +0 -5
  242. package/src/modules/sales/components/documents/LineItemDialog.tsx +0 -10
  243. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +3 -53
  244. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +8 -10
  245. package/src/modules/sales/components/documents/ShipmentDialog.tsx +40 -65
  246. package/src/modules/sales/i18n/de.json +0 -5
  247. package/src/modules/sales/i18n/en.json +0 -5
  248. package/src/modules/sales/i18n/es.json +0 -5
  249. package/src/modules/sales/i18n/pl.json +0 -5
  250. package/src/modules/sales/lib/shipments/snapshots.ts +0 -30
  251. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +34 -25
  252. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -11
  253. package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +28 -11
  254. package/src/modules/sync_excel/lib/adapters/customers.ts +22 -20
  255. package/src/modules/sync_excel/lib/parser.ts +0 -245
  256. package/src/modules/sync_excel/lib/upload-storage.ts +1 -23
  257. package/src/modules/workflows/frontend/checkout-demo/page.tsx +12 -1
  258. package/src/modules/workflows/lib/activity-executor.ts +22 -2
  259. package/src/modules/workflows/lib/find-definition.ts +53 -1
  260. package/src/modules/workflows/lib/signal-handler.ts +5 -4
  261. package/src/modules/workflows/lib/step-handler.ts +4 -8
  262. package/src/modules/workflows/lib/task-handler.ts +2 -4
  263. package/src/modules/workflows/lib/timer-handler.ts +3 -2
  264. package/src/modules/workflows/lib/transition-handler.ts +5 -13
  265. package/src/modules/workflows/lib/workflow-executor.ts +11 -8
  266. package/src/modules/workflows/migrations/Migration20260715120000.ts +114 -0
  267. package/src/modules/workflows/migrations/Migration20260716120000.ts +57 -0
  268. package/src/modules/workflows/workflows.ts +2 -0
  269. package/dist/generated/entities/gateway_session_initialization/index.js +0 -23
  270. package/dist/generated/entities/gateway_session_initialization/index.js.map +0 -7
  271. package/dist/modules/attachments/lib/reconcileOrganization.js +0 -110
  272. package/dist/modules/attachments/lib/reconcileOrganization.js.map +0 -7
  273. package/dist/modules/attachments/lib/requestScope.js +0 -10
  274. package/dist/modules/attachments/lib/requestScope.js.map +0 -7
  275. package/dist/modules/auth/api/autologin.js +0 -85
  276. package/dist/modules/auth/api/autologin.js.map +0 -7
  277. package/dist/modules/auth/lib/autologin.js +0 -19
  278. package/dist/modules/auth/lib/autologin.js.map +0 -7
  279. package/dist/modules/customers/components/detail/useDealsAccess.js +0 -16
  280. package/dist/modules/customers/components/detail/useDealsAccess.js.map +0 -7
  281. package/dist/modules/payment_gateways/lib/session-idempotency.js +0 -104
  282. package/dist/modules/payment_gateways/lib/session-idempotency.js.map +0 -7
  283. package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js +0 -11
  284. package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js.map +0 -7
  285. package/dist/modules/sales/components/SalesChannelsDisabledNotice.js +0 -15
  286. package/dist/modules/sales/components/SalesChannelsDisabledNotice.js.map +0 -7
  287. package/dist/modules/sales/components/useSalesChannelsEnabled.js +0 -44
  288. package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +0 -7
  289. package/dist/modules/sales/lib/salesChannelsToggle.js +0 -18
  290. package/dist/modules/sales/lib/salesChannelsToggle.js.map +0 -7
  291. package/dist/modules/sales/lib/salesChannelsToggleId.js +0 -5
  292. package/dist/modules/sales/lib/salesChannelsToggleId.js.map +0 -7
  293. package/generated/entities/gateway_session_initialization/index.ts +0 -10
  294. package/src/modules/attachments/lib/reconcileOrganization.ts +0 -188
  295. package/src/modules/attachments/lib/requestScope.ts +0 -27
  296. package/src/modules/auth/api/autologin.ts +0 -100
  297. package/src/modules/auth/lib/autologin.ts +0 -36
  298. package/src/modules/customers/components/detail/useDealsAccess.ts +0 -19
  299. package/src/modules/payment_gateways/lib/session-idempotency.ts +0 -142
  300. package/src/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.ts +0 -10
  301. package/src/modules/sales/components/SalesChannelsDisabledNotice.tsx +0 -21
  302. package/src/modules/sales/components/useSalesChannelsEnabled.ts +0 -59
  303. package/src/modules/sales/lib/salesChannelsToggle.ts +0 -26
  304. package/src/modules/sales/lib/salesChannelsToggleId.ts +0 -1
@@ -2,8 +2,9 @@
2
2
 
3
3
  import * as React from 'react'
4
4
  import { Activity, Building2, History, NotebookPen, Paperclip, Users } from 'lucide-react'
5
+ import { cn } from '@open-mercato/shared/lib/utils'
5
6
  import { useT } from '@open-mercato/shared/lib/i18n/context'
6
- import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
7
+ import { Button } from '@open-mercato/ui/primitives/button'
7
8
 
8
9
  export type DealTabId =
9
10
  | 'activities'
@@ -18,7 +19,7 @@ type TabDef = {
18
19
  id: DealTabId
19
20
  label: string
20
21
  icon?: React.ReactNode
21
- count?: React.ReactNode
22
+ badge?: React.ReactNode
22
23
  }
23
24
 
24
25
  type DealDetailTabsProps = {
@@ -37,9 +38,21 @@ export function resolveLegacyTab(tab: string | null | undefined): DealTabId {
37
38
  return SUPPORTED_TAB_IDS.has(tab as DealTabId) ? (tab as DealTabId) : 'activities'
38
39
  }
39
40
 
40
- function formatTabCount(count: number): string | number | undefined {
41
- if (count <= 0) return undefined
42
- return count > 999 ? '999+' : count
41
+ function CountBadge({ count }: { count: number }) {
42
+ if (count <= 0) return null
43
+ return (
44
+ <span className="ml-1.5 rounded-sm bg-muted px-1.5 py-px text-xs font-semibold leading-none text-muted-foreground">
45
+ {count > 999 ? '999+' : count}
46
+ </span>
47
+ )
48
+ }
49
+
50
+ function NewBadge() {
51
+ return (
52
+ <span className="ml-1.5 rounded-sm bg-muted px-1.5 py-px text-xs font-semibold leading-none text-muted-foreground">
53
+ NEW
54
+ </span>
55
+ )
43
56
  }
44
57
 
45
58
  export function DealDetailTabs({
@@ -63,13 +76,13 @@ export function DealDetailTabs({
63
76
  id: 'people',
64
77
  label: t('customers.deals.detail.tabs.people', 'People'),
65
78
  icon: <Users className="size-4" />,
66
- count: formatTabCount(peopleCount),
79
+ badge: <CountBadge count={peopleCount} />,
67
80
  },
68
81
  {
69
82
  id: 'companies',
70
83
  label: t('customers.deals.detail.tabs.companies', 'Companies'),
71
84
  icon: <Building2 className="size-4" />,
72
- count: formatTabCount(companiesCount),
85
+ badge: <CountBadge count={companiesCount} />,
73
86
  },
74
87
  {
75
88
  id: 'notes',
@@ -85,7 +98,7 @@ export function DealDetailTabs({
85
98
  id: 'changelog',
86
99
  label: t('customers.deals.detail.tabs.changelog', 'Changelog'),
87
100
  icon: <History className="size-4" />,
88
- count: 'NEW',
101
+ badge: <NewBadge />,
89
102
  },
90
103
  ],
91
104
  [companiesCount, peopleCount, t],
@@ -104,22 +117,34 @@ export function DealDetailTabs({
104
117
 
105
118
  return (
106
119
  <div>
107
- <Tabs
108
- value={activeTab}
109
- onValueChange={(value) => onTabChange(value as DealTabId)}
110
- variant="underline"
111
- >
112
- <TabsList
113
- aria-label={t('customers.deals.detail.tabs.label', 'Deal detail sections')}
114
- className="w-full overflow-x-auto"
115
- >
116
- {allTabs.map((tab) => (
117
- <TabsTrigger key={tab.id} value={tab.id} leading={tab.icon} count={tab.count}>
118
- {tab.label}
119
- </TabsTrigger>
120
- ))}
121
- </TabsList>
122
- </Tabs>
120
+ <div className="border-b border-border" role="tablist" aria-label={t('customers.deals.detail.tabs.label', 'Deal detail sections')}>
121
+ <nav className="-mb-px flex gap-7 overflow-x-auto" role="presentation">
122
+ {allTabs.map((tab) => {
123
+ const isActive = activeTab === tab.id
124
+ return (
125
+ <Button
126
+ key={tab.id}
127
+ type="button"
128
+ variant="ghost"
129
+ size="sm"
130
+ role="tab"
131
+ aria-selected={isActive}
132
+ onClick={() => onTabChange(tab.id)}
133
+ className={cn(
134
+ 'h-auto shrink-0 rounded-none border-b-2 px-3 py-2.5 hover:bg-transparent',
135
+ isActive
136
+ ? 'border-foreground text-foreground font-semibold'
137
+ : 'border-transparent text-muted-foreground hover:text-foreground',
138
+ )}
139
+ >
140
+ {tab.icon ? <span className="mr-1.5">{tab.icon}</span> : null}
141
+ {tab.label}
142
+ {tab.badge}
143
+ </Button>
144
+ )
145
+ })}
146
+ </nav>
147
+ </div>
123
148
 
124
149
  <div className="pt-5" role="tabpanel">
125
150
  {children}
@@ -3,7 +3,6 @@
3
3
  import * as React from 'react'
4
4
  import type { SectionAction } from '@open-mercato/ui/backend/detail'
5
5
  import { Button } from '@open-mercato/ui/primitives/button'
6
- import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
7
6
  import { cn } from '@open-mercato/shared/lib/utils'
8
7
  import { Plus } from 'lucide-react'
9
8
 
@@ -47,19 +46,31 @@ export function DetailTabsLayout<TId extends string = string>({
47
46
  return (
48
47
  <div className={cn('space-y-4', className)}>
49
48
  <div className={cn('flex flex-wrap items-center justify-between gap-3', headerClassName)}>
50
- <Tabs
51
- value={activeTab}
52
- onValueChange={(value) => handleTabChange(value as TId)}
53
- variant="underline"
49
+ <nav
50
+ className={cn('flex flex-wrap items-center gap-3 text-sm', navClassName)}
51
+ role="tablist"
52
+ aria-label={navAriaLabel}
54
53
  >
55
- <TabsList className={cn('h-auto flex-wrap border-b-0', navClassName)} aria-label={navAriaLabel}>
56
- {tabs.map((tab) => (
57
- <TabsTrigger key={tab.id} value={tab.id}>
58
- {tab.label}
59
- </TabsTrigger>
60
- ))}
61
- </TabsList>
62
- </Tabs>
54
+ {tabs.map((tab) => (
55
+ <Button
56
+ key={tab.id}
57
+ type="button"
58
+ variant="ghost"
59
+ size="sm"
60
+ role="tab"
61
+ aria-selected={activeTab === tab.id}
62
+ onClick={() => handleTabChange(tab.id)}
63
+ className={cn(
64
+ 'h-auto rounded-none border-b-2 px-0 py-1',
65
+ activeTab === tab.id
66
+ ? 'border-accent-indigo text-foreground hover:bg-transparent'
67
+ : 'border-transparent text-muted-foreground hover:text-foreground hover:bg-transparent'
68
+ )}
69
+ >
70
+ {tab.label}
71
+ </Button>
72
+ ))}
73
+ </nav>
63
74
  {sectionAction ? (
64
75
  <Button
65
76
  type="button"
@@ -3,7 +3,8 @@
3
3
  import * as React from 'react'
4
4
  import { useRouter, useSearchParams } from 'next/navigation'
5
5
  import { useT } from '@open-mercato/shared/lib/i18n/context'
6
- import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
6
+ import { cn } from '@open-mercato/shared/lib/utils'
7
+ import { Button } from '@open-mercato/ui/primitives/button'
7
8
 
8
9
  export type MobilePersonZone = 'details' | 'activity'
9
10
 
@@ -79,30 +80,35 @@ export function MobilePersonDetail({
79
80
 
80
81
  return (
81
82
  <div className="space-y-4">
82
- <div onKeyDown={handleKeyDown}>
83
- <Tabs
84
- value={zone}
85
- onValueChange={(value) => handleZoneChange(value as MobilePersonZone)}
86
- variant="underline"
87
- >
88
- <TabsList
89
- aria-label={t(
90
- 'customers.people.mobile.zoneSwitcher.ariaLabel',
91
- 'Zone selector',
92
- )}
93
- className="w-full"
94
- >
95
- {ZONES.map((entry) => (
96
- <TabsTrigger
97
- key={entry.id}
98
- value={entry.id}
99
- className="flex-1 justify-center"
100
- >
101
- {t(entry.labelKey, entry.fallback)}
102
- </TabsTrigger>
103
- ))}
104
- </TabsList>
105
- </Tabs>
83
+ <div
84
+ role="tablist"
85
+ aria-label={t(
86
+ 'customers.people.mobile.zoneSwitcher.ariaLabel',
87
+ 'Zone selector',
88
+ )}
89
+ className="grid grid-cols-2 gap-1 rounded-lg border border-border/70 bg-muted/20 p-1"
90
+ onKeyDown={handleKeyDown}
91
+ >
92
+ {ZONES.map((entry) => {
93
+ const isActive = zone === entry.id
94
+ return (
95
+ <Button
96
+ key={entry.id}
97
+ type="button"
98
+ role="tab"
99
+ aria-selected={isActive}
100
+ aria-controls={`mobile-person-zone-${entry.id}`}
101
+ variant={isActive ? 'default' : 'ghost'}
102
+ className={cn(
103
+ 'h-11 rounded-lg text-sm font-semibold',
104
+ isActive ? '' : 'text-muted-foreground',
105
+ )}
106
+ onClick={() => handleZoneChange(entry.id)}
107
+ >
108
+ {t(entry.labelKey, entry.fallback)}
109
+ </Button>
110
+ )
111
+ })}
106
112
  </div>
107
113
  <div
108
114
  id={`mobile-person-zone-${zone}`}
@@ -1,9 +1,9 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
+ import { cn } from '@open-mercato/shared/lib/utils'
4
5
  import { useT } from '@open-mercato/shared/lib/i18n/context'
5
6
  import { Button } from '@open-mercato/ui/primitives/button'
6
- import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
7
7
  import {
8
8
  SquareCheckBig,
9
9
  Mail,
@@ -32,7 +32,7 @@ type TabDef = {
32
32
  id: PersonTabId
33
33
  label: string
34
34
  icon?: React.ReactNode
35
- count?: React.ReactNode
35
+ badge?: React.ReactNode
36
36
  }
37
37
 
38
38
  type PersonDetailTabsProps = {
@@ -56,9 +56,21 @@ export function resolveLegacyTab(tab: string | null | undefined): PersonTabId {
56
56
  return SUPPORTED_TAB_IDS.has(tab as PersonTabId) ? (tab as PersonTabId) : 'activities'
57
57
  }
58
58
 
59
- function formatTabCount(count: number): string | number | undefined {
60
- if (count <= 0) return undefined
61
- return count > 999 ? '999+' : count
59
+ function CountBadge({ count }: { count: number }) {
60
+ if (count <= 0) return null
61
+ return (
62
+ <span className="ml-1 rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium leading-none text-muted-foreground">
63
+ {count > 999 ? '999+' : count}
64
+ </span>
65
+ )
66
+ }
67
+
68
+ function NewBadge() {
69
+ return (
70
+ <span className="ml-1.5 rounded bg-foreground px-1.5 py-0.5 text-overline font-semibold leading-none text-background">
71
+ NEW
72
+ </span>
73
+ )
62
74
  }
63
75
 
64
76
  export function PersonDetailTabs({
@@ -82,7 +94,7 @@ export function PersonDetailTabs({
82
94
  id: 'activities',
83
95
  label: t('customers.people.detail.tabs.activities', 'Activities'),
84
96
  icon: <SquareCheckBig className="size-4" />,
85
- count: formatTabCount(activitiesCount),
97
+ badge: <CountBadge count={activitiesCount} />,
86
98
  },
87
99
  {
88
100
  id: 'emails',
@@ -93,37 +105,37 @@ export function PersonDetailTabs({
93
105
  id: 'deals',
94
106
  label: t('customers.people.detail.tabs.deals', 'Deals'),
95
107
  icon: <Briefcase className="size-4" />,
96
- count: formatTabCount(dealsCount),
108
+ badge: <CountBadge count={dealsCount} />,
97
109
  },
98
110
  {
99
111
  id: 'companies',
100
112
  label: t('customers.people.detail.tabs.companies', 'Companies'),
101
113
  icon: <Building2 className="size-4" />,
102
- count: formatTabCount(companiesCount),
114
+ badge: <CountBadge count={companiesCount} />,
103
115
  },
104
116
  {
105
117
  id: 'addresses',
106
118
  label: t('customers.people.detail.tabs.addresses', 'Addresses'),
107
119
  icon: <MapPin className="size-4" />,
108
- count: formatTabCount(addressesCount),
120
+ badge: <CountBadge count={addressesCount} />,
109
121
  },
110
122
  {
111
123
  id: 'tasks',
112
124
  label: t('customers.people.detail.tabs.tasks', 'Tasks'),
113
125
  icon: <Check className="size-4" />,
114
- count: formatTabCount(tasksCount),
126
+ badge: <CountBadge count={tasksCount} />,
115
127
  },
116
128
  {
117
129
  id: 'changelog',
118
130
  label: t('customers.people.detail.tabs.changelog', 'Change log'),
119
131
  icon: <History className="size-4" />,
120
- count: 'NEW',
132
+ badge: <NewBadge />,
121
133
  },
122
134
  {
123
135
  id: 'files',
124
136
  label: t('customers.people.detail.tabs.files', 'Files'),
125
137
  icon: <Paperclip className="size-4" />,
126
- count: formatTabCount(filesCount),
138
+ badge: <CountBadge count={filesCount} />,
127
139
  },
128
140
  ],
129
141
  [t, activitiesCount, dealsCount, companiesCount, addressesCount, tasksCount, filesCount],
@@ -143,24 +155,33 @@ export function PersonDetailTabs({
143
155
  return (
144
156
  <div>
145
157
  {/* Tab navigation — full width above both zones */}
146
- <div className="flex items-end justify-between gap-2 border-b">
147
- <Tabs
148
- value={activeTab}
149
- onValueChange={(value) => onTabChange(value as PersonTabId)}
150
- variant="underline"
151
- className="min-w-0 flex-1"
152
- >
153
- <TabsList
154
- aria-label={t('customers.people.detail.tabs.label', 'Person detail sections')}
155
- className="-mb-px w-full overflow-x-auto border-b-0 px-1"
156
- >
157
- {allTabs.map((tab) => (
158
- <TabsTrigger key={tab.id} value={tab.id} leading={tab.icon} count={tab.count}>
158
+ <div className="flex items-end justify-between gap-2 border-b" role="tablist" aria-label={t('customers.people.detail.tabs.label', 'Person detail sections')}>
159
+ <nav className="-mb-px flex flex-1 gap-1 overflow-x-auto px-1">
160
+ {allTabs.map((tab) => {
161
+ const isActive = activeTab === tab.id
162
+ return (
163
+ <Button
164
+ key={tab.id}
165
+ type="button"
166
+ variant="ghost"
167
+ size="sm"
168
+ role="tab"
169
+ aria-selected={isActive}
170
+ onClick={() => onTabChange(tab.id)}
171
+ className={cn(
172
+ 'h-auto shrink-0 rounded-none border-b-2 px-3 py-2.5 hover:bg-transparent',
173
+ isActive
174
+ ? 'border-foreground text-foreground font-semibold'
175
+ : 'border-transparent text-muted-foreground hover:text-foreground',
176
+ )}
177
+ >
178
+ {tab.icon && <span className="mr-1.5">{tab.icon}</span>}
159
179
  {tab.label}
160
- </TabsTrigger>
161
- ))}
162
- </TabsList>
163
- </Tabs>
180
+ {tab.badge}
181
+ </Button>
182
+ )
183
+ })}
184
+ </nav>
164
185
  {sectionAction ? (
165
186
  <Button
166
187
  type="button"
@@ -6,10 +6,7 @@ import { DashboardRoleWidgets } from '@open-mercato/core/modules/dashboards/data
6
6
  import { Role } from '@open-mercato/core/modules/auth/data/entities'
7
7
  import { roleWidgetSettingsSchema } from '@open-mercato/core/modules/dashboards/data/validators'
8
8
  import { loadAllWidgets } from '@open-mercato/core/modules/dashboards/lib/widgets'
9
- import {
10
- resolveWidgetAssignmentReadScope,
11
- resolveWidgetAssignmentTargetAccess,
12
- } from '@open-mercato/core/modules/dashboards/lib/widgetAssignmentScope'
9
+ import { resolveWidgetAssignmentReadScope } from '@open-mercato/core/modules/dashboards/lib/widgetAssignmentScope'
13
10
  import { hasFeature } from '@open-mercato/shared/security/features'
14
11
  import {
15
12
  runCrudMutationGuardAfterSuccess,
@@ -73,15 +70,7 @@ export async function GET(req: Request) {
73
70
  })
74
71
 
75
72
  const role = await em.findOne(Role, { id: roleId, deletedAt: null })
76
- const access = resolveWidgetAssignmentTargetAccess({
77
- isSuperAdmin: !!acl.isSuperAdmin,
78
- scopeTenantId: tenantId,
79
- target: role,
80
- })
81
- if (access === 'forbidden') {
82
- return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
83
- }
84
- if (access === 'not-found') {
73
+ if (!role || (tenantId && role.tenantId !== tenantId)) {
85
74
  return NextResponse.json({ error: 'Role not found' }, { status: 404 })
86
75
  }
87
76
 
@@ -132,15 +121,7 @@ export async function PUT(req: Request) {
132
121
  const organizationId = auth.orgId ?? null
133
122
 
134
123
  const role = await em.findOne(Role, { id: parsed.data.roleId, deletedAt: null })
135
- const access = resolveWidgetAssignmentTargetAccess({
136
- isSuperAdmin: !!acl.isSuperAdmin,
137
- scopeTenantId: tenantId,
138
- target: role,
139
- })
140
- if (access === 'forbidden') {
141
- return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
142
- }
143
- if (access === 'not-found') {
124
+ if (!role || (tenantId && role.tenantId !== tenantId)) {
144
125
  return NextResponse.json({ error: 'Role not found' }, { status: 404 })
145
126
  }
146
127
 
@@ -7,10 +7,7 @@ import { User } from '@open-mercato/core/modules/auth/data/entities'
7
7
  import { userWidgetSettingsSchema } from '@open-mercato/core/modules/dashboards/data/validators'
8
8
  import { loadAllWidgets } from '@open-mercato/core/modules/dashboards/lib/widgets'
9
9
  import { resolveAllowedWidgetIds } from '@open-mercato/core/modules/dashboards/lib/access'
10
- import {
11
- resolveWidgetAssignmentReadScope,
12
- resolveWidgetAssignmentTargetAccess,
13
- } from '@open-mercato/core/modules/dashboards/lib/widgetAssignmentScope'
10
+ import { resolveWidgetAssignmentReadScope } from '@open-mercato/core/modules/dashboards/lib/widgetAssignmentScope'
14
11
  import { hasFeature } from '@open-mercato/shared/security/features'
15
12
  import {
16
13
  runCrudMutationGuardAfterSuccess,
@@ -56,15 +53,7 @@ export async function GET(req: Request) {
56
53
  })
57
54
 
58
55
  const targetUserForRead = await em.findOne(User, { id: userId, deletedAt: null })
59
- const readAccess = resolveWidgetAssignmentTargetAccess({
60
- isSuperAdmin: !!acl.isSuperAdmin,
61
- scopeTenantId: tenantId,
62
- target: targetUserForRead,
63
- })
64
- if (readAccess === 'forbidden') {
65
- return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
66
- }
67
- if (readAccess === 'not-found') {
56
+ if (!targetUserForRead || (tenantId && (targetUserForRead.tenantId ?? null) !== tenantId)) {
68
57
  return NextResponse.json({ error: 'User not found' }, { status: 404 })
69
58
  }
70
59
 
@@ -132,15 +121,7 @@ export async function PUT(req: Request) {
132
121
  const organizationId = auth.orgId ?? null
133
122
 
134
123
  const targetUser = await em.findOne(User, { id: parsed.data.userId, deletedAt: null })
135
- const writeAccess = resolveWidgetAssignmentTargetAccess({
136
- isSuperAdmin: !!acl.isSuperAdmin,
137
- scopeTenantId: tenantId,
138
- target: targetUser,
139
- })
140
- if (writeAccess === 'forbidden') {
141
- return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
142
- }
143
- if (writeAccess === 'not-found') {
124
+ if (!targetUser || (tenantId && (targetUser.tenantId ?? null) !== tenantId)) {
144
125
  return NextResponse.json({ error: 'User not found' }, { status: 404 })
145
126
  }
146
127
 
@@ -6,7 +6,6 @@ import { Role } from '@open-mercato/core/modules/auth/data/entities'
6
6
  import { loadAllWidgets } from '@open-mercato/core/modules/dashboards/lib/widgets'
7
7
  import { appendWidgetsToRoles, resolveAnalyticsWidgetIds } from '@open-mercato/core/modules/dashboards/lib/role-widgets'
8
8
  import { seedAnalyticsData } from './seed/analytics'
9
- import { parseCommaSeparatedList } from '@open-mercato/shared/lib/string'
10
9
 
11
10
  type Args = Record<string, string>
12
11
 
@@ -109,7 +108,10 @@ const seedDefaults: ModuleCli = {
109
108
  return
110
109
  }
111
110
 
112
- const roleNames = parseCommaSeparatedList(roleCsv)
111
+ const roleNames = roleCsv
112
+ .split(',')
113
+ .map((name) => name.trim())
114
+ .filter(Boolean)
113
115
 
114
116
  if (!roleNames.length) {
115
117
  console.log('No roles provided, nothing to seed.')
@@ -123,7 +125,7 @@ const seedDefaults: ModuleCli = {
123
125
  tenantId,
124
126
  organizationId,
125
127
  roleNames,
126
- widgetIds: widgetCsv ? parseCommaSeparatedList(widgetCsv) : undefined,
128
+ widgetIds: widgetCsv ? widgetCsv.split(',').map((id) => id.trim()).filter(Boolean) : undefined,
127
129
  logger: (message) => console.log(message),
128
130
  })
129
131
  },
@@ -141,7 +143,10 @@ const enableAnalyticsWidgets: ModuleCli = {
141
143
  return
142
144
  }
143
145
 
144
- const roleNames = parseCommaSeparatedList(roleCsv)
146
+ const roleNames = roleCsv
147
+ .split(',')
148
+ .map((name) => name.trim())
149
+ .filter(Boolean)
145
150
 
146
151
  if (!roleNames.length) {
147
152
  console.log('No roles provided, nothing to update.')
@@ -8,24 +8,6 @@ export type ResolvedAssignmentScope = {
8
8
  organizationId: string | null
9
9
  }
10
10
 
11
- export type WidgetAssignmentTarget = {
12
- tenantId?: string | null
13
- }
14
-
15
- export type WidgetAssignmentTargetAccess = 'allowed' | 'forbidden' | 'not-found'
16
-
17
- export function resolveWidgetAssignmentTargetAccess(params: {
18
- isSuperAdmin: boolean
19
- scopeTenantId: string | null
20
- target: WidgetAssignmentTarget | null | undefined
21
- }): WidgetAssignmentTargetAccess {
22
- const { isSuperAdmin, scopeTenantId, target } = params
23
- if (!isSuperAdmin && !scopeTenantId) return 'forbidden'
24
- if (!target) return 'not-found'
25
- if (scopeTenantId && (target.tenantId ?? null) !== scopeTenantId) return 'not-found'
26
- return 'allowed'
27
- }
28
-
29
11
  export function resolveWidgetAssignmentReadScope(params: {
30
12
  auth: AuthScopeInput
31
13
  isSuperAdmin: boolean
@@ -4,13 +4,22 @@ import {
4
4
  dictionaryEntryCommandCreateSchema,
5
5
  dictionaryEntryCommandUpdateSchema,
6
6
  } from '@open-mercato/core/modules/dictionaries/data/validators'
7
- import {
8
- ensureDictionaryEntryScope,
9
- registerDictionaryEntryCommands,
10
- } from '@open-mercato/core/modules/dictionaries/commands/factory'
7
+ import { registerDictionaryEntryCommands } from '@open-mercato/core/modules/dictionaries/commands/factory'
8
+ import type { CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
11
9
  import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
12
10
  import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
13
11
 
12
+ function ensureScope(ctx: CommandRuntimeContext, scope: { tenantId: string; organizationId: string }): void {
13
+ const tenantId = ctx.auth?.tenantId ?? null
14
+ if (tenantId && tenantId !== scope.tenantId) {
15
+ throw new CrudHttpError(403, { error: 'Forbidden' })
16
+ }
17
+ const organizationId = ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null
18
+ if (organizationId && organizationId !== scope.organizationId) {
19
+ throw new CrudHttpError(403, { error: 'Forbidden' })
20
+ }
21
+ }
22
+
14
23
  async function ensureDictionary(em: EntityManager, id: string): Promise<Dictionary> {
15
24
  const dictionary = await em.findOne(Dictionary, {
16
25
  id,
@@ -28,12 +37,12 @@ registerDictionaryEntryCommands({
28
37
  translationKeyPrefix: 'dictionaries.entries',
29
38
  createSchema: dictionaryEntryCommandCreateSchema,
30
39
  updateSchema: dictionaryEntryCommandUpdateSchema,
31
- ensureScope: ensureDictionaryEntryScope,
40
+ ensureScope,
32
41
  duplicateError: 'An entry with this value already exists.',
33
42
  resolveDictionaryForCreate: async ({ em, ctx, parsed }) => {
34
43
  const dictionary = await ensureDictionary(em, parsed.dictionaryId)
35
44
  const scope = { tenantId: dictionary.tenantId, organizationId: dictionary.organizationId }
36
- ensureDictionaryEntryScope(ctx, scope)
45
+ ensureScope(ctx, scope)
37
46
  return { dictionary, scope }
38
47
  },
39
48
  resolveEntry: async ({ em, ctx, id }) => {
@@ -45,7 +54,7 @@ registerDictionaryEntryCommands({
45
54
  throw new CrudHttpError(404, { error: 'Dictionary not found' })
46
55
  }
47
56
  const scope = { tenantId: entry.tenantId, organizationId: entry.organizationId }
48
- ensureDictionaryEntryScope(ctx, scope)
57
+ ensureScope(ctx, scope)
49
58
  return { entry, dictionary: entry.dictionary, scope }
50
59
  },
51
60
  ensureDictionaryForUndo: async ({ em, snapshot }) => {