@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,378 @@
1
+ import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import {
3
+ getGatewayAdapter
4
+ } from "@open-mercato/shared/modules/payment_gateways/types";
5
+ import { GatewayTransaction } from "../data/entities.js";
6
+ import { isValidTransition } from "./status-machine.js";
7
+ import { emitPaymentGatewayEvent } from "../events.js";
8
+ function createPaymentGatewayService(deps) {
9
+ const { em, integrationCredentialsService, integrationLogService } = deps;
10
+ async function findTransactionOrThrow(transactionId, scope) {
11
+ const transaction = await findOneWithDecryption(
12
+ em,
13
+ GatewayTransaction,
14
+ {
15
+ id: transactionId,
16
+ organizationId: scope.organizationId,
17
+ tenantId: scope.tenantId,
18
+ deletedAt: null
19
+ },
20
+ void 0,
21
+ scope
22
+ );
23
+ if (!transaction) {
24
+ throw new Error("Transaction not found");
25
+ }
26
+ return transaction;
27
+ }
28
+ function readProviderSessionId(transaction) {
29
+ if (typeof transaction.providerSessionId === "string" && transaction.providerSessionId.trim().length > 0) {
30
+ return transaction.providerSessionId;
31
+ }
32
+ throw new Error("Transaction is missing provider session id");
33
+ }
34
+ async function emitStatusEvent(status, payload) {
35
+ const eventMap = {
36
+ authorized: "payment_gateways.payment.authorized",
37
+ captured: "payment_gateways.payment.captured",
38
+ failed: "payment_gateways.payment.failed",
39
+ refunded: "payment_gateways.payment.refunded",
40
+ cancelled: "payment_gateways.payment.cancelled"
41
+ };
42
+ const eventId = eventMap[status];
43
+ if (!eventId) return;
44
+ await emitPaymentGatewayEvent(eventId, payload);
45
+ }
46
+ async function writeTransactionLog(providerKey, scope, transactionId, level, message, payload, code) {
47
+ if (!integrationLogService) return;
48
+ await integrationLogService.write({
49
+ integrationId: `gateway_${providerKey}`,
50
+ scopeEntityType: "payment_transaction",
51
+ scopeEntityId: transactionId,
52
+ level,
53
+ message,
54
+ code,
55
+ payload: payload ?? null
56
+ }, scope);
57
+ }
58
+ async function resolveAdapterAndCredentials(providerKey, scope) {
59
+ const integrationId = `gateway_${providerKey}`;
60
+ const selectedVersion = deps.integrationStateService ? await deps.integrationStateService.resolveApiVersion(integrationId, scope) : void 0;
61
+ const adapter = getGatewayAdapter(providerKey, selectedVersion);
62
+ if (!adapter) {
63
+ throw new Error(
64
+ selectedVersion ? `No gateway adapter registered for provider: ${providerKey} (version: ${selectedVersion})` : `No gateway adapter registered for provider: ${providerKey}`
65
+ );
66
+ }
67
+ const credentials = await integrationCredentialsService.resolve(integrationId, scope) ?? {};
68
+ return { adapter, credentials };
69
+ }
70
+ return {
71
+ async createPaymentSession(input) {
72
+ const scope = { organizationId: input.organizationId, tenantId: input.tenantId };
73
+ const { adapter, credentials } = await resolveAdapterAndCredentials(input.providerKey, scope);
74
+ const sessionInput = {
75
+ paymentId: input.paymentId,
76
+ orderId: input.orderId,
77
+ tenantId: input.tenantId,
78
+ organizationId: input.organizationId,
79
+ amount: input.amount,
80
+ currencyCode: input.currencyCode,
81
+ captureMethod: input.captureMethod,
82
+ description: input.description,
83
+ successUrl: input.successUrl,
84
+ cancelUrl: input.cancelUrl,
85
+ metadata: input.metadata,
86
+ credentials
87
+ };
88
+ const session = await adapter.createSession(sessionInput);
89
+ const transaction = em.create(GatewayTransaction, {
90
+ paymentId: input.paymentId,
91
+ providerKey: input.providerKey,
92
+ providerSessionId: session.sessionId,
93
+ unifiedStatus: session.status,
94
+ redirectUrl: session.redirectUrl ?? null,
95
+ clientSecret: null,
96
+ amount: String(input.amount),
97
+ currencyCode: input.currencyCode,
98
+ gatewayMetadata: session.providerData ?? null,
99
+ organizationId: input.organizationId,
100
+ tenantId: input.tenantId
101
+ });
102
+ await em.persistAndFlush(transaction);
103
+ await emitPaymentGatewayEvent("payment_gateways.session.created", {
104
+ transactionId: transaction.id,
105
+ paymentId: transaction.paymentId,
106
+ providerKey: transaction.providerKey,
107
+ status: transaction.unifiedStatus,
108
+ organizationId: transaction.organizationId,
109
+ tenantId: transaction.tenantId
110
+ });
111
+ await writeTransactionLog(
112
+ transaction.providerKey,
113
+ scope,
114
+ transaction.id,
115
+ "info",
116
+ "Payment session created",
117
+ {
118
+ paymentId: transaction.paymentId,
119
+ providerSessionId: transaction.providerSessionId,
120
+ status: transaction.unifiedStatus,
121
+ amount: input.amount,
122
+ currencyCode: input.currencyCode
123
+ }
124
+ );
125
+ return { transaction, session };
126
+ },
127
+ async capturePayment(transactionId, amount, scope) {
128
+ const transaction = await findTransactionOrThrow(transactionId, scope);
129
+ const { adapter, credentials } = await resolveAdapterAndCredentials(
130
+ transaction.providerKey,
131
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId }
132
+ );
133
+ const result = await adapter.capture({
134
+ sessionId: readProviderSessionId(transaction),
135
+ amount,
136
+ credentials
137
+ });
138
+ transaction.unifiedStatus = result.status;
139
+ transaction.gatewayMetadata = { ...transaction.gatewayMetadata, captureResult: result.providerData };
140
+ await em.flush();
141
+ await emitStatusEvent(result.status, {
142
+ transactionId: transaction.id,
143
+ paymentId: transaction.paymentId,
144
+ providerKey: transaction.providerKey,
145
+ organizationId: transaction.organizationId,
146
+ tenantId: transaction.tenantId
147
+ });
148
+ await writeTransactionLog(
149
+ transaction.providerKey,
150
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId },
151
+ transaction.id,
152
+ "info",
153
+ "Payment captured",
154
+ {
155
+ amount: amount ?? null,
156
+ status: result.status,
157
+ capturedAmount: result.capturedAmount
158
+ }
159
+ );
160
+ return result;
161
+ },
162
+ async refundPayment(transactionId, amount, reason, scope) {
163
+ const transaction = await findTransactionOrThrow(transactionId, scope);
164
+ const { adapter, credentials } = await resolveAdapterAndCredentials(
165
+ transaction.providerKey,
166
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId }
167
+ );
168
+ const result = await adapter.refund({
169
+ sessionId: readProviderSessionId(transaction),
170
+ amount,
171
+ reason,
172
+ credentials
173
+ });
174
+ transaction.unifiedStatus = result.status;
175
+ transaction.gatewayRefundId = result.refundId;
176
+ transaction.gatewayMetadata = { ...transaction.gatewayMetadata, refundResult: result.providerData };
177
+ await em.flush();
178
+ await emitStatusEvent(result.status, {
179
+ transactionId: transaction.id,
180
+ paymentId: transaction.paymentId,
181
+ providerKey: transaction.providerKey,
182
+ organizationId: transaction.organizationId,
183
+ tenantId: transaction.tenantId
184
+ });
185
+ await writeTransactionLog(
186
+ transaction.providerKey,
187
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId },
188
+ transaction.id,
189
+ "info",
190
+ "Payment refunded",
191
+ {
192
+ amount: amount ?? null,
193
+ reason: reason ?? null,
194
+ status: result.status,
195
+ refundId: result.refundId
196
+ }
197
+ );
198
+ return result;
199
+ },
200
+ async cancelPayment(transactionId, reason, scope) {
201
+ const transaction = await findTransactionOrThrow(transactionId, scope);
202
+ const { adapter, credentials } = await resolveAdapterAndCredentials(
203
+ transaction.providerKey,
204
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId }
205
+ );
206
+ const result = await adapter.cancel({
207
+ sessionId: readProviderSessionId(transaction),
208
+ reason,
209
+ credentials
210
+ });
211
+ transaction.unifiedStatus = result.status;
212
+ await em.flush();
213
+ await emitStatusEvent(result.status, {
214
+ transactionId: transaction.id,
215
+ paymentId: transaction.paymentId,
216
+ providerKey: transaction.providerKey,
217
+ organizationId: transaction.organizationId,
218
+ tenantId: transaction.tenantId
219
+ });
220
+ await writeTransactionLog(
221
+ transaction.providerKey,
222
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId },
223
+ transaction.id,
224
+ "info",
225
+ "Payment cancelled",
226
+ {
227
+ reason: reason ?? null,
228
+ status: result.status
229
+ }
230
+ );
231
+ return result;
232
+ },
233
+ async getPaymentStatus(transactionId, scope) {
234
+ const transaction = await findTransactionOrThrow(transactionId, scope);
235
+ const { adapter, credentials } = await resolveAdapterAndCredentials(
236
+ transaction.providerKey,
237
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId }
238
+ );
239
+ const status = await adapter.getStatus({
240
+ sessionId: readProviderSessionId(transaction),
241
+ credentials
242
+ });
243
+ if (status.status !== transaction.unifiedStatus && isValidTransition(transaction.unifiedStatus, status.status)) {
244
+ const previousStatus = transaction.unifiedStatus;
245
+ transaction.unifiedStatus = status.status;
246
+ transaction.gatewayStatus = status.status;
247
+ transaction.gatewayMetadata = { ...transaction.gatewayMetadata, statusResult: status.providerData ?? null };
248
+ transaction.lastPolledAt = /* @__PURE__ */ new Date();
249
+ await em.flush();
250
+ await emitStatusEvent(status.status, {
251
+ transactionId: transaction.id,
252
+ paymentId: transaction.paymentId,
253
+ providerKey: transaction.providerKey,
254
+ previousStatus,
255
+ organizationId: transaction.organizationId,
256
+ tenantId: transaction.tenantId
257
+ });
258
+ await writeTransactionLog(
259
+ transaction.providerKey,
260
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId },
261
+ transaction.id,
262
+ "info",
263
+ "Payment status updated by poller",
264
+ {
265
+ previousStatus,
266
+ nextStatus: status.status
267
+ }
268
+ );
269
+ }
270
+ return status;
271
+ },
272
+ async syncTransactionStatus(transactionId, update, scope) {
273
+ const transaction = await findTransactionOrThrow(transactionId, scope);
274
+ const currentStatus = transaction.unifiedStatus;
275
+ const canTransition = isValidTransition(currentStatus, update.unifiedStatus);
276
+ const shouldApplyStatus = canTransition && update.unifiedStatus !== currentStatus;
277
+ const previousStatus = transaction.unifiedStatus;
278
+ if (shouldApplyStatus) {
279
+ transaction.unifiedStatus = update.unifiedStatus;
280
+ }
281
+ if (update.providerStatus) {
282
+ transaction.gatewayStatus = update.providerStatus;
283
+ }
284
+ if (update.providerData) {
285
+ transaction.gatewayMetadata = { ...transaction.gatewayMetadata, ...update.providerData };
286
+ }
287
+ if (update.webhookEvent) {
288
+ const webhookLog = Array.isArray(transaction.webhookLog) ? transaction.webhookLog : [];
289
+ webhookLog.push({
290
+ eventType: update.webhookEvent.eventType,
291
+ receivedAt: update.webhookEvent.receivedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
292
+ idempotencyKey: update.webhookEvent.idempotencyKey,
293
+ unifiedStatus: update.unifiedStatus,
294
+ processed: update.webhookEvent.processed
295
+ });
296
+ transaction.webhookLog = webhookLog;
297
+ }
298
+ transaction.lastWebhookAt = /* @__PURE__ */ new Date();
299
+ await em.flush();
300
+ if (shouldApplyStatus) {
301
+ await emitStatusEvent(update.unifiedStatus, {
302
+ transactionId: transaction.id,
303
+ paymentId: transaction.paymentId,
304
+ providerKey: transaction.providerKey,
305
+ previousStatus,
306
+ organizationId: transaction.organizationId,
307
+ tenantId: transaction.tenantId
308
+ });
309
+ }
310
+ await writeTransactionLog(
311
+ transaction.providerKey,
312
+ { organizationId: transaction.organizationId, tenantId: transaction.tenantId },
313
+ transaction.id,
314
+ shouldApplyStatus ? "info" : "warn",
315
+ shouldApplyStatus ? "Payment status synchronized from webhook" : "Webhook received with no status transition",
316
+ {
317
+ previousStatus,
318
+ nextStatus: update.unifiedStatus,
319
+ providerStatus: update.providerStatus ?? null,
320
+ eventType: update.webhookEvent?.eventType ?? null,
321
+ idempotencyKey: update.webhookEvent?.idempotencyKey ?? null
322
+ }
323
+ );
324
+ },
325
+ async findTransaction(id, scope) {
326
+ return findOneWithDecryption(
327
+ em,
328
+ GatewayTransaction,
329
+ {
330
+ id,
331
+ organizationId: scope.organizationId,
332
+ tenantId: scope.tenantId,
333
+ deletedAt: null
334
+ },
335
+ void 0,
336
+ scope
337
+ );
338
+ },
339
+ async findTransactionBySessionId(providerSessionId, scope, providerKey) {
340
+ return findOneWithDecryption(
341
+ em,
342
+ GatewayTransaction,
343
+ {
344
+ providerSessionId,
345
+ organizationId: scope.organizationId,
346
+ tenantId: scope.tenantId,
347
+ deletedAt: null,
348
+ ...providerKey ? { providerKey } : {}
349
+ },
350
+ void 0,
351
+ scope
352
+ );
353
+ },
354
+ async listTransactionsForStatusPolling(scope) {
355
+ const where = {
356
+ unifiedStatus: { $in: ["pending", "authorized", "partially_captured"] },
357
+ deletedAt: null
358
+ };
359
+ if (scope?.organizationId) where.organizationId = scope.organizationId;
360
+ if (scope?.tenantId) where.tenantId = scope.tenantId;
361
+ if (scope?.providerKey) where.providerKey = scope.providerKey;
362
+ return findWithDecryption(
363
+ em,
364
+ GatewayTransaction,
365
+ where,
366
+ {
367
+ orderBy: { updatedAt: "asc" },
368
+ limit: scope?.limit ?? 100
369
+ },
370
+ scope
371
+ );
372
+ }
373
+ };
374
+ }
375
+ export {
376
+ createPaymentGatewayService
377
+ };
378
+ //# sourceMappingURL=gateway-service.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/payment_gateways/lib/gateway-service.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n getGatewayAdapter,\n type CreateSessionInput,\n type CreateSessionResult,\n type CaptureResult,\n type RefundResult,\n type CancelResult,\n type GatewayPaymentStatus,\n type UnifiedPaymentStatus,\n} from '@open-mercato/shared/modules/payment_gateways/types'\nimport type { CredentialsService } from '../../integrations/lib/credentials-service'\nimport type { IntegrationStateService } from '../../integrations/lib/state-service'\nimport type { IntegrationLogService } from '../../integrations/lib/log-service'\nimport { GatewayTransaction } from '../data/entities'\nimport { isValidTransition } from './status-machine'\nimport { emitPaymentGatewayEvent } from '../events'\n\nexport interface PaymentGatewayServiceDeps {\n em: EntityManager\n integrationCredentialsService: CredentialsService\n integrationStateService?: IntegrationStateService\n integrationLogService?: IntegrationLogService\n}\n\nexport interface CreatePaymentSessionInput {\n providerKey: string\n paymentId: string\n orderId?: string\n amount: number\n currencyCode: string\n captureMethod?: 'automatic' | 'manual'\n description?: string\n successUrl?: string\n cancelUrl?: string\n metadata?: Record<string, unknown>\n organizationId: string\n tenantId: string\n}\n\nexport function createPaymentGatewayService(deps: PaymentGatewayServiceDeps) {\n const { em, integrationCredentialsService, integrationLogService } = deps\n\n async function findTransactionOrThrow(\n transactionId: string,\n scope: { organizationId: string; tenantId: string },\n ): Promise<GatewayTransaction> {\n const transaction = await findOneWithDecryption(\n em,\n GatewayTransaction,\n {\n id: transactionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n if (!transaction) {\n throw new Error('Transaction not found')\n }\n return transaction\n }\n\n function readProviderSessionId(transaction: GatewayTransaction): string {\n if (typeof transaction.providerSessionId === 'string' && transaction.providerSessionId.trim().length > 0) {\n return transaction.providerSessionId\n }\n throw new Error('Transaction is missing provider session id')\n }\n\n async function emitStatusEvent(status: UnifiedPaymentStatus, payload: Record<string, unknown>) {\n type PaymentGatewayEventId = Parameters<typeof emitPaymentGatewayEvent>[0]\n const eventMap: Partial<Record<UnifiedPaymentStatus, PaymentGatewayEventId>> = {\n authorized: 'payment_gateways.payment.authorized',\n captured: 'payment_gateways.payment.captured',\n failed: 'payment_gateways.payment.failed',\n refunded: 'payment_gateways.payment.refunded',\n cancelled: 'payment_gateways.payment.cancelled',\n }\n const eventId = eventMap[status]\n if (!eventId) return\n await emitPaymentGatewayEvent(eventId, payload)\n }\n\n async function writeTransactionLog(\n providerKey: string,\n scope: { organizationId: string; tenantId: string },\n transactionId: string,\n level: 'info' | 'warn' | 'error',\n message: string,\n payload?: Record<string, unknown> | null,\n code?: string | null,\n ) {\n if (!integrationLogService) return\n await integrationLogService.write({\n integrationId: `gateway_${providerKey}`,\n scopeEntityType: 'payment_transaction',\n scopeEntityId: transactionId,\n level,\n message,\n code,\n payload: payload ?? null,\n }, scope)\n }\n\n async function resolveAdapterAndCredentials(providerKey: string, scope: { organizationId: string; tenantId: string }) {\n const integrationId = `gateway_${providerKey}`\n const selectedVersion = deps.integrationStateService\n ? await deps.integrationStateService.resolveApiVersion(integrationId, scope)\n : undefined\n const adapter = getGatewayAdapter(providerKey, selectedVersion)\n if (!adapter) {\n throw new Error(\n selectedVersion\n ? `No gateway adapter registered for provider: ${providerKey} (version: ${selectedVersion})`\n : `No gateway adapter registered for provider: ${providerKey}`,\n )\n }\n const credentials = await integrationCredentialsService.resolve(integrationId, scope) ?? {}\n\n return { adapter, credentials }\n }\n\n return {\n async createPaymentSession(input: CreatePaymentSessionInput): Promise<{ transaction: GatewayTransaction; session: CreateSessionResult }> {\n const scope = { organizationId: input.organizationId, tenantId: input.tenantId }\n const { adapter, credentials } = await resolveAdapterAndCredentials(input.providerKey, scope)\n\n const sessionInput: CreateSessionInput = {\n paymentId: input.paymentId,\n orderId: input.orderId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n amount: input.amount,\n currencyCode: input.currencyCode,\n captureMethod: input.captureMethod,\n description: input.description,\n successUrl: input.successUrl,\n cancelUrl: input.cancelUrl,\n metadata: input.metadata,\n credentials,\n }\n\n const session = await adapter.createSession(sessionInput)\n\n const transaction = em.create(GatewayTransaction, {\n paymentId: input.paymentId,\n providerKey: input.providerKey,\n providerSessionId: session.sessionId,\n unifiedStatus: session.status,\n redirectUrl: session.redirectUrl ?? null,\n clientSecret: null,\n amount: String(input.amount),\n currencyCode: input.currencyCode,\n gatewayMetadata: session.providerData ?? null,\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n })\n await em.persistAndFlush(transaction)\n await emitPaymentGatewayEvent('payment_gateways.session.created', {\n transactionId: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n status: transaction.unifiedStatus,\n organizationId: transaction.organizationId,\n tenantId: transaction.tenantId,\n })\n await writeTransactionLog(\n transaction.providerKey,\n scope,\n transaction.id,\n 'info',\n 'Payment session created',\n {\n paymentId: transaction.paymentId,\n providerSessionId: transaction.providerSessionId,\n status: transaction.unifiedStatus,\n amount: input.amount,\n currencyCode: input.currencyCode,\n },\n )\n\n return { transaction, session }\n },\n\n async capturePayment(transactionId: string, amount: number | undefined, scope: { organizationId: string; tenantId: string }): Promise<CaptureResult> {\n const transaction = await findTransactionOrThrow(transactionId, scope)\n const { adapter, credentials } = await resolveAdapterAndCredentials(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n )\n\n const result = await adapter.capture({\n sessionId: readProviderSessionId(transaction),\n amount,\n credentials,\n })\n\n transaction.unifiedStatus = result.status\n transaction.gatewayMetadata = { ...transaction.gatewayMetadata, captureResult: result.providerData }\n await em.flush()\n await emitStatusEvent(result.status, {\n transactionId: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n organizationId: transaction.organizationId,\n tenantId: transaction.tenantId,\n })\n await writeTransactionLog(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n transaction.id,\n 'info',\n 'Payment captured',\n {\n amount: amount ?? null,\n status: result.status,\n capturedAmount: result.capturedAmount,\n },\n )\n\n return result\n },\n\n async refundPayment(\n transactionId: string,\n amount: number | undefined,\n reason: string | undefined,\n scope: { organizationId: string; tenantId: string },\n ): Promise<RefundResult> {\n const transaction = await findTransactionOrThrow(transactionId, scope)\n const { adapter, credentials } = await resolveAdapterAndCredentials(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n )\n\n const result = await adapter.refund({\n sessionId: readProviderSessionId(transaction),\n amount,\n reason,\n credentials,\n })\n\n transaction.unifiedStatus = result.status\n transaction.gatewayRefundId = result.refundId\n transaction.gatewayMetadata = { ...transaction.gatewayMetadata, refundResult: result.providerData }\n await em.flush()\n await emitStatusEvent(result.status, {\n transactionId: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n organizationId: transaction.organizationId,\n tenantId: transaction.tenantId,\n })\n await writeTransactionLog(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n transaction.id,\n 'info',\n 'Payment refunded',\n {\n amount: amount ?? null,\n reason: reason ?? null,\n status: result.status,\n refundId: result.refundId,\n },\n )\n\n return result\n },\n\n async cancelPayment(\n transactionId: string,\n reason: string | undefined,\n scope: { organizationId: string; tenantId: string },\n ): Promise<CancelResult> {\n const transaction = await findTransactionOrThrow(transactionId, scope)\n const { adapter, credentials } = await resolveAdapterAndCredentials(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n )\n\n const result = await adapter.cancel({\n sessionId: readProviderSessionId(transaction),\n reason,\n credentials,\n })\n\n transaction.unifiedStatus = result.status\n await em.flush()\n await emitStatusEvent(result.status, {\n transactionId: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n organizationId: transaction.organizationId,\n tenantId: transaction.tenantId,\n })\n await writeTransactionLog(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n transaction.id,\n 'info',\n 'Payment cancelled',\n {\n reason: reason ?? null,\n status: result.status,\n },\n )\n\n return result\n },\n\n async getPaymentStatus(transactionId: string, scope: { organizationId: string; tenantId: string }): Promise<GatewayPaymentStatus> {\n const transaction = await findTransactionOrThrow(transactionId, scope)\n const { adapter, credentials } = await resolveAdapterAndCredentials(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n )\n\n const status = await adapter.getStatus({\n sessionId: readProviderSessionId(transaction),\n credentials,\n })\n\n if (status.status !== transaction.unifiedStatus && isValidTransition(transaction.unifiedStatus as UnifiedPaymentStatus, status.status)) {\n const previousStatus = transaction.unifiedStatus\n transaction.unifiedStatus = status.status\n transaction.gatewayStatus = status.status\n transaction.gatewayMetadata = { ...transaction.gatewayMetadata, statusResult: status.providerData ?? null }\n transaction.lastPolledAt = new Date()\n await em.flush()\n await emitStatusEvent(status.status, {\n transactionId: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n previousStatus,\n organizationId: transaction.organizationId,\n tenantId: transaction.tenantId,\n })\n await writeTransactionLog(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n transaction.id,\n 'info',\n 'Payment status updated by poller',\n {\n previousStatus,\n nextStatus: status.status,\n },\n )\n }\n\n return status\n },\n\n async syncTransactionStatus(transactionId: string, update: {\n unifiedStatus: UnifiedPaymentStatus\n providerStatus?: string\n providerData?: Record<string, unknown>\n webhookEvent?: {\n eventType: string\n idempotencyKey: string\n processed: boolean\n receivedAt?: string\n }\n }, scope: { organizationId: string; tenantId: string }): Promise<void> {\n const transaction = await findTransactionOrThrow(transactionId, scope)\n const currentStatus = transaction.unifiedStatus as UnifiedPaymentStatus\n const canTransition = isValidTransition(currentStatus, update.unifiedStatus)\n const shouldApplyStatus = canTransition && update.unifiedStatus !== currentStatus\n const previousStatus = transaction.unifiedStatus\n if (shouldApplyStatus) {\n transaction.unifiedStatus = update.unifiedStatus\n }\n if (update.providerStatus) {\n transaction.gatewayStatus = update.providerStatus\n }\n if (update.providerData) {\n transaction.gatewayMetadata = { ...transaction.gatewayMetadata, ...update.providerData }\n }\n if (update.webhookEvent) {\n const webhookLog = Array.isArray(transaction.webhookLog) ? transaction.webhookLog : []\n webhookLog.push({\n eventType: update.webhookEvent.eventType,\n receivedAt: update.webhookEvent.receivedAt ?? new Date().toISOString(),\n idempotencyKey: update.webhookEvent.idempotencyKey,\n unifiedStatus: update.unifiedStatus,\n processed: update.webhookEvent.processed,\n })\n transaction.webhookLog = webhookLog\n }\n transaction.lastWebhookAt = new Date()\n await em.flush()\n if (shouldApplyStatus) {\n await emitStatusEvent(update.unifiedStatus, {\n transactionId: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n previousStatus,\n organizationId: transaction.organizationId,\n tenantId: transaction.tenantId,\n })\n }\n await writeTransactionLog(\n transaction.providerKey,\n { organizationId: transaction.organizationId, tenantId: transaction.tenantId },\n transaction.id,\n shouldApplyStatus ? 'info' : 'warn',\n shouldApplyStatus ? 'Payment status synchronized from webhook' : 'Webhook received with no status transition',\n {\n previousStatus,\n nextStatus: update.unifiedStatus,\n providerStatus: update.providerStatus ?? null,\n eventType: update.webhookEvent?.eventType ?? null,\n idempotencyKey: update.webhookEvent?.idempotencyKey ?? null,\n },\n )\n },\n\n async findTransaction(id: string, scope: { organizationId: string; tenantId: string }): Promise<GatewayTransaction | null> {\n return findOneWithDecryption(\n em,\n GatewayTransaction,\n {\n id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n },\n\n async findTransactionBySessionId(\n providerSessionId: string,\n scope: { organizationId: string; tenantId: string },\n providerKey?: string,\n ): Promise<GatewayTransaction | null> {\n return findOneWithDecryption(\n em,\n GatewayTransaction,\n {\n providerSessionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n ...(providerKey ? { providerKey } : {}),\n },\n undefined,\n scope,\n )\n },\n\n async listTransactionsForStatusPolling(scope?: {\n organizationId?: string\n tenantId?: string\n providerKey?: string\n limit?: number\n }): Promise<GatewayTransaction[]> {\n const where: Record<string, unknown> = {\n unifiedStatus: { $in: ['pending', 'authorized', 'partially_captured'] },\n deletedAt: null,\n }\n if (scope?.organizationId) where.organizationId = scope.organizationId\n if (scope?.tenantId) where.tenantId = scope.tenantId\n if (scope?.providerKey) where.providerKey = scope.providerKey\n\n return findWithDecryption(\n em,\n GatewayTransaction,\n where,\n {\n orderBy: { updatedAt: 'asc' },\n limit: scope?.limit ?? 100,\n },\n scope,\n )\n },\n }\n}\n\nexport type PaymentGatewayService = ReturnType<typeof createPaymentGatewayService>\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ import { createQueue } from "@open-mercato/queue";
2
+ import { getRedisUrl } from "@open-mercato/shared/lib/redis/connection";
3
+ const queues = /* @__PURE__ */ new Map();
4
+ function getPaymentGatewayQueue(queueName) {
5
+ const existing = queues.get(queueName);
6
+ if (existing) return existing;
7
+ const created = process.env.QUEUE_STRATEGY === "async" ? createQueue(queueName, "async", {
8
+ connection: { url: getRedisUrl("QUEUE") },
9
+ concurrency: Math.max(1, Number.parseInt(process.env.PAYMENT_GATEWAY_QUEUE_CONCURRENCY ?? "5", 10) || 5)
10
+ }) : createQueue(queueName, "local");
11
+ queues.set(queueName, created);
12
+ return created;
13
+ }
14
+ export {
15
+ getPaymentGatewayQueue
16
+ };
17
+ //# sourceMappingURL=queue.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/payment_gateways/lib/queue.ts"],
4
+ "sourcesContent": ["import { createQueue, type Queue } from '@open-mercato/queue'\nimport { getRedisUrl } from '@open-mercato/shared/lib/redis/connection'\n\nconst queues = new Map<string, Queue<Record<string, unknown>>>()\n\nexport function getPaymentGatewayQueue(queueName: string): Queue<Record<string, unknown>> {\n const existing = queues.get(queueName)\n if (existing) return existing\n\n const created = process.env.QUEUE_STRATEGY === 'async'\n ? createQueue<Record<string, unknown>>(queueName, 'async', {\n connection: { url: getRedisUrl('QUEUE') },\n concurrency: Math.max(1, Number.parseInt(process.env.PAYMENT_GATEWAY_QUEUE_CONCURRENCY ?? '5', 10) || 5),\n })\n : createQueue<Record<string, unknown>>(queueName, 'local')\n\n queues.set(queueName, created)\n return created\n}\n"],
5
+ "mappings": "AAAA,SAAS,mBAA+B;AACxC,SAAS,mBAAmB;AAE5B,MAAM,SAAS,oBAAI,IAA4C;AAExD,SAAS,uBAAuB,WAAmD;AACxF,QAAM,WAAW,OAAO,IAAI,SAAS;AACrC,MAAI,SAAU,QAAO;AAErB,QAAM,UAAU,QAAQ,IAAI,mBAAmB,UAC3C,YAAqC,WAAW,SAAS;AAAA,IACzD,YAAY,EAAE,KAAK,YAAY,OAAO,EAAE;AAAA,IACxC,aAAa,KAAK,IAAI,GAAG,OAAO,SAAS,QAAQ,IAAI,qCAAqC,KAAK,EAAE,KAAK,CAAC;AAAA,EACzG,CAAC,IACC,YAAqC,WAAW,OAAO;AAE3D,SAAO,IAAI,WAAW,OAAO;AAC7B,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,29 @@
1
+ const VALID_TRANSITIONS = {
2
+ pending: ["authorized", "captured", "failed", "expired", "cancelled"],
3
+ authorized: ["captured", "partially_captured", "cancelled", "failed"],
4
+ captured: ["refunded", "partially_refunded"],
5
+ partially_captured: ["captured", "refunded", "partially_refunded", "cancelled"],
6
+ partially_refunded: ["refunded"]
7
+ // Terminal states: refunded, cancelled, failed, expired — no valid transitions out
8
+ };
9
+ const TERMINAL_STATUSES = /* @__PURE__ */ new Set([
10
+ "refunded",
11
+ "cancelled",
12
+ "failed",
13
+ "expired"
14
+ ]);
15
+ function isValidTransition(from, to) {
16
+ if (from === to) return false;
17
+ const allowed = VALID_TRANSITIONS[from];
18
+ if (!allowed) return false;
19
+ return allowed.includes(to);
20
+ }
21
+ function isTerminalStatus(status) {
22
+ return TERMINAL_STATUSES.has(status);
23
+ }
24
+ export {
25
+ TERMINAL_STATUSES,
26
+ isTerminalStatus,
27
+ isValidTransition
28
+ };
29
+ //# sourceMappingURL=status-machine.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/payment_gateways/lib/status-machine.ts"],
4
+ "sourcesContent": ["import type { UnifiedPaymentStatus } from '@open-mercato/shared/modules/payment_gateways/types'\n\nconst VALID_TRANSITIONS: Record<string, UnifiedPaymentStatus[]> = {\n pending: ['authorized', 'captured', 'failed', 'expired', 'cancelled'],\n authorized: ['captured', 'partially_captured', 'cancelled', 'failed'],\n captured: ['refunded', 'partially_refunded'],\n partially_captured: ['captured', 'refunded', 'partially_refunded', 'cancelled'],\n partially_refunded: ['refunded'],\n // Terminal states: refunded, cancelled, failed, expired \u2014 no valid transitions out\n}\n\nexport const TERMINAL_STATUSES: Set<UnifiedPaymentStatus> = new Set([\n 'refunded',\n 'cancelled',\n 'failed',\n 'expired',\n])\n\nexport function isValidTransition(from: UnifiedPaymentStatus, to: UnifiedPaymentStatus): boolean {\n if (from === to) return false\n const allowed = VALID_TRANSITIONS[from]\n if (!allowed) return false\n return allowed.includes(to)\n}\n\nexport function isTerminalStatus(status: UnifiedPaymentStatus): boolean {\n return TERMINAL_STATUSES.has(status)\n}\n"],
5
+ "mappings": "AAEA,MAAM,oBAA4D;AAAA,EAChE,SAAS,CAAC,cAAc,YAAY,UAAU,WAAW,WAAW;AAAA,EACpE,YAAY,CAAC,YAAY,sBAAsB,aAAa,QAAQ;AAAA,EACpE,UAAU,CAAC,YAAY,oBAAoB;AAAA,EAC3C,oBAAoB,CAAC,YAAY,YAAY,sBAAsB,WAAW;AAAA,EAC9E,oBAAoB,CAAC,UAAU;AAAA;AAEjC;AAEO,MAAM,oBAA+C,oBAAI,IAAI;AAAA,EAClE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,kBAAkB,MAA4B,IAAmC;AAC/F,MAAI,SAAS,GAAI,QAAO;AACxB,QAAM,UAAU,kBAAkB,IAAI;AACtC,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,QAAQ,SAAS,EAAE;AAC5B;AAEO,SAAS,iBAAiB,QAAuC;AACtE,SAAO,kBAAkB,IAAI,MAAM;AACrC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,88 @@
1
+ import { getGatewayAdapter } from "@open-mercato/shared/modules/payment_gateways/types";
2
+ import { claimWebhookProcessing, releaseWebhookClaim } from "./webhook-utils.js";
3
+ function readSessionIdFromEvent(event) {
4
+ const id = event.data.id;
5
+ if (typeof id === "string" && id.trim().length > 0) return id.trim();
6
+ const paymentIntent = event.data.payment_intent;
7
+ if (typeof paymentIntent === "string" && paymentIntent.trim().length > 0) return paymentIntent.trim();
8
+ return null;
9
+ }
10
+ function readScopeFromEvent(event) {
11
+ const metadata = event.data.metadata;
12
+ if (!metadata || typeof metadata !== "object") return null;
13
+ const metadataRecord = metadata;
14
+ const organizationId = typeof metadataRecord.organizationId === "string" ? metadataRecord.organizationId.trim() : "";
15
+ const tenantId = typeof metadataRecord.tenantId === "string" ? metadataRecord.tenantId.trim() : "";
16
+ if (!organizationId || !tenantId) return null;
17
+ return { organizationId, tenantId };
18
+ }
19
+ async function writeTransactionLog(integrationLogService, providerKey, scope, transactionId, level, message, payload) {
20
+ await integrationLogService.write({
21
+ integrationId: `gateway_${providerKey}`,
22
+ scopeEntityType: "payment_transaction",
23
+ scopeEntityId: transactionId,
24
+ level,
25
+ message,
26
+ payload: payload ?? null
27
+ }, scope);
28
+ }
29
+ async function processPaymentGatewayWebhookJob(deps, payload) {
30
+ const { em, paymentGatewayService, integrationLogService } = deps;
31
+ const { providerKey, event } = payload;
32
+ const scopedPayload = payload.scope ?? readScopeFromEvent(event);
33
+ let transaction = payload.transactionId && scopedPayload ? await paymentGatewayService.findTransaction(payload.transactionId, scopedPayload) : null;
34
+ if (!transaction) {
35
+ const sessionId = readSessionIdFromEvent(event);
36
+ if (sessionId && scopedPayload) {
37
+ transaction = await paymentGatewayService.findTransactionBySessionId(sessionId, scopedPayload, providerKey);
38
+ }
39
+ }
40
+ if (!transaction) return;
41
+ const scope = { organizationId: transaction.organizationId, tenantId: transaction.tenantId };
42
+ const claimed = await claimWebhookProcessing(em, event.idempotencyKey, providerKey, scope, event.eventType);
43
+ if (!claimed) {
44
+ await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, "info", "Duplicate payment gateway webhook skipped", {
45
+ eventType: event.eventType,
46
+ idempotencyKey: event.idempotencyKey
47
+ });
48
+ return;
49
+ }
50
+ try {
51
+ const adapter = getGatewayAdapter(providerKey);
52
+ if (!adapter) {
53
+ await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, "warn", "Missing payment gateway adapter for webhook event", {
54
+ providerKey,
55
+ eventType: event.eventType
56
+ });
57
+ return;
58
+ }
59
+ const providerStatus = typeof event.data.status === "string" ? event.data.status : "";
60
+ const unifiedStatus = adapter.mapStatus(providerStatus, event.eventType);
61
+ await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, "info", "Payment gateway webhook received", {
62
+ eventType: event.eventType,
63
+ providerStatus,
64
+ unifiedStatus
65
+ });
66
+ await paymentGatewayService.syncTransactionStatus(transaction.id, {
67
+ unifiedStatus,
68
+ providerStatus: event.eventType,
69
+ providerData: event.data,
70
+ webhookEvent: {
71
+ eventType: event.eventType,
72
+ idempotencyKey: event.idempotencyKey,
73
+ processed: true
74
+ }
75
+ }, scope);
76
+ await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, "info", "Payment gateway webhook processed", {
77
+ eventType: event.eventType,
78
+ unifiedStatus
79
+ });
80
+ } catch (error) {
81
+ await releaseWebhookClaim(em, event.idempotencyKey, providerKey, scope);
82
+ throw error;
83
+ }
84
+ }
85
+ export {
86
+ processPaymentGatewayWebhookJob
87
+ };
88
+ //# sourceMappingURL=webhook-processor.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/payment_gateways/lib/webhook-processor.ts"],
4
+ "sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { getGatewayAdapter, type WebhookEvent } from '@open-mercato/shared/modules/payment_gateways/types'\nimport type { IntegrationLogService } from '../../integrations/lib/log-service'\nimport type { PaymentGatewayService } from './gateway-service'\nimport { claimWebhookProcessing, releaseWebhookClaim } from './webhook-utils'\n\nexport type PaymentGatewayWebhookJobPayload = {\n providerKey: string\n event: WebhookEvent\n transactionId?: string | null\n scope?: {\n organizationId: string\n tenantId: string\n } | null\n}\n\ntype PaymentGatewayWebhookProcessorDeps = {\n em: EntityManager\n paymentGatewayService: PaymentGatewayService\n integrationLogService: IntegrationLogService\n}\n\nfunction readSessionIdFromEvent(event: WebhookEvent): string | null {\n const id = event.data.id\n if (typeof id === 'string' && id.trim().length > 0) return id.trim()\n const paymentIntent = event.data.payment_intent\n if (typeof paymentIntent === 'string' && paymentIntent.trim().length > 0) return paymentIntent.trim()\n return null\n}\n\nfunction readScopeFromEvent(event: WebhookEvent): { organizationId: string; tenantId: string } | null {\n const metadata = event.data.metadata\n if (!metadata || typeof metadata !== 'object') return null\n\n const metadataRecord = metadata as Record<string, unknown>\n const organizationId = typeof metadataRecord.organizationId === 'string'\n ? metadataRecord.organizationId.trim()\n : ''\n const tenantId = typeof metadataRecord.tenantId === 'string'\n ? metadataRecord.tenantId.trim()\n : ''\n\n if (!organizationId || !tenantId) return null\n return { organizationId, tenantId }\n}\n\nasync function writeTransactionLog(\n integrationLogService: IntegrationLogService,\n providerKey: string,\n scope: { organizationId: string; tenantId: string },\n transactionId: string,\n level: 'info' | 'warn' | 'error',\n message: string,\n payload?: Record<string, unknown>,\n) {\n await integrationLogService.write({\n integrationId: `gateway_${providerKey}`,\n scopeEntityType: 'payment_transaction',\n scopeEntityId: transactionId,\n level,\n message,\n payload: payload ?? null,\n }, scope)\n}\n\nexport async function processPaymentGatewayWebhookJob(\n deps: PaymentGatewayWebhookProcessorDeps,\n payload: PaymentGatewayWebhookJobPayload,\n): Promise<void> {\n const { em, paymentGatewayService, integrationLogService } = deps\n const { providerKey, event } = payload\n const scopedPayload = payload.scope ?? readScopeFromEvent(event)\n\n let transaction = payload.transactionId && scopedPayload\n ? await paymentGatewayService.findTransaction(payload.transactionId, scopedPayload)\n : null\n\n if (!transaction) {\n const sessionId = readSessionIdFromEvent(event)\n if (sessionId && scopedPayload) {\n transaction = await paymentGatewayService.findTransactionBySessionId(sessionId, scopedPayload, providerKey)\n }\n }\n if (!transaction) return\n\n const scope = { organizationId: transaction.organizationId, tenantId: transaction.tenantId }\n const claimed = await claimWebhookProcessing(em, event.idempotencyKey, providerKey, scope, event.eventType)\n if (!claimed) {\n await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, 'info', 'Duplicate payment gateway webhook skipped', {\n eventType: event.eventType,\n idempotencyKey: event.idempotencyKey,\n })\n return\n }\n\n try {\n const adapter = getGatewayAdapter(providerKey)\n if (!adapter) {\n await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, 'warn', 'Missing payment gateway adapter for webhook event', {\n providerKey,\n eventType: event.eventType,\n })\n return\n }\n\n const providerStatus = typeof event.data.status === 'string' ? event.data.status : ''\n const unifiedStatus = adapter.mapStatus(providerStatus, event.eventType)\n await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, 'info', 'Payment gateway webhook received', {\n eventType: event.eventType,\n providerStatus,\n unifiedStatus,\n })\n\n await paymentGatewayService.syncTransactionStatus(transaction.id, {\n unifiedStatus,\n providerStatus: event.eventType,\n providerData: event.data,\n webhookEvent: {\n eventType: event.eventType,\n idempotencyKey: event.idempotencyKey,\n processed: true,\n },\n }, scope)\n\n await writeTransactionLog(integrationLogService, providerKey, scope, transaction.id, 'info', 'Payment gateway webhook processed', {\n eventType: event.eventType,\n unifiedStatus,\n })\n } catch (error: unknown) {\n await releaseWebhookClaim(em, event.idempotencyKey, providerKey, scope)\n throw error\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,42 @@
1
+ import { UniqueConstraintViolationException } from "@mikro-orm/core";
2
+ import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
3
+ import { WebhookProcessedEvent } from "../data/entities.js";
4
+ async function claimWebhookProcessing(em, idempotencyKey, providerKey, scope, eventType) {
5
+ const record = em.create(WebhookProcessedEvent, {
6
+ idempotencyKey,
7
+ providerKey,
8
+ eventType,
9
+ organizationId: scope.organizationId,
10
+ tenantId: scope.tenantId
11
+ });
12
+ try {
13
+ await em.persistAndFlush(record);
14
+ return true;
15
+ } catch (error) {
16
+ if (error instanceof UniqueConstraintViolationException) {
17
+ return false;
18
+ }
19
+ throw error;
20
+ }
21
+ }
22
+ async function releaseWebhookClaim(em, idempotencyKey, providerKey, scope) {
23
+ const existing = await findOneWithDecryption(
24
+ em,
25
+ WebhookProcessedEvent,
26
+ {
27
+ idempotencyKey,
28
+ providerKey,
29
+ organizationId: scope.organizationId,
30
+ tenantId: scope.tenantId
31
+ },
32
+ void 0,
33
+ scope
34
+ );
35
+ if (!existing) return;
36
+ await em.removeAndFlush(existing);
37
+ }
38
+ export {
39
+ claimWebhookProcessing,
40
+ releaseWebhookClaim
41
+ };
42
+ //# sourceMappingURL=webhook-utils.js.map