@open-mercato/core 0.6.6-develop.6317.1.b3be10ab84 → 0.6.6-develop.6331.1.a33b8e99b7

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 +1 -1
  2. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +3 -0
  3. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  4. package/dist/modules/auth/api/roles/acl/route.js +2 -2
  5. package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
  6. package/dist/modules/auth/api/users/acl/route.js +2 -2
  7. package/dist/modules/auth/api/users/acl/route.js.map +2 -2
  8. package/dist/modules/auth/backend/roles/[id]/edit/page.js +12 -0
  9. package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
  10. package/dist/modules/auth/backend/users/[id]/edit/page.js +12 -0
  11. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  12. package/dist/modules/auth/data/entities.js +2 -2
  13. package/dist/modules/auth/data/entities.js.map +2 -2
  14. package/dist/modules/business_rules/api/rules/route.js +3 -3
  15. package/dist/modules/business_rules/api/rules/route.js.map +2 -2
  16. package/dist/modules/business_rules/api/sets/route.js +3 -3
  17. package/dist/modules/business_rules/api/sets/route.js.map +2 -2
  18. package/dist/modules/business_rules/backend/rules/[id]/page.js +12 -1
  19. package/dist/modules/business_rules/backend/rules/[id]/page.js.map +2 -2
  20. package/dist/modules/business_rules/backend/sets/[id]/page.js +12 -1
  21. package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
  22. package/dist/modules/catalog/api/product-media/route.js.map +2 -2
  23. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +12 -0
  24. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  25. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
  26. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  27. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +12 -1
  28. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  29. package/dist/modules/catalog/components/PriceKindSettings.js +13 -3
  30. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  31. package/dist/modules/catalog/lib/bulkDelete.js.map +2 -2
  32. package/dist/modules/currencies/backend/currencies/[id]/page.js +15 -3
  33. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  34. package/dist/modules/currencies/backend/currencies/page.js +2 -1
  35. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  36. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +12 -1
  37. package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
  38. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -2
  39. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  40. package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -3
  41. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  42. package/dist/modules/customer_accounts/api/admin/users/[id].js +3 -3
  43. package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
  44. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +7 -12
  45. package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
  46. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +5 -2
  47. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  48. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -1
  49. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
  50. package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js +2 -1
  51. package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js.map +2 -2
  52. package/dist/modules/customers/api/addresses/route.js +4 -2
  53. package/dist/modules/customers/api/addresses/route.js.map +2 -2
  54. package/dist/modules/customers/api/tags/route.js +8 -3
  55. package/dist/modules/customers/api/tags/route.js.map +2 -2
  56. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +13 -2
  57. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  58. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +24 -9
  59. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
  60. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +53 -23
  61. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
  62. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +13 -3
  63. package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +2 -2
  64. package/dist/modules/customers/backend/customers/deals/[id]/page.js +19 -2
  65. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  66. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +13 -2
  67. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  68. package/dist/modules/customers/commands/interactions.js +5 -5
  69. package/dist/modules/customers/commands/interactions.js.map +2 -2
  70. package/dist/modules/customers/commands/pipeline-stages.js +24 -2
  71. package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
  72. package/dist/modules/customers/commands/pipelines.js +24 -2
  73. package/dist/modules/customers/commands/pipelines.js.map +2 -2
  74. package/dist/modules/customers/components/detail/AddressesSection.js +46 -29
  75. package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
  76. package/dist/modules/customers/components/detail/DealForm.js +5 -1
  77. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  78. package/dist/modules/customers/components/detail/EntityTagsDialog.js +76 -67
  79. package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +3 -3
  80. package/dist/modules/customers/components/detail/notesAdapter.js +25 -18
  81. package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
  82. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +4 -3
  83. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  84. package/dist/modules/data_sync/api/runs.js +1 -0
  85. package/dist/modules/data_sync/api/runs.js.map +2 -2
  86. package/dist/modules/data_sync/api/schedules/[id]/route.js +38 -19
  87. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
  88. package/dist/modules/data_sync/api/schedules/route.js +1 -1
  89. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  90. package/dist/modules/data_sync/backend/data-sync/page.js +35 -16
  91. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  92. package/dist/modules/data_sync/data/validators.js +1 -0
  93. package/dist/modules/data_sync/data/validators.js.map +2 -2
  94. package/dist/modules/data_sync/lib/sync-run-service.js +20 -0
  95. package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
  96. package/dist/modules/data_sync/lib/sync-schedule-service.js +19 -5
  97. package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
  98. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +3 -3
  99. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  100. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +3 -3
  101. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  102. package/dist/modules/dictionaries/components/DictionariesManager.js +12 -1
  103. package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
  104. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  105. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +12 -0
  106. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  107. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +12 -0
  108. package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
  109. package/dist/modules/entities/api/entities.js +2 -2
  110. package/dist/modules/entities/api/entities.js.map +2 -2
  111. package/dist/modules/entities/api/records.js +18 -6
  112. package/dist/modules/entities/api/records.js.map +2 -2
  113. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +17 -10
  114. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  115. package/dist/modules/feature_toggles/api/overrides/route.js +2 -2
  116. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  117. package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
  118. package/dist/modules/feature_toggles/data/entities.js +1 -1
  119. package/dist/modules/feature_toggles/data/entities.js.map +2 -2
  120. package/dist/modules/feature_toggles/data/validators.js +2 -1
  121. package/dist/modules/feature_toggles/data/validators.js.map +2 -2
  122. package/dist/modules/feature_toggles/lib/queries.js +2 -1
  123. package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
  124. package/dist/modules/inbox_ops/api/settings/route.js +2 -2
  125. package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
  126. package/dist/modules/messages/api/unread-count/route.js +32 -0
  127. package/dist/modules/messages/api/unread-count/route.js.map +2 -2
  128. package/dist/modules/query_index/components/QueryIndexesTable.js +13 -5
  129. package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
  130. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +12 -1
  131. package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
  132. package/dist/modules/resources/backend/resources/resources/[id]/page.js +12 -1
  133. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  134. package/dist/modules/resources/components/detail/notesAdapter.js +25 -18
  135. package/dist/modules/resources/components/detail/notesAdapter.js.map +2 -2
  136. package/dist/modules/sales/backend/sales/documents/[id]/page.js +14 -1
  137. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  138. package/dist/modules/sales/commands/documents.js +11 -10
  139. package/dist/modules/sales/commands/documents.js.map +2 -2
  140. package/dist/modules/sales/commands/payments.js +6 -1
  141. package/dist/modules/sales/commands/payments.js.map +2 -2
  142. package/dist/modules/sales/commands/returns.js +3 -3
  143. package/dist/modules/sales/commands/returns.js.map +2 -2
  144. package/dist/modules/sales/commands/shared.js +3 -3
  145. package/dist/modules/sales/commands/shared.js.map +2 -2
  146. package/dist/modules/sales/commands/shipments.js +6 -1
  147. package/dist/modules/sales/commands/shipments.js.map +2 -2
  148. package/dist/modules/sales/components/documents/PaymentDialog.js +6 -3
  149. package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
  150. package/dist/modules/sales/components/documents/PaymentsSection.js +7 -3
  151. package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
  152. package/dist/modules/sales/components/documents/ShipmentDialog.js +6 -3
  153. package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
  154. package/dist/modules/sales/components/documents/ShipmentsSection.js +7 -3
  155. package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
  156. package/dist/modules/sales/di.js +39 -3
  157. package/dist/modules/sales/di.js.map +2 -2
  158. package/dist/modules/sales/setup.js +2 -0
  159. package/dist/modules/sales/setup.js.map +2 -2
  160. package/dist/modules/shipping_carriers/i18n/en.js +11 -1
  161. package/dist/modules/shipping_carriers/i18n/en.js.map +2 -2
  162. package/dist/modules/shipping_carriers/i18n/pl.js +11 -1
  163. package/dist/modules/shipping_carriers/i18n/pl.js.map +2 -2
  164. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js +25 -0
  165. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js.map +7 -0
  166. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +3 -17
  167. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +2 -2
  168. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +12 -1
  169. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  170. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +12 -1
  171. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  172. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +12 -1
  173. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  174. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -1
  175. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  176. package/dist/modules/staff/commands/job-histories.js +3 -3
  177. package/dist/modules/staff/commands/job-histories.js.map +2 -2
  178. package/dist/modules/staff/components/detail/addressesAdapter.js +33 -24
  179. package/dist/modules/staff/components/detail/addressesAdapter.js.map +2 -2
  180. package/dist/modules/staff/components/detail/notesAdapter.js +25 -18
  181. package/dist/modules/staff/components/detail/notesAdapter.js.map +2 -2
  182. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +37 -0
  183. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  184. package/dist/modules/translations/components/TranslationManager.js +7 -1
  185. package/dist/modules/translations/components/TranslationManager.js.map +2 -2
  186. package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +19 -14
  187. package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
  188. package/dist/modules/workflows/api/definitions/[id]/route.js +3 -3
  189. package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
  190. package/dist/modules/workflows/backend/definitions/[id]/page.js +12 -1
  191. package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
  192. package/dist/modules/workflows/backend/definitions/visual-editor/page.js +11 -1
  193. package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
  194. package/package.json +7 -7
  195. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +3 -0
  196. package/src/modules/auth/api/roles/acl/route.ts +2 -2
  197. package/src/modules/auth/api/users/acl/route.ts +2 -2
  198. package/src/modules/auth/backend/roles/[id]/edit/page.tsx +17 -0
  199. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -0
  200. package/src/modules/auth/data/entities.ts +2 -2
  201. package/src/modules/business_rules/api/rules/route.ts +3 -3
  202. package/src/modules/business_rules/api/sets/route.ts +3 -3
  203. package/src/modules/business_rules/backend/rules/[id]/page.tsx +17 -1
  204. package/src/modules/business_rules/backend/sets/[id]/page.tsx +18 -1
  205. package/src/modules/catalog/api/product-media/route.ts +4 -0
  206. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +17 -0
  207. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +21 -0
  208. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +16 -1
  209. package/src/modules/catalog/components/PriceKindSettings.tsx +15 -7
  210. package/src/modules/catalog/lib/bulkDelete.ts +6 -0
  211. package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -3
  212. package/src/modules/currencies/backend/currencies/page.tsx +2 -1
  213. package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +17 -1
  214. package/src/modules/currencies/backend/exchange-rates/page.tsx +3 -2
  215. package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -3
  216. package/src/modules/customer_accounts/api/admin/users/[id].ts +3 -3
  217. package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +7 -10
  218. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +6 -7
  219. package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +3 -2
  220. package/src/modules/customer_accounts/widgets/injection/company-users/widget.client.tsx +3 -2
  221. package/src/modules/customers/api/addresses/route.ts +2 -0
  222. package/src/modules/customers/api/tags/route.ts +6 -1
  223. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +19 -2
  224. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +29 -8
  225. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +47 -20
  226. package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +13 -3
  227. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +21 -1
  228. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -2
  229. package/src/modules/customers/commands/interactions.ts +5 -5
  230. package/src/modules/customers/commands/pipeline-stages.ts +26 -2
  231. package/src/modules/customers/commands/pipelines.ts +26 -2
  232. package/src/modules/customers/components/detail/AddressesSection.tsx +50 -28
  233. package/src/modules/customers/components/detail/DealForm.tsx +12 -0
  234. package/src/modules/customers/components/detail/EntityTagsDialog.tsx +89 -71
  235. package/src/modules/customers/components/detail/notesAdapter.ts +29 -18
  236. package/src/modules/customers/i18n/de.json +2 -0
  237. package/src/modules/customers/i18n/en.json +2 -0
  238. package/src/modules/customers/i18n/es.json +2 -0
  239. package/src/modules/customers/i18n/pl.json +2 -0
  240. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +6 -3
  241. package/src/modules/data_sync/api/runs.ts +1 -0
  242. package/src/modules/data_sync/api/schedules/[id]/route.ts +38 -20
  243. package/src/modules/data_sync/api/schedules/route.ts +1 -1
  244. package/src/modules/data_sync/backend/data-sync/page.tsx +35 -16
  245. package/src/modules/data_sync/data/validators.ts +1 -0
  246. package/src/modules/data_sync/i18n/de.json +1 -0
  247. package/src/modules/data_sync/i18n/en.json +1 -0
  248. package/src/modules/data_sync/i18n/es.json +1 -0
  249. package/src/modules/data_sync/i18n/pl.json +1 -0
  250. package/src/modules/data_sync/lib/sync-run-service.ts +23 -0
  251. package/src/modules/data_sync/lib/sync-schedule-service.ts +30 -5
  252. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +3 -3
  253. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +3 -3
  254. package/src/modules/dictionaries/components/DictionariesManager.tsx +21 -1
  255. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +2 -0
  256. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +17 -0
  257. package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +17 -0
  258. package/src/modules/entities/api/entities.ts +2 -2
  259. package/src/modules/entities/api/records.ts +24 -6
  260. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +25 -12
  261. package/src/modules/feature_toggles/api/overrides/route.ts +2 -2
  262. package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +12 -0
  263. package/src/modules/feature_toggles/data/entities.ts +1 -1
  264. package/src/modules/feature_toggles/data/validators.ts +1 -0
  265. package/src/modules/feature_toggles/lib/queries.ts +1 -0
  266. package/src/modules/inbox_ops/api/settings/route.ts +2 -2
  267. package/src/modules/messages/api/unread-count/route.ts +40 -0
  268. package/src/modules/query_index/components/QueryIndexesTable.tsx +17 -15
  269. package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +17 -1
  270. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +17 -1
  271. package/src/modules/resources/components/detail/notesAdapter.ts +29 -18
  272. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +17 -1
  273. package/src/modules/sales/commands/documents.ts +11 -10
  274. package/src/modules/sales/commands/payments.ts +11 -0
  275. package/src/modules/sales/commands/returns.ts +3 -3
  276. package/src/modules/sales/commands/shared.ts +10 -4
  277. package/src/modules/sales/commands/shipments.ts +14 -0
  278. package/src/modules/sales/components/documents/PaymentDialog.tsx +7 -3
  279. package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -3
  280. package/src/modules/sales/components/documents/ShipmentDialog.tsx +7 -3
  281. package/src/modules/sales/components/documents/ShipmentsSection.tsx +8 -3
  282. package/src/modules/sales/di.ts +68 -9
  283. package/src/modules/sales/setup.ts +2 -0
  284. package/src/modules/shipping_carriers/i18n/de.json +11 -1
  285. package/src/modules/shipping_carriers/i18n/en.json +11 -1
  286. package/src/modules/shipping_carriers/i18n/en.ts +10 -0
  287. package/src/modules/shipping_carriers/i18n/es.json +11 -1
  288. package/src/modules/shipping_carriers/i18n/pl.json +11 -1
  289. package/src/modules/shipping_carriers/i18n/pl.ts +10 -0
  290. package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.tsx +35 -0
  291. package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +3 -22
  292. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +17 -1
  293. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +17 -1
  294. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +17 -1
  295. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -1
  296. package/src/modules/staff/commands/job-histories.ts +3 -3
  297. package/src/modules/staff/components/detail/addressesAdapter.ts +40 -23
  298. package/src/modules/staff/components/detail/notesAdapter.ts +28 -18
  299. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +74 -0
  300. package/src/modules/translations/components/TranslationManager.tsx +14 -1
  301. package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +30 -13
  302. package/src/modules/workflows/api/definitions/[id]/route.ts +3 -3
  303. package/src/modules/workflows/backend/definitions/[id]/page.tsx +18 -1
  304. package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +19 -1
@@ -1,7 +1,9 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from 'react'
4
- import { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
4
+ import { apiCall, apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
5
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
6
+ import { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'
5
7
  import { AddressesSection as SharedAddressesSection } from '@open-mercato/ui/backend/detail'
6
8
  import type { AddressDataAdapter, AddressTypesAdapter, AddressFormatStrategy, SectionAction } from '@open-mercato/ui/backend/detail'
7
9
  import { createTranslatorWithFallback } from '@open-mercato/shared/lib/i18n/translate'
@@ -99,6 +101,12 @@ export function AddressesSection({
99
101
  : typeof record.isPrimary === 'boolean'
100
102
  ? record.isPrimary
101
103
  : false,
104
+ updatedAt:
105
+ typeof record.updated_at === 'string'
106
+ ? record.updated_at
107
+ : typeof record.updatedAt === 'string'
108
+ ? record.updatedAt
109
+ : null,
102
110
  }
103
111
  })
104
112
  .filter((value): value is NonNullable<typeof value> => value !== null)
@@ -107,7 +115,7 @@ export function AddressesSection({
107
115
  const response = await apiCallOrThrow<Record<string, unknown>>(
108
116
  '/api/customers/addresses',
109
117
  {
110
- // optimistic-lock-exempt: address link add/remove sub-resource
118
+ // optimistic-lock-exempt: address create-only (no prior version to compare)
111
119
  method: 'POST',
112
120
  headers: { 'content-type': 'application/json' },
113
121
  body: JSON.stringify({
@@ -120,33 +128,47 @@ export function AddressesSection({
120
128
  )
121
129
  return response.result ?? {}
122
130
  },
123
- update: async ({ id, payload }) => {
124
- await apiCallOrThrow(
125
- '/api/customers/addresses',
126
- {
127
- // optimistic-lock-exempt: address link add/remove sub-resource
128
- method: 'PUT',
129
- headers: { 'content-type': 'application/json' },
130
- body: JSON.stringify({
131
- id,
132
- ...payload,
133
- country: payload.country ? payload.country.toUpperCase() : undefined,
134
- }),
135
- },
136
- { errorMessage: t('customers.people.detail.addresses.error') },
137
- )
131
+ update: async ({ id, payload, updatedAt }) => {
132
+ try {
133
+ await withScopedApiRequestHeaders(
134
+ buildOptimisticLockHeader(updatedAt ?? null),
135
+ () => apiCallOrThrow(
136
+ '/api/customers/addresses',
137
+ {
138
+ method: 'PUT',
139
+ headers: { 'content-type': 'application/json' },
140
+ body: JSON.stringify({
141
+ id,
142
+ ...payload,
143
+ country: payload.country ? payload.country.toUpperCase() : undefined,
144
+ }),
145
+ },
146
+ { errorMessage: t('customers.people.detail.addresses.error') },
147
+ ),
148
+ )
149
+ } catch (err) {
150
+ surfaceRecordConflict(err, t)
151
+ throw err
152
+ }
138
153
  },
139
- delete: async ({ id }) => {
140
- await apiCallOrThrow(
141
- '/api/customers/addresses',
142
- {
143
- // optimistic-lock-exempt: address link add/remove sub-resource
144
- method: 'DELETE',
145
- headers: { 'content-type': 'application/json' },
146
- body: JSON.stringify({ id }),
147
- },
148
- { errorMessage: t('customers.people.detail.addresses.error') },
149
- )
154
+ delete: async ({ id, updatedAt }) => {
155
+ try {
156
+ await withScopedApiRequestHeaders(
157
+ buildOptimisticLockHeader(updatedAt ?? null),
158
+ () => apiCallOrThrow(
159
+ '/api/customers/addresses',
160
+ {
161
+ method: 'DELETE',
162
+ headers: { 'content-type': 'application/json' },
163
+ body: JSON.stringify({ id }),
164
+ },
165
+ { errorMessage: t('customers.people.detail.addresses.error') },
166
+ ),
167
+ )
168
+ } catch (err) {
169
+ surfaceRecordConflict(err, t)
170
+ throw err
171
+ }
150
172
  },
151
173
  }), [t])
152
174
 
@@ -69,6 +69,14 @@ export type DealFormProps = {
69
69
  showCancelAction?: boolean
70
70
  initialPipelineOptions?: PipelineOption[]
71
71
  initialPipelineStageOptions?: PipelineStageOption[]
72
+ /**
73
+ * Injection spot id for the form-scoped record_locks widget (e.g.
74
+ * `customers.deal`). Mirrors how people-v2/companies-v2 mount their save-time
75
+ * `crud-form:*` widget so a deal save conflict surfaces the merge dialog.
76
+ */
77
+ injectionSpotId?: string
78
+ /** Optimistic-lock version (`deal.updatedAt`) for the embedded CrudForm. */
79
+ optimisticLockUpdatedAt?: string | null
72
80
  }
73
81
 
74
82
  type EntityOption = {
@@ -732,6 +740,8 @@ export function DealForm({
732
740
  showCancelAction = true,
733
741
  initialPipelineOptions,
734
742
  initialPipelineStageOptions,
743
+ injectionSpotId,
744
+ optimisticLockUpdatedAt,
735
745
  }: DealFormProps) {
736
746
  const t = useT()
737
747
  const [pending, setPending] = React.useState(false)
@@ -1168,6 +1178,8 @@ export function DealForm({
1168
1178
  backHref={backHref}
1169
1179
  hideFooterActions={hideFooterActions}
1170
1180
  onDirtyChange={onDirtyChange}
1181
+ injectionSpotId={injectionSpotId}
1182
+ optimisticLockUpdatedAt={optimisticLockUpdatedAt}
1171
1183
  collapsibleGroups={collapsibleGroups}
1172
1184
  sortableGroups={sortableGroups}
1173
1185
  versionHistory={showVersionHistory && mode === 'edit' && initialValues?.id
@@ -438,53 +438,49 @@ export function EntityTagsDialog({
438
438
  const loadData = React.useCallback(async () => {
439
439
  setLoading(true)
440
440
  try {
441
- let kindSettings: KindSetting[] = []
442
441
  const scopedQuery = new URLSearchParams()
443
442
  if (entityOrganizationId) {
444
443
  scopedQuery.set('organizationId', entityOrganizationId)
445
444
  }
446
- try {
447
- const settingsCall = await apiCall<{ items?: KindSetting[] }>(
448
- `/api/customers/dictionaries/kind-settings${scopedQuery.size ? `?${scopedQuery.toString()}` : ''}`,
449
- { cache: 'no-store', headers: { 'x-om-unauthorized-redirect': '0' } },
450
- )
451
- if (settingsCall.ok && settingsCall.result?.items) {
452
- kindSettings = settingsCall.result.items
445
+
446
+ const loadKindSettings = async (): Promise<KindSetting[]> => {
447
+ try {
448
+ const settingsCall = await apiCall<{ items?: KindSetting[] }>(
449
+ `/api/customers/dictionaries/kind-settings${scopedQuery.size ? `?${scopedQuery.toString()}` : ''}`,
450
+ { cache: 'no-store', headers: { 'x-om-unauthorized-redirect': '0' } },
451
+ )
452
+ if (settingsCall.ok && settingsCall.result?.items) {
453
+ return settingsCall.result.items
454
+ }
455
+ } catch {
456
+ // Default category order works without explicit settings rows.
453
457
  }
454
- } catch {
455
- // Default category order works without explicit settings rows.
458
+ return []
456
459
  }
457
460
 
458
- const settingsMap = new Map(kindSettings.map((setting) => [setting.kind, setting]))
459
-
460
- const selectedTagEntries = Array.isArray(entityData.tags)
461
- ? entityData.tags.map((tag) => ({
462
- id: tag.id,
463
- value: tag.id,
464
- label: tag.label,
465
- color: tag.color ?? null,
466
- }))
467
- : []
468
-
469
- let assignedLabelIds: string[] = []
470
- let selectedLabelEntries: CategoryOption[] = []
471
- try {
472
- const labelsQuery = new URLSearchParams()
473
- labelsQuery.set('entityId', entityId)
474
- labelsQuery.set('pageSize', '1')
475
- if (entityOrganizationId) {
476
- labelsQuery.set('organizationId', entityOrganizationId)
477
- }
478
- const labelsCall = await apiCall<{
479
- items?: LabelItem[]
480
- assignedIds?: string[]
481
- }>(`/api/customers/labels?${labelsQuery.toString()}`, {
482
- cache: 'no-store',
483
- headers: { 'x-om-unauthorized-redirect': '0' },
484
- })
485
- const labelsData = labelsCall.ok ? labelsCall.result : null
486
- assignedLabelIds = labelsData?.assignedIds ?? []
487
- if (assignedLabelIds.length > 0) {
461
+ const loadLabelData = async (): Promise<{
462
+ assignedLabelIds: string[]
463
+ selectedLabelEntries: CategoryOption[]
464
+ }> => {
465
+ try {
466
+ const labelsQuery = new URLSearchParams()
467
+ labelsQuery.set('entityId', entityId)
468
+ labelsQuery.set('pageSize', '1')
469
+ if (entityOrganizationId) {
470
+ labelsQuery.set('organizationId', entityOrganizationId)
471
+ }
472
+ const labelsCall = await apiCall<{
473
+ items?: LabelItem[]
474
+ assignedIds?: string[]
475
+ }>(`/api/customers/labels?${labelsQuery.toString()}`, {
476
+ cache: 'no-store',
477
+ headers: { 'x-om-unauthorized-redirect': '0' },
478
+ })
479
+ const labelsData = labelsCall.ok ? labelsCall.result : null
480
+ const assignedLabelIds = labelsData?.assignedIds ?? []
481
+ if (assignedLabelIds.length === 0) {
482
+ return { assignedLabelIds, selectedLabelEntries: [] }
483
+ }
488
484
  const detailQuery = new URLSearchParams({
489
485
  ids: assignedLabelIds.join(','),
490
486
  pageSize: String(Math.min(assignedLabelIds.length, 100)),
@@ -500,44 +496,36 @@ export function EntityTagsDialog({
500
496
  },
501
497
  )
502
498
  const selectedLabels = selectedLabelsCall.ok ? selectedLabelsCall.result?.items ?? [] : []
503
- selectedLabelEntries = selectedLabels.map((label) => ({
499
+ const selectedLabelEntries = selectedLabels.map((label) => ({
504
500
  id: label.id,
505
501
  value: label.id,
506
502
  label: label.label,
507
503
  color: null,
508
504
  }))
505
+ return { assignedLabelIds, selectedLabelEntries }
506
+ } catch {
507
+ return { assignedLabelIds: [], selectedLabelEntries: [] }
509
508
  }
510
- } catch {
511
- assignedLabelIds = []
512
- selectedLabelEntries = []
513
509
  }
514
510
 
515
- const categoryDefs = buildApplicableCategories(entityType, kindSettings)
516
- const loadedCategories: CategorySection[] = []
511
+ const selectedTagEntries = Array.isArray(entityData.tags)
512
+ ? entityData.tags.map((tag) => ({
513
+ id: tag.id,
514
+ value: tag.id,
515
+ label: tag.label,
516
+ color: tag.color ?? null,
517
+ }))
518
+ : []
517
519
 
518
- for (const categoryDef of categoryDefs) {
519
- if (categoryDef.source === 'tags') {
520
- loadedCategories.push({
521
- ...categoryDef,
522
- label: t(categoryDef.labelKey, categoryDef.labelFallback),
523
- description: t(categoryDef.descriptionKey, categoryDef.descriptionFallback),
524
- entries: sortOptions(selectedTagEntries),
525
- selectionMode: categoryDef.selectionMode ?? 'multi',
526
- })
527
- continue
528
- }
520
+ // The label chain is independent of kind settings and the dictionary
521
+ // fan-out, so kick it off immediately and let it resolve in parallel.
522
+ const labelDataPromise = loadLabelData()
529
523
 
530
- if (categoryDef.source === 'labels') {
531
- loadedCategories.push({
532
- ...categoryDef,
533
- label: t(categoryDef.labelKey, categoryDef.labelFallback),
534
- description: t(categoryDef.descriptionKey, categoryDef.descriptionFallback),
535
- entries: sortOptions(selectedLabelEntries),
536
- selectionMode: categoryDef.selectionMode ?? 'multi',
537
- })
538
- continue
539
- }
524
+ const kindSettings = await loadKindSettings()
525
+ const settingsMap = new Map(kindSettings.map((setting) => [setting.kind, setting]))
526
+ const categoryDefs = buildApplicableCategories(entityType, kindSettings)
540
527
 
528
+ const loadDictionaryCategory = async (categoryDef: CategoryDef): Promise<CategorySection> => {
541
529
  try {
542
530
  const dictionaryUrl = new URL(`/api/customers/dictionaries/${categoryDef.routeKind}`, 'http://localhost')
543
531
  if (entityOrganizationId) {
@@ -568,7 +556,7 @@ export function EntityTagsDialog({
568
556
  color: null,
569
557
  })
570
558
  })
571
- loadedCategories.push({
559
+ return {
572
560
  ...categoryDef,
573
561
  label: categoryDef.labelKey
574
562
  ? t(categoryDef.labelKey, categoryDef.labelFallback)
@@ -582,7 +570,7 @@ export function EntityTagsDialog({
582
570
  : categoryDef.descriptionFallback,
583
571
  entries: sortOptions(entries),
584
572
  selectionMode,
585
- })
573
+ }
586
574
  } catch {
587
575
  const setting = categoryDef.settingKind
588
576
  ? settingsMap.get(categoryDef.settingKind)
@@ -594,7 +582,7 @@ export function EntityTagsDialog({
594
582
  label: value,
595
583
  color: null,
596
584
  }))
597
- loadedCategories.push({
585
+ return {
598
586
  ...categoryDef,
599
587
  label: categoryDef.labelKey
600
588
  ? t(categoryDef.labelKey, categoryDef.labelFallback)
@@ -608,10 +596,40 @@ export function EntityTagsDialog({
608
596
  : categoryDef.descriptionFallback,
609
597
  entries: fallbackEntries,
610
598
  selectionMode,
611
- })
599
+ }
612
600
  }
613
601
  }
614
602
 
603
+ // Independent dictionary requests fan out together instead of awaiting
604
+ // each one sequentially; Promise.all preserves categoryDefs order so the
605
+ // subsequent sort and selection initialization stay stable.
606
+ const loadedCategories = await Promise.all(
607
+ categoryDefs.map(async (categoryDef): Promise<CategorySection> => {
608
+ if (categoryDef.source === 'tags') {
609
+ return {
610
+ ...categoryDef,
611
+ label: t(categoryDef.labelKey, categoryDef.labelFallback),
612
+ description: t(categoryDef.descriptionKey, categoryDef.descriptionFallback),
613
+ entries: sortOptions(selectedTagEntries),
614
+ selectionMode: categoryDef.selectionMode ?? 'multi',
615
+ }
616
+ }
617
+ if (categoryDef.source === 'labels') {
618
+ const { selectedLabelEntries } = await labelDataPromise
619
+ return {
620
+ ...categoryDef,
621
+ label: t(categoryDef.labelKey, categoryDef.labelFallback),
622
+ description: t(categoryDef.descriptionKey, categoryDef.descriptionFallback),
623
+ entries: sortOptions(selectedLabelEntries),
624
+ selectionMode: categoryDef.selectionMode ?? 'multi',
625
+ }
626
+ }
627
+ return loadDictionaryCategory(categoryDef)
628
+ }),
629
+ )
630
+
631
+ const { assignedLabelIds, selectedLabelEntries } = await labelDataPromise
632
+
615
633
  loadedCategories.sort((left, right) => {
616
634
  const leftSortOrder =
617
635
  left.settingKind && settingsMap.has(left.settingKind)
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
 
3
- import { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
3
+ import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'
4
+ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'
4
5
  import { mapCommentSummary, type NotesDataAdapter } from '@open-mercato/ui/backend/detail/NotesSection'
5
6
 
6
7
  type Translator = (key: string, fallback?: string, params?: Record<string, string | number>) => string
@@ -92,33 +93,43 @@ export function createCustomerNotesAdapter(
92
93
  )
93
94
  return response.result ?? {}
94
95
  },
95
- update: async ({ id, patch }) => {
96
+ update: async ({ id, patch, updatedAt }) => {
96
97
  const payload: Record<string, unknown> = { id }
97
98
  if (patch.body !== undefined) payload.body = patch.body
98
99
  if (patch.appearanceIcon !== undefined) payload.appearanceIcon = patch.appearanceIcon
99
100
  if (patch.appearanceColor !== undefined) payload.appearanceColor = patch.appearanceColor
101
+ // Send the optimistic-lock header (note's loaded updatedAt) so a stale edit —
102
+ // or an edit after the note was deleted in another tab — surfaces the unified
103
+ // conflict bar (409) instead of silently overwriting. The guarded runner
104
+ // (useGuardedMutation) routes the 409 through surfaceRecordConflict.
100
105
  await runWrite(
101
- () => apiCallOrThrow(
102
- '/api/customers/comments',
103
- {
104
- method: 'PUT',
105
- headers: { 'content-type': 'application/json' },
106
- body: JSON.stringify(payload),
107
- },
108
- { errorMessage: translator('customers.people.detail.notes.updateError') },
106
+ () => withScopedApiRequestHeaders(
107
+ buildOptimisticLockHeader(updatedAt ?? null),
108
+ () => apiCallOrThrow(
109
+ '/api/customers/comments',
110
+ {
111
+ method: 'PUT',
112
+ headers: { 'content-type': 'application/json' },
113
+ body: JSON.stringify(payload),
114
+ },
115
+ { errorMessage: translator('customers.people.detail.notes.updateError') },
116
+ ),
109
117
  ),
110
118
  { operation: 'updateNote', id },
111
119
  )
112
120
  },
113
- delete: async ({ id }) => {
121
+ delete: async ({ id, updatedAt }) => {
114
122
  await runWrite(
115
- () => apiCallOrThrow(
116
- `/api/customers/comments?id=${encodeURIComponent(id)}`,
117
- {
118
- method: 'DELETE',
119
- headers: { 'content-type': 'application/json' },
120
- },
121
- { errorMessage: translator('customers.people.detail.notes.deleteError', 'Failed to delete note') },
123
+ () => withScopedApiRequestHeaders(
124
+ buildOptimisticLockHeader(updatedAt ?? null),
125
+ () => apiCallOrThrow(
126
+ `/api/customers/comments?id=${encodeURIComponent(id)}`,
127
+ {
128
+ method: 'DELETE',
129
+ headers: { 'content-type': 'application/json' },
130
+ },
131
+ { errorMessage: translator('customers.people.detail.notes.deleteError', 'Failed to delete note') },
132
+ ),
122
133
  ),
123
134
  { operation: 'deleteNote', id },
124
135
  )
@@ -923,6 +923,8 @@
923
923
  "customers.deals.detail.badge.deal": "Deal",
924
924
  "customers.deals.detail.badge.lost": "Lost",
925
925
  "customers.deals.detail.badge.won": "Won",
926
+ "customers.deals.detail.closeLostError": "Deal konnte nicht als verloren markiert werden.",
927
+ "customers.deals.detail.closeWonError": "Deal konnte nicht als gewonnen markiert werden.",
926
928
  "customers.deals.detail.closure.lost": "Lost",
927
929
  "customers.deals.detail.closure.prompt": "Close deal — choose outcome",
928
930
  "customers.deals.detail.closure.won": "Won",
@@ -923,6 +923,8 @@
923
923
  "customers.deals.detail.badge.deal": "Deal",
924
924
  "customers.deals.detail.badge.lost": "Lost",
925
925
  "customers.deals.detail.badge.won": "Won",
926
+ "customers.deals.detail.closeLostError": "Failed to mark deal as lost.",
927
+ "customers.deals.detail.closeWonError": "Failed to mark deal as won.",
926
928
  "customers.deals.detail.closure.lost": "Lost",
927
929
  "customers.deals.detail.closure.prompt": "Close deal — choose outcome",
928
930
  "customers.deals.detail.closure.won": "Won",
@@ -923,6 +923,8 @@
923
923
  "customers.deals.detail.badge.deal": "Deal",
924
924
  "customers.deals.detail.badge.lost": "Lost",
925
925
  "customers.deals.detail.badge.won": "Won",
926
+ "customers.deals.detail.closeLostError": "No se pudo marcar el deal como perdido.",
927
+ "customers.deals.detail.closeWonError": "No se pudo marcar el deal como ganado.",
926
928
  "customers.deals.detail.closure.lost": "Lost",
927
929
  "customers.deals.detail.closure.prompt": "Close deal — choose outcome",
928
930
  "customers.deals.detail.closure.won": "Won",
@@ -923,6 +923,8 @@
923
923
  "customers.deals.detail.badge.deal": "Deal",
924
924
  "customers.deals.detail.badge.lost": "Lost",
925
925
  "customers.deals.detail.badge.won": "Won",
926
+ "customers.deals.detail.closeLostError": "Nie udało się oznaczyć deala jako przegranego.",
927
+ "customers.deals.detail.closeWonError": "Nie udało się oznaczyć deala jako wygranego.",
926
928
  "customers.deals.detail.closure.lost": "Lost",
927
929
  "customers.deals.detail.closure.prompt": "Close deal — choose outcome",
928
930
  "customers.deals.detail.closure.won": "Won",
@@ -193,9 +193,12 @@ export const WidgetVisibilityEditor = React.forwardRef<WidgetVisibilityEditorHan
193
193
  setLoading(true)
194
194
  setError(null)
195
195
  try {
196
- await loadCatalog()
197
- if (kind === 'role') await loadRoleData(tenantIdRef.current, organizationIdRef.current)
198
- else await loadUserData(tenantIdRef.current, organizationIdRef.current)
196
+ await Promise.all([
197
+ loadCatalog(),
198
+ kind === 'role'
199
+ ? loadRoleData(tenantIdRef.current, organizationIdRef.current)
200
+ : loadUserData(tenantIdRef.current, organizationIdRef.current),
201
+ ])
199
202
  } catch (err) {
200
203
  console.error('Failed to load widget visibility data', err)
201
204
  if (!cancelled) {
@@ -25,6 +25,7 @@ export async function GET(req: Request) {
25
25
  entityType: url.searchParams.get('entityType') ?? undefined,
26
26
  direction: url.searchParams.get('direction') ?? undefined,
27
27
  status: url.searchParams.get('status') ?? undefined,
28
+ search: url.searchParams.get('search') ?? undefined,
28
29
  page: url.searchParams.get('page') ?? undefined,
29
30
  pageSize: url.searchParams.get('pageSize') ?? undefined,
30
31
  })
@@ -3,6 +3,8 @@ import { z } from 'zod'
3
3
  import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
4
4
  import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
5
5
  import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
6
+ import { readOptimisticLockExpected } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
7
+ import { isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'
6
8
  import { updateSyncScheduleSchema } from '../../../data/validators'
7
9
  import type { SyncScheduleService } from '../../../lib/sync-schedule-service'
8
10
  import { serializeSchedule } from '../serialize'
@@ -111,7 +113,8 @@ export async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }>
111
113
  timezone: parsed.data.timezone ?? current.timezone,
112
114
  fullSync: parsed.data.fullSync ?? current.fullSync,
113
115
  isEnabled: parsed.data.isEnabled ?? current.isEnabled,
114
- }, scope)
116
+ expectedUpdatedAt: readOptimisticLockExpected(req),
117
+ }, scope, container)
115
118
 
116
119
  if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {
117
120
  await runCrudMutationGuardAfterSuccess(container, {
@@ -126,9 +129,11 @@ export async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }>
126
129
  metadata: guardResult.metadata ?? null,
127
130
  })
128
131
  }
129
-
130
132
  return NextResponse.json(serializeSchedule(schedule))
131
133
  } catch (error) {
134
+ if (isCrudHttpError(error)) {
135
+ return NextResponse.json(error.body, { status: error.status })
136
+ }
132
137
  const message = error instanceof Error ? error.message : 'Failed to update sync schedule'
133
138
  return NextResponse.json({ error: message }, { status: 422 })
134
139
  }
@@ -168,25 +173,38 @@ export async function DELETE(req: Request, ctx: { params?: Promise<{ id?: string
168
173
  return NextResponse.json(guardResult.body, { status: guardResult.status })
169
174
  }
170
175
 
171
- const deleted = await scheduleService.deleteSchedule(parsedParams.data.id, scope)
176
+ try {
177
+ const deleted = await scheduleService.deleteSchedule(
178
+ parsedParams.data.id,
179
+ scope,
180
+ container,
181
+ readOptimisticLockExpected(req),
182
+ )
183
+
184
+ if (!deleted) {
185
+ return NextResponse.json({ error: 'Schedule not found' }, { status: 404 })
186
+ }
172
187
 
173
- if (!deleted) {
174
- return NextResponse.json({ error: 'Schedule not found' }, { status: 404 })
175
- }
188
+ if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {
189
+ await runCrudMutationGuardAfterSuccess(container, {
190
+ tenantId: auth.tenantId,
191
+ organizationId: scope.organizationId,
192
+ userId: auth.sub,
193
+ resourceKind: 'data_sync.schedule',
194
+ resourceId: parsedParams.data.id,
195
+ operation: 'delete',
196
+ requestMethod: req.method,
197
+ requestHeaders: req.headers,
198
+ metadata: guardResult.metadata ?? null,
199
+ })
200
+ }
176
201
 
177
- if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {
178
- await runCrudMutationGuardAfterSuccess(container, {
179
- tenantId: auth.tenantId,
180
- organizationId: scope.organizationId,
181
- userId: auth.sub,
182
- resourceKind: 'data_sync.schedule',
183
- resourceId: parsedParams.data.id,
184
- operation: 'delete',
185
- requestMethod: req.method,
186
- requestHeaders: req.headers,
187
- metadata: guardResult.metadata ?? null,
188
- })
202
+ return NextResponse.json({ deleted: true })
203
+ } catch (error) {
204
+ if (isCrudHttpError(error)) {
205
+ return NextResponse.json(error.body, { status: error.status })
206
+ }
207
+ const message = error instanceof Error ? error.message : 'Failed to delete sync schedule'
208
+ return NextResponse.json({ error: message }, { status: 422 })
189
209
  }
190
-
191
- return NextResponse.json({ deleted: true })
192
210
  }
@@ -90,7 +90,7 @@ export async function POST(req: Request) {
90
90
  const schedule = await scheduleService.saveSchedule({
91
91
  ...parsed.data,
92
92
  expectedUpdatedAt: readOptimisticLockExpected(req),
93
- }, scope)
93
+ }, scope, container)
94
94
 
95
95
  if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {
96
96
  await runCrudMutationGuardAfterSuccess(container, {