@open-mercato/core 0.4.7-develop-0a657b411f → 0.4.7-develop-e249d3e7d0

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 (278) hide show
  1. package/dist/generated/entities/carrier_shipment/index.js +37 -0
  2. package/dist/generated/entities/carrier_shipment/index.js.map +7 -0
  3. package/dist/generated/entities/gateway_transaction/index.js +47 -0
  4. package/dist/generated/entities/gateway_transaction/index.js.map +7 -0
  5. package/dist/generated/entities/webhook_processed_event/index.js +17 -0
  6. package/dist/generated/entities/webhook_processed_event/index.js.map +7 -0
  7. package/dist/generated/entities.ids.generated.js +10 -1
  8. package/dist/generated/entities.ids.generated.js.map +2 -2
  9. package/dist/generated/entity-fields-registry.js +6 -0
  10. package/dist/generated/entity-fields-registry.js.map +2 -2
  11. package/dist/modules/data_sync/api/runs/[id]/cancel.js +14 -5
  12. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
  13. package/dist/modules/data_sync/backend/data-sync/page.meta.js +2 -2
  14. package/dist/modules/data_sync/backend/data-sync/page.meta.js.map +1 -1
  15. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +37 -12
  16. package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
  17. package/dist/modules/directory/api/get/tenants/lookup.js +1 -0
  18. package/dist/modules/directory/api/get/tenants/lookup.js.map +2 -2
  19. package/dist/modules/integrations/api/[id]/route.js +38 -11
  20. package/dist/modules/integrations/api/[id]/route.js.map +2 -2
  21. package/dist/modules/integrations/api/logs/route.js +52 -26
  22. package/dist/modules/integrations/api/logs/route.js.map +2 -2
  23. package/dist/modules/integrations/api/route.js +37 -7
  24. package/dist/modules/integrations/api/route.js.map +2 -2
  25. package/dist/modules/integrations/api/umes-read.js +121 -0
  26. package/dist/modules/integrations/api/umes-read.js.map +7 -0
  27. package/dist/modules/integrations/backend/integrations/[id]/page.js +715 -183
  28. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  29. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +30 -9
  30. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  31. package/dist/modules/integrations/backend/integrations/detail-page-widgets.js +46 -0
  32. package/dist/modules/integrations/backend/integrations/detail-page-widgets.js.map +7 -0
  33. package/dist/modules/integrations/backend/integrations/page.js +78 -62
  34. package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
  35. package/dist/modules/integrations/backend/integrations/page.meta.js +2 -2
  36. package/dist/modules/integrations/backend/integrations/page.meta.js.map +1 -1
  37. package/dist/modules/integrations/setup.js +2 -2
  38. package/dist/modules/integrations/setup.js.map +2 -2
  39. package/dist/modules/payment_gateways/acl.js +12 -0
  40. package/dist/modules/payment_gateways/acl.js.map +7 -0
  41. package/dist/modules/payment_gateways/api/cancel/route.js +55 -0
  42. package/dist/modules/payment_gateways/api/cancel/route.js.map +7 -0
  43. package/dist/modules/payment_gateways/api/capture/route.js +55 -0
  44. package/dist/modules/payment_gateways/api/capture/route.js.map +7 -0
  45. package/dist/modules/payment_gateways/api/interceptors.js +24 -0
  46. package/dist/modules/payment_gateways/api/interceptors.js.map +7 -0
  47. package/dist/modules/payment_gateways/api/openapi.js +5 -0
  48. package/dist/modules/payment_gateways/api/openapi.js.map +7 -0
  49. package/dist/modules/payment_gateways/api/refund/route.js +56 -0
  50. package/dist/modules/payment_gateways/api/refund/route.js.map +7 -0
  51. package/dist/modules/payment_gateways/api/sessions/route.js +74 -0
  52. package/dist/modules/payment_gateways/api/sessions/route.js.map +7 -0
  53. package/dist/modules/payment_gateways/api/status/route.js +66 -0
  54. package/dist/modules/payment_gateways/api/status/route.js.map +7 -0
  55. package/dist/modules/payment_gateways/api/transactions/[id]/route.js +118 -0
  56. package/dist/modules/payment_gateways/api/transactions/[id]/route.js.map +7 -0
  57. package/dist/modules/payment_gateways/api/transactions/route.js +113 -0
  58. package/dist/modules/payment_gateways/api/transactions/route.js.map +7 -0
  59. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +136 -0
  60. package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +7 -0
  61. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +496 -0
  62. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +7 -0
  63. package/dist/modules/payment_gateways/backend/payment-gateways/page.meta.js +23 -0
  64. package/dist/modules/payment_gateways/backend/payment-gateways/page.meta.js.map +7 -0
  65. package/dist/modules/payment_gateways/data/enrichers.js +5 -0
  66. package/dist/modules/payment_gateways/data/enrichers.js.map +7 -0
  67. package/dist/modules/payment_gateways/data/entities.js +131 -0
  68. package/dist/modules/payment_gateways/data/entities.js.map +7 -0
  69. package/dist/modules/payment_gateways/data/validators.js +57 -0
  70. package/dist/modules/payment_gateways/data/validators.js.map +7 -0
  71. package/dist/modules/payment_gateways/di.js +16 -0
  72. package/dist/modules/payment_gateways/di.js.map +7 -0
  73. package/dist/modules/payment_gateways/events.js +21 -0
  74. package/dist/modules/payment_gateways/events.js.map +7 -0
  75. package/dist/modules/payment_gateways/i18n/en.js +6 -0
  76. package/dist/modules/payment_gateways/i18n/en.js.map +7 -0
  77. package/dist/modules/payment_gateways/i18n/pl.js +6 -0
  78. package/dist/modules/payment_gateways/i18n/pl.js.map +7 -0
  79. package/dist/modules/payment_gateways/index.js +9 -0
  80. package/dist/modules/payment_gateways/index.js.map +7 -0
  81. package/dist/modules/payment_gateways/lib/gateway-service.js +378 -0
  82. package/dist/modules/payment_gateways/lib/gateway-service.js.map +7 -0
  83. package/dist/modules/payment_gateways/lib/queue.js +17 -0
  84. package/dist/modules/payment_gateways/lib/queue.js.map +7 -0
  85. package/dist/modules/payment_gateways/lib/status-machine.js +29 -0
  86. package/dist/modules/payment_gateways/lib/status-machine.js.map +7 -0
  87. package/dist/modules/payment_gateways/lib/webhook-processor.js +88 -0
  88. package/dist/modules/payment_gateways/lib/webhook-processor.js.map +7 -0
  89. package/dist/modules/payment_gateways/lib/webhook-utils.js +42 -0
  90. package/dist/modules/payment_gateways/lib/webhook-utils.js.map +7 -0
  91. package/dist/modules/payment_gateways/migrations/Migration20260305122155.js +19 -0
  92. package/dist/modules/payment_gateways/migrations/Migration20260305122155.js.map +7 -0
  93. package/dist/modules/payment_gateways/setup.js +13 -0
  94. package/dist/modules/payment_gateways/setup.js.map +7 -0
  95. package/dist/modules/payment_gateways/widgets/injection-table.js +7 -0
  96. package/dist/modules/payment_gateways/widgets/injection-table.js.map +7 -0
  97. package/dist/modules/payment_gateways/workers/status-poller.js +44 -0
  98. package/dist/modules/payment_gateways/workers/status-poller.js.map +7 -0
  99. package/dist/modules/payment_gateways/workers/webhook-processor.js +20 -0
  100. package/dist/modules/payment_gateways/workers/webhook-processor.js.map +7 -0
  101. package/dist/modules/sales/data/enrichers.js +72 -0
  102. package/dist/modules/sales/data/enrichers.js.map +7 -0
  103. package/dist/modules/sales/lib/makeSalesLineRoute.js +3 -0
  104. package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
  105. package/dist/modules/sales/widgets/injection/payment-gateway-config-field/widget.js +29 -0
  106. package/dist/modules/sales/widgets/injection/payment-gateway-config-field/widget.js.map +7 -0
  107. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +23 -0
  108. package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +7 -0
  109. package/dist/modules/sales/widgets/injection-table.js +13 -1
  110. package/dist/modules/sales/widgets/injection-table.js.map +2 -2
  111. package/dist/modules/shipping_carriers/acl.js +10 -0
  112. package/dist/modules/shipping_carriers/acl.js.map +7 -0
  113. package/dist/modules/shipping_carriers/api/cancel/route.js +55 -0
  114. package/dist/modules/shipping_carriers/api/cancel/route.js.map +7 -0
  115. package/dist/modules/shipping_carriers/api/interceptors.js +21 -0
  116. package/dist/modules/shipping_carriers/api/interceptors.js.map +7 -0
  117. package/dist/modules/shipping_carriers/api/openapi.js +5 -0
  118. package/dist/modules/shipping_carriers/api/openapi.js.map +7 -0
  119. package/dist/modules/shipping_carriers/api/rates/route.js +55 -0
  120. package/dist/modules/shipping_carriers/api/rates/route.js.map +7 -0
  121. package/dist/modules/shipping_carriers/api/shipments/route.js +61 -0
  122. package/dist/modules/shipping_carriers/api/shipments/route.js.map +7 -0
  123. package/dist/modules/shipping_carriers/api/tracking/route.js +58 -0
  124. package/dist/modules/shipping_carriers/api/tracking/route.js.map +7 -0
  125. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +119 -0
  126. package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +7 -0
  127. package/dist/modules/shipping_carriers/data/enrichers.js +82 -0
  128. package/dist/modules/shipping_carriers/data/enrichers.js.map +7 -0
  129. package/dist/modules/shipping_carriers/data/entities.js +80 -0
  130. package/dist/modules/shipping_carriers/data/entities.js.map +7 -0
  131. package/dist/modules/shipping_carriers/data/validators.js +49 -0
  132. package/dist/modules/shipping_carriers/data/validators.js.map +7 -0
  133. package/dist/modules/shipping_carriers/di.js +15 -0
  134. package/dist/modules/shipping_carriers/di.js.map +7 -0
  135. package/dist/modules/shipping_carriers/events.js +19 -0
  136. package/dist/modules/shipping_carriers/events.js.map +7 -0
  137. package/dist/modules/shipping_carriers/i18n/en.js +11 -0
  138. package/dist/modules/shipping_carriers/i18n/en.js.map +7 -0
  139. package/dist/modules/shipping_carriers/i18n/pl.js +11 -0
  140. package/dist/modules/shipping_carriers/i18n/pl.js.map +7 -0
  141. package/dist/modules/shipping_carriers/index.js +9 -0
  142. package/dist/modules/shipping_carriers/index.js.map +7 -0
  143. package/dist/modules/shipping_carriers/lib/adapter-registry.js +29 -0
  144. package/dist/modules/shipping_carriers/lib/adapter-registry.js.map +7 -0
  145. package/dist/modules/shipping_carriers/lib/adapter.js +1 -0
  146. package/dist/modules/shipping_carriers/lib/adapter.js.map +7 -0
  147. package/dist/modules/shipping_carriers/lib/queue.js +17 -0
  148. package/dist/modules/shipping_carriers/lib/queue.js.map +7 -0
  149. package/dist/modules/shipping_carriers/lib/shipping-service.js +155 -0
  150. package/dist/modules/shipping_carriers/lib/shipping-service.js.map +7 -0
  151. package/dist/modules/shipping_carriers/lib/status-sync.js +37 -0
  152. package/dist/modules/shipping_carriers/lib/status-sync.js.map +7 -0
  153. package/dist/modules/shipping_carriers/migrations/Migration20260305170000.js +16 -0
  154. package/dist/modules/shipping_carriers/migrations/Migration20260305170000.js.map +7 -0
  155. package/dist/modules/shipping_carriers/setup.js +13 -0
  156. package/dist/modules/shipping_carriers/setup.js.map +7 -0
  157. package/dist/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.js +25 -0
  158. package/dist/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.js.map +7 -0
  159. package/dist/modules/shipping_carriers/widgets/injection/tracking-column/widget.js +23 -0
  160. package/dist/modules/shipping_carriers/widgets/injection/tracking-column/widget.js.map +7 -0
  161. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +40 -0
  162. package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +7 -0
  163. package/dist/modules/shipping_carriers/widgets/injection-table.js +24 -0
  164. package/dist/modules/shipping_carriers/widgets/injection-table.js.map +7 -0
  165. package/dist/modules/shipping_carriers/workers/status-poller.js +21 -0
  166. package/dist/modules/shipping_carriers/workers/status-poller.js.map +7 -0
  167. package/dist/modules/shipping_carriers/workers/webhook-processor.js +54 -0
  168. package/dist/modules/shipping_carriers/workers/webhook-processor.js.map +7 -0
  169. package/dist/modules/translations/api/get/locales.js +1 -0
  170. package/dist/modules/translations/api/get/locales.js.map +2 -2
  171. package/dist/modules/translations/api/put/locales.js +1 -0
  172. package/dist/modules/translations/api/put/locales.js.map +2 -2
  173. package/generated/entities/carrier_shipment/index.ts +17 -0
  174. package/generated/entities/gateway_transaction/index.ts +22 -0
  175. package/generated/entities/webhook_processed_event/index.ts +7 -0
  176. package/generated/entities.ids.generated.ts +10 -1
  177. package/generated/entity-fields-registry.ts +6 -0
  178. package/jest.config.cjs +1 -0
  179. package/package.json +5 -2
  180. package/src/modules/auth/i18n/de.json +1 -0
  181. package/src/modules/auth/i18n/en.json +1 -0
  182. package/src/modules/auth/i18n/es.json +1 -0
  183. package/src/modules/auth/i18n/pl.json +1 -0
  184. package/src/modules/data_sync/api/runs/[id]/cancel.ts +18 -5
  185. package/src/modules/data_sync/backend/data-sync/page.meta.ts +2 -2
  186. package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +50 -12
  187. package/src/modules/directory/api/get/tenants/lookup.ts +1 -0
  188. package/src/modules/integrations/AGENTS.md +31 -0
  189. package/src/modules/integrations/api/[id]/route.ts +38 -11
  190. package/src/modules/integrations/api/logs/route.ts +53 -27
  191. package/src/modules/integrations/api/route.ts +31 -1
  192. package/src/modules/integrations/api/umes-read.ts +177 -0
  193. package/src/modules/integrations/backend/integrations/[id]/page.tsx +902 -202
  194. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +43 -9
  195. package/src/modules/integrations/backend/integrations/detail-page-widgets.ts +74 -0
  196. package/src/modules/integrations/backend/integrations/page.meta.ts +2 -2
  197. package/src/modules/integrations/backend/integrations/page.tsx +65 -54
  198. package/src/modules/integrations/i18n/de.json +15 -0
  199. package/src/modules/integrations/i18n/en.json +15 -0
  200. package/src/modules/integrations/i18n/es.json +15 -0
  201. package/src/modules/integrations/i18n/pl.json +15 -0
  202. package/src/modules/integrations/setup.ts +2 -2
  203. package/src/modules/payment_gateways/acl.ts +8 -0
  204. package/src/modules/payment_gateways/api/cancel/route.ts +56 -0
  205. package/src/modules/payment_gateways/api/capture/route.ts +56 -0
  206. package/src/modules/payment_gateways/api/interceptors.ts +22 -0
  207. package/src/modules/payment_gateways/api/openapi.ts +1 -0
  208. package/src/modules/payment_gateways/api/refund/route.ts +57 -0
  209. package/src/modules/payment_gateways/api/sessions/route.ts +76 -0
  210. package/src/modules/payment_gateways/api/status/route.ts +69 -0
  211. package/src/modules/payment_gateways/api/transactions/[id]/route.ts +123 -0
  212. package/src/modules/payment_gateways/api/transactions/route.ts +120 -0
  213. package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +161 -0
  214. package/src/modules/payment_gateways/backend/payment-gateways/page.meta.ts +19 -0
  215. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +660 -0
  216. package/src/modules/payment_gateways/data/enrichers.ts +8 -0
  217. package/src/modules/payment_gateways/data/entities.ts +106 -0
  218. package/src/modules/payment_gateways/data/validators.ts +67 -0
  219. package/src/modules/payment_gateways/di.ts +26 -0
  220. package/src/modules/payment_gateways/events.ts +17 -0
  221. package/src/modules/payment_gateways/i18n/de.json +77 -0
  222. package/src/modules/payment_gateways/i18n/en.json +77 -0
  223. package/src/modules/payment_gateways/i18n/en.ts +4 -0
  224. package/src/modules/payment_gateways/i18n/es.json +77 -0
  225. package/src/modules/payment_gateways/i18n/pl.json +77 -0
  226. package/src/modules/payment_gateways/i18n/pl.ts +4 -0
  227. package/src/modules/payment_gateways/index.ts +5 -0
  228. package/src/modules/payment_gateways/lib/gateway-service.ts +486 -0
  229. package/src/modules/payment_gateways/lib/queue.ts +19 -0
  230. package/src/modules/payment_gateways/lib/status-machine.ts +28 -0
  231. package/src/modules/payment_gateways/lib/webhook-processor.ts +133 -0
  232. package/src/modules/payment_gateways/lib/webhook-utils.ts +52 -0
  233. package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +373 -0
  234. package/src/modules/payment_gateways/migrations/Migration20260305122155.ts +20 -0
  235. package/src/modules/payment_gateways/setup.ts +11 -0
  236. package/src/modules/payment_gateways/widgets/injection-table.ts +9 -0
  237. package/src/modules/payment_gateways/workers/status-poller.ts +58 -0
  238. package/src/modules/payment_gateways/workers/webhook-processor.ts +30 -0
  239. package/src/modules/sales/data/enrichers.ts +120 -0
  240. package/src/modules/sales/lib/makeSalesLineRoute.ts +3 -0
  241. package/src/modules/sales/widgets/injection/payment-gateway-config-field/widget.ts +28 -0
  242. package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +22 -0
  243. package/src/modules/sales/widgets/injection-table.ts +12 -0
  244. package/src/modules/shipping_carriers/acl.ts +6 -0
  245. package/src/modules/shipping_carriers/api/cancel/route.ts +53 -0
  246. package/src/modules/shipping_carriers/api/interceptors.ts +19 -0
  247. package/src/modules/shipping_carriers/api/openapi.ts +1 -0
  248. package/src/modules/shipping_carriers/api/rates/route.ts +53 -0
  249. package/src/modules/shipping_carriers/api/shipments/route.ts +59 -0
  250. package/src/modules/shipping_carriers/api/tracking/route.ts +56 -0
  251. package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +134 -0
  252. package/src/modules/shipping_carriers/data/enrichers.ts +89 -0
  253. package/src/modules/shipping_carriers/data/entities.ts +60 -0
  254. package/src/modules/shipping_carriers/data/validators.ts +48 -0
  255. package/src/modules/shipping_carriers/di.ts +20 -0
  256. package/src/modules/shipping_carriers/events.ts +16 -0
  257. package/src/modules/shipping_carriers/i18n/de.json +7 -0
  258. package/src/modules/shipping_carriers/i18n/en.json +7 -0
  259. package/src/modules/shipping_carriers/i18n/en.ts +7 -0
  260. package/src/modules/shipping_carriers/i18n/es.json +7 -0
  261. package/src/modules/shipping_carriers/i18n/pl.json +7 -0
  262. package/src/modules/shipping_carriers/i18n/pl.ts +7 -0
  263. package/src/modules/shipping_carriers/index.ts +5 -0
  264. package/src/modules/shipping_carriers/lib/adapter-registry.ts +33 -0
  265. package/src/modules/shipping_carriers/lib/adapter.ts +93 -0
  266. package/src/modules/shipping_carriers/lib/queue.ts +19 -0
  267. package/src/modules/shipping_carriers/lib/shipping-service.ts +204 -0
  268. package/src/modules/shipping_carriers/lib/status-sync.ts +38 -0
  269. package/src/modules/shipping_carriers/migrations/Migration20260305170000.ts +14 -0
  270. package/src/modules/shipping_carriers/setup.ts +11 -0
  271. package/src/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.ts +24 -0
  272. package/src/modules/shipping_carriers/widgets/injection/tracking-column/widget.ts +22 -0
  273. package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +44 -0
  274. package/src/modules/shipping_carriers/widgets/injection-table.ts +22 -0
  275. package/src/modules/shipping_carriers/workers/status-poller.ts +33 -0
  276. package/src/modules/shipping_carriers/workers/webhook-processor.ts +79 -0
  277. package/src/modules/translations/api/get/locales.ts +1 -0
  278. package/src/modules/translations/api/put/locales.ts +1 -0
@@ -0,0 +1,28 @@
1
+ import type { InjectionFieldWidget } from '@open-mercato/shared/modules/widgets/injection'
2
+
3
+ const widget: InjectionFieldWidget = {
4
+ metadata: {
5
+ id: 'sales.injection.payment-gateway-config-field',
6
+ priority: 40,
7
+ },
8
+ fields: [
9
+ {
10
+ id: 'payment_gateways.captureMethod',
11
+ label: 'payment_gateways.field.captureMethod',
12
+ type: 'select',
13
+ group: 'details',
14
+ options: [
15
+ { value: 'automatic', label: 'payment_gateways.captureMethod.automatic' },
16
+ { value: 'manual', label: 'payment_gateways.captureMethod.manual' },
17
+ ],
18
+ },
19
+ {
20
+ id: 'payment_gateways.paymentTypes',
21
+ label: 'payment_gateways.field.paymentTypes',
22
+ type: 'text',
23
+ group: 'details',
24
+ },
25
+ ],
26
+ }
27
+
28
+ export default widget
@@ -0,0 +1,22 @@
1
+ import type { InjectionColumnWidget } from '@open-mercato/shared/modules/widgets/injection'
2
+
3
+ const widget: InjectionColumnWidget = {
4
+ metadata: {
5
+ id: 'sales.injection.payment-gateway-status-column',
6
+ priority: 50,
7
+ },
8
+ columns: [
9
+ {
10
+ id: 'gateway_status',
11
+ header: 'payment_gateways.column.gatewayStatus',
12
+ accessorKey: '_gateway.unifiedStatus',
13
+ sortable: false,
14
+ cell: ({ getValue }) => {
15
+ const value = getValue()
16
+ return typeof value === 'string' && value.trim().length > 0 ? value : 'pending'
17
+ },
18
+ },
19
+ ],
20
+ }
21
+
22
+ export default widget
@@ -17,6 +17,18 @@ export const injectionTable: ModuleInjectionTable = {
17
17
  priority: 50,
18
18
  },
19
19
  ],
20
+ 'data-table:sales.payments:columns': {
21
+ widgetId: 'sales.injection.payment-gateway-status-column',
22
+ priority: 50,
23
+ },
24
+ 'crud-form:sales.payment_method:fields': {
25
+ widgetId: 'sales.injection.payment-gateway-config-field',
26
+ priority: 40,
27
+ },
28
+ 'crud-form:sales.sales_payment_method:fields': {
29
+ widgetId: 'sales.injection.payment-gateway-config-field',
30
+ priority: 40,
31
+ },
20
32
  }
21
33
 
22
34
  export default injectionTable
@@ -0,0 +1,6 @@
1
+ export const features = [
2
+ { id: 'shipping_carriers.view', title: 'View shipping carrier shipments', module: 'shipping_carriers' },
3
+ { id: 'shipping_carriers.manage', title: 'Manage shipping carrier operations', module: 'shipping_carriers' },
4
+ ]
5
+
6
+ export default features
@@ -0,0 +1,53 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
3
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
+ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
5
+ import type { ShippingCarrierService } from '../../lib/shipping-service'
6
+ import { cancelShipmentSchema } from '../../data/validators'
7
+ import { shippingCarriersTag } from '../openapi'
8
+
9
+ export const metadata = {
10
+ path: '/shipping-carriers/cancel',
11
+ POST: { requireAuth: true, requireFeatures: ['shipping_carriers.manage'] },
12
+ }
13
+
14
+ export async function POST(req: Request) {
15
+ const auth = await getAuthFromRequest(req)
16
+ if (!auth?.tenantId || !auth.orgId) {
17
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
18
+ }
19
+ const payload = await readJsonSafe<unknown>(req)
20
+ const parsed = cancelShipmentSchema.safeParse(payload)
21
+ if (!parsed.success) {
22
+ return NextResponse.json({ error: 'Invalid payload', details: parsed.error.flatten() }, { status: 422 })
23
+ }
24
+ const container = await createRequestContainer()
25
+ const service = container.resolve('shippingCarrierService') as ShippingCarrierService
26
+ try {
27
+ const result = await service.cancelShipment({
28
+ ...parsed.data,
29
+ organizationId: auth.orgId as string,
30
+ tenantId: auth.tenantId,
31
+ })
32
+ return NextResponse.json(result)
33
+ } catch (error: unknown) {
34
+ const message = error instanceof Error ? error.message : 'Failed to cancel shipment'
35
+ return NextResponse.json({ error: message }, { status: 502 })
36
+ }
37
+ }
38
+
39
+ export const openApi = {
40
+ tags: [shippingCarriersTag],
41
+ summary: 'Cancel shipment',
42
+ methods: {
43
+ POST: {
44
+ summary: 'Cancel shipment',
45
+ tags: [shippingCarriersTag],
46
+ responses: [
47
+ { status: 200, description: 'Shipment cancelled' },
48
+ { status: 422, description: 'Validation failed' },
49
+ { status: 502, description: 'Provider upstream error' },
50
+ ],
51
+ },
52
+ },
53
+ }
@@ -0,0 +1,19 @@
1
+ import type { ApiInterceptor } from '@open-mercato/shared/lib/crud/api-interceptor'
2
+ import { getShippingAdapter } from '../lib/adapter-registry'
3
+
4
+ export const interceptors: ApiInterceptor[] = [
5
+ {
6
+ id: 'shipping_carriers.validate-provider',
7
+ targetRoute: 'shipping-carriers/*',
8
+ methods: ['POST', 'GET'],
9
+ priority: 100,
10
+ async before(request) {
11
+ const providerKey = (request.body?.providerKey ?? request.query?.providerKey) as string | undefined
12
+ if (!providerKey || providerKey.trim().length === 0) return { ok: true }
13
+ if (!getShippingAdapter(providerKey.trim())) {
14
+ return { ok: false, statusCode: 422, message: `Unknown shipping provider: ${providerKey}` }
15
+ }
16
+ return { ok: true }
17
+ },
18
+ },
19
+ ]
@@ -0,0 +1 @@
1
+ export const shippingCarriersTag = 'ShippingCarriers'
@@ -0,0 +1,53 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
3
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
+ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
5
+ import type { ShippingCarrierService } from '../../lib/shipping-service'
6
+ import { calculateRatesSchema } from '../../data/validators'
7
+ import { shippingCarriersTag } from '../openapi'
8
+
9
+ export const metadata = {
10
+ path: '/shipping-carriers/rates',
11
+ POST: { requireAuth: true, requireFeatures: ['shipping_carriers.manage'] },
12
+ }
13
+
14
+ export async function POST(req: Request) {
15
+ const auth = await getAuthFromRequest(req)
16
+ if (!auth?.tenantId || !auth.orgId) {
17
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
18
+ }
19
+ const payload = await readJsonSafe<unknown>(req)
20
+ const parsed = calculateRatesSchema.safeParse(payload)
21
+ if (!parsed.success) {
22
+ return NextResponse.json({ error: 'Invalid payload', details: parsed.error.flatten() }, { status: 422 })
23
+ }
24
+ const container = await createRequestContainer()
25
+ const service = container.resolve('shippingCarrierService') as ShippingCarrierService
26
+ try {
27
+ const rates = await service.calculateRates({
28
+ ...parsed.data,
29
+ organizationId: auth.orgId as string,
30
+ tenantId: auth.tenantId,
31
+ })
32
+ return NextResponse.json({ rates })
33
+ } catch (error: unknown) {
34
+ const message = error instanceof Error ? error.message : 'Failed to calculate rates'
35
+ return NextResponse.json({ error: message }, { status: 502 })
36
+ }
37
+ }
38
+
39
+ export const openApi = {
40
+ tags: [shippingCarriersTag],
41
+ summary: 'Calculate shipping rates',
42
+ methods: {
43
+ POST: {
44
+ summary: 'Calculate shipping rates',
45
+ tags: [shippingCarriersTag],
46
+ responses: [
47
+ { status: 200, description: 'Rates calculated' },
48
+ { status: 422, description: 'Validation failed' },
49
+ { status: 502, description: 'Provider upstream error' },
50
+ ],
51
+ },
52
+ },
53
+ }
@@ -0,0 +1,59 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
3
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
+ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
5
+ import type { ShippingCarrierService } from '../../lib/shipping-service'
6
+ import { createShipmentSchema } from '../../data/validators'
7
+ import { shippingCarriersTag } from '../openapi'
8
+
9
+ export const metadata = {
10
+ path: '/shipping-carriers/shipments',
11
+ POST: { requireAuth: true, requireFeatures: ['shipping_carriers.manage'] },
12
+ }
13
+
14
+ export async function POST(req: Request) {
15
+ const auth = await getAuthFromRequest(req)
16
+ if (!auth?.tenantId || !auth.orgId) {
17
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
18
+ }
19
+ const payload = await readJsonSafe<unknown>(req)
20
+ const parsed = createShipmentSchema.safeParse(payload)
21
+ if (!parsed.success) {
22
+ return NextResponse.json({ error: 'Invalid payload', details: parsed.error.flatten() }, { status: 422 })
23
+ }
24
+ const container = await createRequestContainer()
25
+ const service = container.resolve('shippingCarrierService') as ShippingCarrierService
26
+ try {
27
+ const shipment = await service.createShipment({
28
+ ...parsed.data,
29
+ organizationId: auth.orgId as string,
30
+ tenantId: auth.tenantId,
31
+ })
32
+ return NextResponse.json({
33
+ shipmentId: shipment.id,
34
+ carrierShipmentId: shipment.carrierShipmentId,
35
+ trackingNumber: shipment.trackingNumber,
36
+ status: shipment.unifiedStatus,
37
+ labelUrl: shipment.labelUrl,
38
+ }, { status: 201 })
39
+ } catch (error: unknown) {
40
+ const message = error instanceof Error ? error.message : 'Failed to create shipment'
41
+ return NextResponse.json({ error: message }, { status: 502 })
42
+ }
43
+ }
44
+
45
+ export const openApi = {
46
+ tags: [shippingCarriersTag],
47
+ summary: 'Create shipment',
48
+ methods: {
49
+ POST: {
50
+ summary: 'Create shipment',
51
+ tags: [shippingCarriersTag],
52
+ responses: [
53
+ { status: 201, description: 'Shipment created' },
54
+ { status: 422, description: 'Validation failed' },
55
+ { status: 502, description: 'Provider upstream error' },
56
+ ],
57
+ },
58
+ },
59
+ }
@@ -0,0 +1,56 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
3
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
4
+ import type { ShippingCarrierService } from '../../lib/shipping-service'
5
+ import { trackingQuerySchema } from '../../data/validators'
6
+ import { shippingCarriersTag } from '../openapi'
7
+
8
+ export const metadata = {
9
+ path: '/shipping-carriers/tracking',
10
+ GET: { requireAuth: true, requireFeatures: ['shipping_carriers.view'] },
11
+ }
12
+
13
+ export async function GET(req: Request) {
14
+ const auth = await getAuthFromRequest(req)
15
+ if (!auth?.tenantId || !auth.orgId) {
16
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
17
+ }
18
+ const url = new URL(req.url)
19
+ const parsed = trackingQuerySchema.safeParse({
20
+ providerKey: url.searchParams.get('providerKey'),
21
+ shipmentId: url.searchParams.get('shipmentId') ?? undefined,
22
+ trackingNumber: url.searchParams.get('trackingNumber') ?? undefined,
23
+ })
24
+ if (!parsed.success) {
25
+ return NextResponse.json({ error: 'Invalid query', details: parsed.error.flatten() }, { status: 422 })
26
+ }
27
+ const container = await createRequestContainer()
28
+ const service = container.resolve('shippingCarrierService') as ShippingCarrierService
29
+ try {
30
+ const tracking = await service.getTracking({
31
+ ...parsed.data,
32
+ organizationId: auth.orgId as string,
33
+ tenantId: auth.tenantId,
34
+ })
35
+ return NextResponse.json(tracking)
36
+ } catch (error: unknown) {
37
+ const message = error instanceof Error ? error.message : 'Failed to fetch tracking'
38
+ return NextResponse.json({ error: message }, { status: 502 })
39
+ }
40
+ }
41
+
42
+ export const openApi = {
43
+ tags: [shippingCarriersTag],
44
+ summary: 'Get tracking',
45
+ methods: {
46
+ GET: {
47
+ summary: 'Get tracking',
48
+ tags: [shippingCarriersTag],
49
+ responses: [
50
+ { status: 200, description: 'Tracking returned' },
51
+ { status: 422, description: 'Validation failed' },
52
+ { status: 502, description: 'Provider upstream error' },
53
+ ],
54
+ },
55
+ },
56
+ }
@@ -0,0 +1,134 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
3
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
4
+ import { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'
5
+ import type { EntityManager } from '@mikro-orm/postgresql'
6
+ import type { CredentialsService } from '../../../../integrations/lib/credentials-service'
7
+ import { CarrierShipment } from '../../../data/entities'
8
+ import { getShippingAdapter } from '../../../lib/adapter-registry'
9
+ import type { ShippingCarrierService } from '../../../lib/shipping-service'
10
+ import { getShippingCarrierQueue } from '../../../lib/queue'
11
+ import { shippingCarriersTag } from '../../openapi'
12
+
13
+ export const metadata = {
14
+ path: '/shipping-carriers/webhook/[provider]',
15
+ POST: { requireAuth: false },
16
+ }
17
+
18
+ function readCarrierShipmentId(payload: Record<string, unknown> | null): string | null {
19
+ if (!payload) return null
20
+ const shipmentId = payload.shipmentId
21
+ if (typeof shipmentId === 'string' && shipmentId.trim().length > 0) return shipmentId.trim()
22
+ const data = payload.data
23
+ if (data && typeof data === 'object') {
24
+ const nested = (data as Record<string, unknown>).shipmentId
25
+ if (typeof nested === 'string' && nested.trim().length > 0) return nested.trim()
26
+ }
27
+ return null
28
+ }
29
+
30
+ export async function POST(req: Request, { params }: { params: Promise<{ provider: string }> | { provider: string } }) {
31
+ const resolvedParams = await params
32
+ const providerKey = resolvedParams.provider
33
+ const adapter = getShippingAdapter(providerKey)
34
+ if (!adapter) {
35
+ return NextResponse.json({ error: `No shipping adapter for provider: ${providerKey}` }, { status: 404 })
36
+ }
37
+
38
+ const rawBody = await req.text()
39
+ const headers: Record<string, string> = {}
40
+ req.headers.forEach((value, key) => {
41
+ headers[key] = value
42
+ })
43
+
44
+ const container = await createRequestContainer()
45
+ const service = container.resolve('shippingCarrierService') as ShippingCarrierService
46
+ const em = container.resolve('em') as EntityManager
47
+ const integrationCredentialsService = container.resolve('integrationCredentialsService') as CredentialsService
48
+ const queue = getShippingCarrierQueue('shipping-carriers-webhook')
49
+ const payload = await readJsonSafe<Record<string, unknown>>(rawBody)
50
+ const carrierShipmentId = readCarrierShipmentId(payload)
51
+
52
+ try {
53
+ const candidates = carrierShipmentId
54
+ ? await findWithDecryption(
55
+ em,
56
+ CarrierShipment,
57
+ {
58
+ providerKey,
59
+ carrierShipmentId,
60
+ deletedAt: null,
61
+ },
62
+ { limit: 10, orderBy: { createdAt: 'desc' } },
63
+ )
64
+ : []
65
+
66
+ let shipment = null as CarrierShipment | null
67
+ let matchedScope = null as { organizationId: string; tenantId: string } | null
68
+ let event = null as Awaited<ReturnType<typeof adapter.verifyWebhook>> | null
69
+ let lastVerificationError: unknown = null
70
+
71
+ for (const candidate of candidates) {
72
+ const candidateScope = { organizationId: candidate.organizationId, tenantId: candidate.tenantId }
73
+ const credentials = await integrationCredentialsService.resolve(`carrier_${providerKey}`, candidateScope) ?? {}
74
+ try {
75
+ event = await adapter.verifyWebhook({ rawBody, headers, credentials })
76
+ shipment = candidate
77
+ matchedScope = candidateScope
78
+ break
79
+ } catch (error: unknown) {
80
+ lastVerificationError = error
81
+ }
82
+ }
83
+
84
+ if (!event) {
85
+ try {
86
+ event = await adapter.verifyWebhook({ rawBody, headers, credentials: {} })
87
+ } catch (error: unknown) {
88
+ throw lastVerificationError ?? error
89
+ }
90
+ }
91
+ if (!event) {
92
+ throw new Error('Webhook verification failed')
93
+ }
94
+
95
+ if (!shipment && carrierShipmentId && matchedScope) {
96
+ shipment = await service.findShipmentByCarrierId(providerKey, carrierShipmentId, matchedScope)
97
+ }
98
+
99
+ const scope = shipment
100
+ ? { organizationId: shipment.organizationId, tenantId: shipment.tenantId }
101
+ : matchedScope
102
+
103
+ await queue.enqueue({
104
+ name: 'shipping-carrier-webhook',
105
+ payload: {
106
+ providerKey,
107
+ event,
108
+ shipmentId: shipment?.id ?? null,
109
+ scope,
110
+ },
111
+ })
112
+
113
+ return NextResponse.json({ received: true, queued: true }, { status: 202 })
114
+ } catch (error: unknown) {
115
+ const message = error instanceof Error ? error.message : 'Webhook verification failed'
116
+ return NextResponse.json({ error: message }, { status: 401 })
117
+ }
118
+ }
119
+
120
+ export const openApi = {
121
+ tags: [shippingCarriersTag],
122
+ summary: 'Receive shipping carrier webhook',
123
+ methods: {
124
+ POST: {
125
+ summary: 'Process inbound carrier webhook',
126
+ tags: [shippingCarriersTag],
127
+ responses: [
128
+ { status: 202, description: 'Webhook accepted for async processing' },
129
+ { status: 401, description: 'Signature verification failed' },
130
+ { status: 404, description: 'Unknown provider' },
131
+ ],
132
+ },
133
+ },
134
+ }
@@ -0,0 +1,89 @@
1
+ import type { ResponseEnricher } from '@open-mercato/shared/lib/crud/response-enricher'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
4
+ import { CarrierShipment } from './entities'
5
+
6
+ type SalesShipmentRecord = Record<string, unknown> & { id?: string; shipmentId?: string; orderId?: string }
7
+
8
+ const salesShipmentCarrierEnricher: ResponseEnricher<SalesShipmentRecord, Record<string, unknown>> = {
9
+ id: 'shipping_carriers.sales-shipment-carrier',
10
+ targetEntity: 'sales.shipment',
11
+ priority: 40,
12
+ timeout: 2000,
13
+ async enrichOne(record, context) {
14
+ const orderId = typeof record.orderId === 'string' ? record.orderId : null
15
+ if (!orderId) return record
16
+ const em = context.em as EntityManager
17
+ const scope = { organizationId: context.organizationId, tenantId: context.tenantId }
18
+ const shipment = await findOneWithDecryption(
19
+ em,
20
+ CarrierShipment,
21
+ {
22
+ orderId,
23
+ organizationId: context.organizationId,
24
+ tenantId: context.tenantId,
25
+ deletedAt: null,
26
+ },
27
+ { orderBy: { createdAt: 'desc' } },
28
+ scope,
29
+ )
30
+ if (!shipment) return record
31
+ return {
32
+ ...record,
33
+ _carrier: {
34
+ shipmentId: shipment.id,
35
+ providerKey: shipment.providerKey,
36
+ trackingNumber: shipment.trackingNumber,
37
+ status: shipment.unifiedStatus,
38
+ },
39
+ }
40
+ },
41
+ async enrichMany(records, context) {
42
+ const orderIds = Array.from(new Set(
43
+ records
44
+ .map((record) => (typeof record.orderId === 'string' ? record.orderId : null))
45
+ .filter((value): value is string => Boolean(value)),
46
+ ))
47
+ if (!orderIds.length) return records
48
+
49
+ const em = context.em as EntityManager
50
+ const scope = { organizationId: context.organizationId, tenantId: context.tenantId }
51
+ const shipments = await findWithDecryption(
52
+ em,
53
+ CarrierShipment,
54
+ {
55
+ orderId: { $in: orderIds },
56
+ organizationId: context.organizationId,
57
+ tenantId: context.tenantId,
58
+ deletedAt: null,
59
+ },
60
+ { orderBy: { createdAt: 'desc' } },
61
+ scope,
62
+ )
63
+
64
+ const latestByOrderId = new Map<string, CarrierShipment>()
65
+ for (const shipment of shipments) {
66
+ if (!latestByOrderId.has(shipment.orderId)) {
67
+ latestByOrderId.set(shipment.orderId, shipment)
68
+ }
69
+ }
70
+
71
+ return records.map((record) => {
72
+ const orderId = typeof record.orderId === 'string' ? record.orderId : null
73
+ if (!orderId) return record
74
+ const shipment = latestByOrderId.get(orderId)
75
+ if (!shipment) return record
76
+ return {
77
+ ...record,
78
+ _carrier: {
79
+ shipmentId: shipment.id,
80
+ providerKey: shipment.providerKey,
81
+ trackingNumber: shipment.trackingNumber,
82
+ status: shipment.unifiedStatus,
83
+ },
84
+ }
85
+ })
86
+ },
87
+ }
88
+
89
+ export const enrichers: ResponseEnricher[] = [salesShipmentCarrierEnricher]
@@ -0,0 +1,60 @@
1
+ import { Entity, Index, OptionalProps, PrimaryKey, Property } from '@mikro-orm/core'
2
+
3
+ @Entity({ tableName: 'carrier_shipments' })
4
+ @Index({ properties: ['orderId', 'organizationId', 'tenantId'] })
5
+ @Index({ properties: ['providerKey', 'carrierShipmentId', 'organizationId'] })
6
+ @Index({ properties: ['organizationId', 'tenantId', 'unifiedStatus'] })
7
+ export class CarrierShipment {
8
+ [OptionalProps]?: 'labelUrl' | 'labelData' | 'trackingEvents' | 'carrierStatus' | 'lastWebhookAt' | 'lastPolledAt' | 'createdAt' | 'updatedAt' | 'deletedAt'
9
+
10
+ @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
11
+ id!: string
12
+
13
+ @Property({ name: 'order_id', type: 'uuid' })
14
+ orderId!: string
15
+
16
+ @Property({ name: 'provider_key', type: 'text' })
17
+ providerKey!: string
18
+
19
+ @Property({ name: 'carrier_shipment_id', type: 'text' })
20
+ carrierShipmentId!: string
21
+
22
+ @Property({ name: 'tracking_number', type: 'text' })
23
+ trackingNumber!: string
24
+
25
+ @Property({ name: 'unified_status', type: 'text' })
26
+ unifiedStatus: string = 'label_created'
27
+
28
+ @Property({ name: 'carrier_status', type: 'text', nullable: true })
29
+ carrierStatus?: string | null
30
+
31
+ @Property({ name: 'label_url', type: 'text', nullable: true })
32
+ labelUrl?: string | null
33
+
34
+ @Property({ name: 'label_data', type: 'text', nullable: true })
35
+ labelData?: string | null
36
+
37
+ @Property({ name: 'tracking_events', type: 'jsonb', nullable: true })
38
+ trackingEvents?: Array<{ status: string; occurredAt: string; location?: string }> | null
39
+
40
+ @Property({ name: 'organization_id', type: 'uuid' })
41
+ organizationId!: string
42
+
43
+ @Property({ name: 'tenant_id', type: 'uuid' })
44
+ tenantId!: string
45
+
46
+ @Property({ name: 'last_webhook_at', type: Date, nullable: true })
47
+ lastWebhookAt?: Date | null
48
+
49
+ @Property({ name: 'last_polled_at', type: Date, nullable: true })
50
+ lastPolledAt?: Date | null
51
+
52
+ @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
53
+ createdAt: Date = new Date()
54
+
55
+ @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })
56
+ updatedAt: Date = new Date()
57
+
58
+ @Property({ name: 'deleted_at', type: Date, nullable: true })
59
+ deletedAt?: Date | null
60
+ }
@@ -0,0 +1,48 @@
1
+ import { z } from 'zod'
2
+
3
+ const addressSchema = z.object({
4
+ countryCode: z.string().min(2).max(3),
5
+ postalCode: z.string().min(1),
6
+ city: z.string().min(1),
7
+ line1: z.string().min(1),
8
+ line2: z.string().optional(),
9
+ })
10
+
11
+ const packageSchema = z.object({
12
+ weightKg: z.number().positive(),
13
+ lengthCm: z.number().positive(),
14
+ widthCm: z.number().positive(),
15
+ heightCm: z.number().positive(),
16
+ })
17
+
18
+ export const calculateRatesSchema = z.object({
19
+ providerKey: z.string().min(1),
20
+ origin: addressSchema,
21
+ destination: addressSchema,
22
+ packages: z.array(packageSchema).min(1),
23
+ })
24
+
25
+ export const createShipmentSchema = z.object({
26
+ providerKey: z.string().min(1),
27
+ orderId: z.string().uuid(),
28
+ origin: addressSchema,
29
+ destination: addressSchema,
30
+ packages: z.array(packageSchema).min(1),
31
+ serviceCode: z.string().min(1),
32
+ labelFormat: z.enum(['pdf', 'zpl', 'png']).optional(),
33
+ })
34
+
35
+ export const trackingQuerySchema = z.object({
36
+ providerKey: z.string().min(1),
37
+ shipmentId: z.string().uuid().optional(),
38
+ trackingNumber: z.string().min(1).optional(),
39
+ }).refine((value) => Boolean(value.shipmentId || value.trackingNumber), {
40
+ message: 'shipmentId or trackingNumber is required',
41
+ path: ['shipmentId'],
42
+ })
43
+
44
+ export const cancelShipmentSchema = z.object({
45
+ providerKey: z.string().min(1),
46
+ shipmentId: z.string().uuid(),
47
+ reason: z.string().max(200).optional(),
48
+ })
@@ -0,0 +1,20 @@
1
+ import { asFunction, asValue } from 'awilix'
2
+ import type { EntityManager } from '@mikro-orm/postgresql'
3
+ import type { AppContainer } from '@open-mercato/shared/lib/di/container'
4
+ import type { CredentialsService } from '../integrations/lib/credentials-service'
5
+ import { CarrierShipment } from './data/entities'
6
+ import { createShippingCarrierService } from './lib/shipping-service'
7
+
8
+ type Cradle = {
9
+ em: EntityManager
10
+ integrationCredentialsService: CredentialsService
11
+ }
12
+
13
+ export function register(container: AppContainer) {
14
+ container.register({
15
+ shippingCarrierService: asFunction(({ em, integrationCredentialsService }: Cradle) =>
16
+ createShippingCarrierService({ em, integrationCredentialsService }),
17
+ ).scoped().proxy(),
18
+ CarrierShipment: asValue(CarrierShipment),
19
+ })
20
+ }