@easypayment/medusa-payment-paypal 0.7.4

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 (268) hide show
  1. package/.medusa/server/src/admin/index.js +1267 -0
  2. package/.medusa/server/src/admin/index.mjs +1268 -0
  3. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts +3 -0
  4. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -0
  5. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js +18 -0
  6. package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js.map +1 -0
  7. package/.medusa/server/src/api/admin/paypal/disconnect/route.d.ts +3 -0
  8. package/.medusa/server/src/api/admin/paypal/disconnect/route.d.ts.map +1 -0
  9. package/.medusa/server/src/api/admin/paypal/disconnect/route.js +9 -0
  10. package/.medusa/server/src/api/admin/paypal/disconnect/route.js.map +1 -0
  11. package/.medusa/server/src/api/admin/paypal/environment/route.d.ts +4 -0
  12. package/.medusa/server/src/api/admin/paypal/environment/route.d.ts.map +1 -0
  13. package/.medusa/server/src/api/admin/paypal/environment/route.js +23 -0
  14. package/.medusa/server/src/api/admin/paypal/environment/route.js.map +1 -0
  15. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts +4 -0
  16. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts.map +1 -0
  17. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js +31 -0
  18. package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js.map +1 -0
  19. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts +4 -0
  20. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.d.ts.map +1 -0
  21. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js +35 -0
  22. package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js.map +1 -0
  23. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts +3 -0
  24. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.d.ts.map +1 -0
  25. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js +19 -0
  26. package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js.map +1 -0
  27. package/.medusa/server/src/api/admin/paypal/save-credentials/route.d.ts +3 -0
  28. package/.medusa/server/src/api/admin/paypal/save-credentials/route.d.ts.map +1 -0
  29. package/.medusa/server/src/api/admin/paypal/save-credentials/route.js +17 -0
  30. package/.medusa/server/src/api/admin/paypal/save-credentials/route.js.map +1 -0
  31. package/.medusa/server/src/api/admin/paypal/settings/route.d.ts +4 -0
  32. package/.medusa/server/src/api/admin/paypal/settings/route.d.ts.map +1 -0
  33. package/.medusa/server/src/api/admin/paypal/settings/route.js +14 -0
  34. package/.medusa/server/src/api/admin/paypal/settings/route.js.map +1 -0
  35. package/.medusa/server/src/api/admin/paypal/status/route.d.ts +3 -0
  36. package/.medusa/server/src/api/admin/paypal/status/route.d.ts.map +1 -0
  37. package/.medusa/server/src/api/admin/paypal/status/route.js +11 -0
  38. package/.medusa/server/src/api/admin/paypal/status/route.js.map +1 -0
  39. package/.medusa/server/src/api/middlewares.d.ts +3 -0
  40. package/.medusa/server/src/api/middlewares.d.ts.map +1 -0
  41. package/.medusa/server/src/api/middlewares.js +16 -0
  42. package/.medusa/server/src/api/middlewares.js.map +1 -0
  43. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts +3 -0
  44. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -0
  45. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js +43 -0
  46. package/.medusa/server/src/api/store/payment-collections/[id]/payment-sessions/route.js.map +1 -0
  47. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts +3 -0
  48. package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -0
  49. package/.medusa/server/src/api/store/paypal/capture-order/route.js +204 -0
  50. package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -0
  51. package/.medusa/server/src/api/store/paypal/config/route.d.ts +3 -0
  52. package/.medusa/server/src/api/store/paypal/config/route.d.ts.map +1 -0
  53. package/.medusa/server/src/api/store/paypal/config/route.js +77 -0
  54. package/.medusa/server/src/api/store/paypal/config/route.js.map +1 -0
  55. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts +3 -0
  56. package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -0
  57. package/.medusa/server/src/api/store/paypal/create-order/route.js +361 -0
  58. package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -0
  59. package/.medusa/server/src/api/store/paypal/settings/route.d.ts +3 -0
  60. package/.medusa/server/src/api/store/paypal/settings/route.d.ts.map +1 -0
  61. package/.medusa/server/src/api/store/paypal/settings/route.js +20 -0
  62. package/.medusa/server/src/api/store/paypal/settings/route.js.map +1 -0
  63. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts +3 -0
  64. package/.medusa/server/src/api/store/paypal/webhook/route.d.ts.map +1 -0
  65. package/.medusa/server/src/api/store/paypal/webhook/route.js +250 -0
  66. package/.medusa/server/src/api/store/paypal/webhook/route.js.map +1 -0
  67. package/.medusa/server/src/api/store/paypal-complete/route.d.ts +3 -0
  68. package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -0
  69. package/.medusa/server/src/api/store/paypal-complete/route.js +76 -0
  70. package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -0
  71. package/.medusa/server/src/index.d.ts +2 -0
  72. package/.medusa/server/src/index.d.ts.map +1 -0
  73. package/.medusa/server/src/index.js +9 -0
  74. package/.medusa/server/src/index.js.map +1 -0
  75. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts +7 -0
  76. package/.medusa/server/src/jobs/paypal-webhook-retry.d.ts.map +1 -0
  77. package/.medusa/server/src/jobs/paypal-webhook-retry.js +132 -0
  78. package/.medusa/server/src/jobs/paypal-webhook-retry.js.map +1 -0
  79. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.d.ts +15 -0
  80. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.d.ts.map +1 -0
  81. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js +67 -0
  82. package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js.map +1 -0
  83. package/.medusa/server/src/modules/paypal/index.d.ts +64 -0
  84. package/.medusa/server/src/modules/paypal/index.d.ts.map +1 -0
  85. package/.medusa/server/src/modules/paypal/index.js +13 -0
  86. package/.medusa/server/src/modules/paypal/index.js.map +1 -0
  87. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.d.ts +6 -0
  88. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.d.ts.map +1 -0
  89. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.js +36 -0
  90. package/.medusa/server/src/modules/paypal/migrations/20260115120000_create_paypal_connection.js.map +1 -0
  91. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.d.ts +6 -0
  92. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.d.ts.map +1 -0
  93. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.js +25 -0
  94. package/.medusa/server/src/modules/paypal/migrations/20260123090000_create_paypal_settings.js.map +1 -0
  95. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.d.ts +6 -0
  96. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.d.ts.map +1 -0
  97. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.js +32 -0
  98. package/.medusa/server/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.js.map +1 -0
  99. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.d.ts +6 -0
  100. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.d.ts.map +1 -0
  101. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.js +30 -0
  102. package/.medusa/server/src/modules/paypal/migrations/20260401090000_create_paypal_metric.js.map +1 -0
  103. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.d.ts +6 -0
  104. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.d.ts.map +1 -0
  105. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.js +34 -0
  106. package/.medusa/server/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.js.map +1 -0
  107. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.d.ts +6 -0
  108. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.d.ts.map +1 -0
  109. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.js +28 -0
  110. package/.medusa/server/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.js.map +1 -0
  111. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.d.ts +6 -0
  112. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.d.ts.map +1 -0
  113. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.js +29 -0
  114. package/.medusa/server/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.js.map +1 -0
  115. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.d.ts +6 -0
  116. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.d.ts.map +1 -0
  117. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.js +14 -0
  118. package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.js.map +1 -0
  119. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.d.ts +6 -0
  120. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.d.ts.map +1 -0
  121. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.js +14 -0
  122. package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.js.map +1 -0
  123. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.d.ts +6 -0
  124. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.d.ts.map +1 -0
  125. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.js +14 -0
  126. package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.js.map +1 -0
  127. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.d.ts +6 -0
  128. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.d.ts.map +1 -0
  129. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.js +20 -0
  130. package/.medusa/server/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.js.map +1 -0
  131. package/.medusa/server/src/modules/paypal/models/paypal_connection.d.ts +16 -0
  132. package/.medusa/server/src/modules/paypal/models/paypal_connection.d.ts.map +1 -0
  133. package/.medusa/server/src/modules/paypal/models/paypal_connection.js +19 -0
  134. package/.medusa/server/src/modules/paypal/models/paypal_connection.js.map +1 -0
  135. package/.medusa/server/src/modules/paypal/models/paypal_metric.d.ts +7 -0
  136. package/.medusa/server/src/modules/paypal/models/paypal_metric.d.ts.map +1 -0
  137. package/.medusa/server/src/modules/paypal/models/paypal_metric.js +10 -0
  138. package/.medusa/server/src/modules/paypal/models/paypal_metric.js.map +1 -0
  139. package/.medusa/server/src/modules/paypal/models/paypal_settings.d.ts +6 -0
  140. package/.medusa/server/src/modules/paypal/models/paypal_settings.d.ts.map +1 -0
  141. package/.medusa/server/src/modules/paypal/models/paypal_settings.js +9 -0
  142. package/.medusa/server/src/modules/paypal/models/paypal_settings.js.map +1 -0
  143. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.d.ts +17 -0
  144. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.d.ts.map +1 -0
  145. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js +20 -0
  146. package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js.map +1 -0
  147. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts +32 -0
  148. package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -0
  149. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +625 -0
  150. package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -0
  151. package/.medusa/server/src/modules/paypal/payment-provider/index.d.ts +6 -0
  152. package/.medusa/server/src/modules/paypal/payment-provider/index.d.ts.map +1 -0
  153. package/.medusa/server/src/modules/paypal/payment-provider/index.js +18 -0
  154. package/.medusa/server/src/modules/paypal/payment-provider/index.js.map +1 -0
  155. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts +39 -0
  156. package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -0
  157. package/.medusa/server/src/modules/paypal/payment-provider/service.js +869 -0
  158. package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -0
  159. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.d.ts +3 -0
  160. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.d.ts.map +1 -0
  161. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js +74 -0
  162. package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js.map +1 -0
  163. package/.medusa/server/src/modules/paypal/service.d.ts +266 -0
  164. package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -0
  165. package/.medusa/server/src/modules/paypal/service.js +1149 -0
  166. package/.medusa/server/src/modules/paypal/service.js.map +1 -0
  167. package/.medusa/server/src/modules/paypal/types/config.d.ts +12 -0
  168. package/.medusa/server/src/modules/paypal/types/config.d.ts.map +1 -0
  169. package/.medusa/server/src/modules/paypal/types/config.js +24 -0
  170. package/.medusa/server/src/modules/paypal/types/config.js.map +1 -0
  171. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts +3 -0
  172. package/.medusa/server/src/modules/paypal/utils/amounts.d.ts.map +1 -0
  173. package/.medusa/server/src/modules/paypal/utils/amounts.js +40 -0
  174. package/.medusa/server/src/modules/paypal/utils/amounts.js.map +1 -0
  175. package/.medusa/server/src/modules/paypal/utils/currencies.d.ts +19 -0
  176. package/.medusa/server/src/modules/paypal/utils/currencies.d.ts.map +1 -0
  177. package/.medusa/server/src/modules/paypal/utils/currencies.js +69 -0
  178. package/.medusa/server/src/modules/paypal/utils/currencies.js.map +1 -0
  179. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts +10 -0
  180. package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts.map +1 -0
  181. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js +30 -0
  182. package/.medusa/server/src/modules/paypal/utils/paypal-auth.js.map +1 -0
  183. package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts +5 -0
  184. package/.medusa/server/src/modules/paypal/utils/provider-ids.d.ts.map +1 -0
  185. package/.medusa/server/src/modules/paypal/utils/provider-ids.js +16 -0
  186. package/.medusa/server/src/modules/paypal/utils/provider-ids.js.map +1 -0
  187. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts +29 -0
  188. package/.medusa/server/src/modules/paypal/webhook-processor.d.ts.map +1 -0
  189. package/.medusa/server/src/modules/paypal/webhook-processor.js +267 -0
  190. package/.medusa/server/src/modules/paypal/webhook-processor.js.map +1 -0
  191. package/.medusa/server/src/providers/paypal/index.d.ts +5 -0
  192. package/.medusa/server/src/providers/paypal/index.d.ts.map +1 -0
  193. package/.medusa/server/src/providers/paypal/index.js +10 -0
  194. package/.medusa/server/src/providers/paypal/index.js.map +1 -0
  195. package/.medusa/server/src/providers/paypal_card/index.d.ts +5 -0
  196. package/.medusa/server/src/providers/paypal_card/index.d.ts.map +1 -0
  197. package/.medusa/server/src/providers/paypal_card/index.js +10 -0
  198. package/.medusa/server/src/providers/paypal_card/index.js.map +1 -0
  199. package/.medusa/server/src/subscribers/paypal-order-invoice.d.ts +6 -0
  200. package/.medusa/server/src/subscribers/paypal-order-invoice.d.ts.map +1 -0
  201. package/.medusa/server/src/subscribers/paypal-order-invoice.js +124 -0
  202. package/.medusa/server/src/subscribers/paypal-order-invoice.js.map +1 -0
  203. package/LICENSE +21 -0
  204. package/README.md +172 -0
  205. package/package.json +80 -0
  206. package/src/admin/index.ts +7 -0
  207. package/src/admin/routes/settings/paypal/_components/Tabs.tsx +48 -0
  208. package/src/admin/routes/settings/paypal/_components/Toast.tsx +51 -0
  209. package/src/admin/routes/settings/paypal/additional-settings/page.tsx +199 -0
  210. package/src/admin/routes/settings/paypal/advanced-card-payments/page.tsx +183 -0
  211. package/src/admin/routes/settings/paypal/apple-pay/page.tsx +5 -0
  212. package/src/admin/routes/settings/paypal/connection/page.tsx +699 -0
  213. package/src/admin/routes/settings/paypal/google-pay/page.tsx +5 -0
  214. package/src/admin/routes/settings/paypal/page.tsx +13 -0
  215. package/src/admin/routes/settings/paypal/pay-later-messaging/page.tsx +5 -0
  216. package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +351 -0
  217. package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +24 -0
  218. package/src/api/admin/paypal/disconnect/route.ts +8 -0
  219. package/src/api/admin/paypal/environment/route.ts +25 -0
  220. package/src/api/admin/paypal/onboard-complete/route.ts +34 -0
  221. package/src/api/admin/paypal/onboarding-link/route.ts +45 -0
  222. package/src/api/admin/paypal/onboarding-status/route.ts +17 -0
  223. package/src/api/admin/paypal/save-credentials/route.ts +22 -0
  224. package/src/api/admin/paypal/settings/route.ts +14 -0
  225. package/src/api/admin/paypal/status/route.ts +12 -0
  226. package/src/api/middlewares.ts +14 -0
  227. package/src/api/store/payment-collections/[id]/payment-sessions/route.ts +56 -0
  228. package/src/api/store/paypal/capture-order/route.ts +265 -0
  229. package/src/api/store/paypal/config/route.ts +100 -0
  230. package/src/api/store/paypal/create-order/route.ts +449 -0
  231. package/src/api/store/paypal/settings/route.ts +19 -0
  232. package/src/api/store/paypal/webhook/route.ts +325 -0
  233. package/src/api/store/paypal-complete/route.ts +95 -0
  234. package/src/index.ts +1 -0
  235. package/src/jobs/paypal-webhook-retry.ts +149 -0
  236. package/src/modules/paypal/clients/paypal-seller.client.ts +62 -0
  237. package/src/modules/paypal/index.ts +8 -0
  238. package/src/modules/paypal/migrations/20260115120000_create_paypal_connection.ts +33 -0
  239. package/src/modules/paypal/migrations/20260123090000_create_paypal_settings.ts +22 -0
  240. package/src/modules/paypal/migrations/20260201090000_create_paypal_webhook_event.ts +29 -0
  241. package/src/modules/paypal/migrations/20260401090000_create_paypal_metric.ts +27 -0
  242. package/src/modules/paypal/migrations/20260701090000_add_paypal_webhook_event_processing.ts +31 -0
  243. package/src/modules/paypal/migrations/20261101090000_remove_paypal_reconciliation_status.ts +25 -0
  244. package/src/modules/paypal/migrations/20261201090000_remove_paypal_audit_log.ts +26 -0
  245. package/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.ts +11 -0
  246. package/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.ts +11 -0
  247. package/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.ts +11 -0
  248. package/src/modules/paypal/migrations/20270201000000_add_webhook_dead_letter.ts +17 -0
  249. package/src/modules/paypal/models/paypal_connection.ts +23 -0
  250. package/src/modules/paypal/models/paypal_metric.ts +9 -0
  251. package/src/modules/paypal/models/paypal_settings.ts +8 -0
  252. package/src/modules/paypal/models/paypal_webhook_event.ts +19 -0
  253. package/src/modules/paypal/payment-provider/README.md +22 -0
  254. package/src/modules/paypal/payment-provider/card-service.ts +767 -0
  255. package/src/modules/paypal/payment-provider/index.ts +15 -0
  256. package/src/modules/paypal/payment-provider/service.ts +1039 -0
  257. package/src/modules/paypal/payment-provider/webhook-utils.ts +88 -0
  258. package/src/modules/paypal/service.ts +1416 -0
  259. package/src/modules/paypal/types/config.ts +33 -0
  260. package/src/modules/paypal/utils/amounts.ts +41 -0
  261. package/src/modules/paypal/utils/currencies.ts +84 -0
  262. package/src/modules/paypal/utils/paypal-auth.ts +31 -0
  263. package/src/modules/paypal/utils/provider-ids.ts +15 -0
  264. package/src/modules/paypal/webhook-processor.ts +363 -0
  265. package/src/providers/paypal/index.ts +8 -0
  266. package/src/providers/paypal_card/index.ts +8 -0
  267. package/src/subscribers/paypal-order-invoice.ts +171 -0
  268. package/tsconfig.json +31 -0
@@ -0,0 +1,325 @@
1
+ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
2
+ import type PayPalModuleService from "../../../../modules/paypal/service"
3
+ import {
4
+ computeNextRetryAt,
5
+ isAllowedEventType,
6
+ isRetryableError,
7
+ normalizeEventVersion,
8
+ processPayPalWebhookEvent,
9
+ } from "../../../../modules/paypal/webhook-processor"
10
+
11
+ const REPLAY_WINDOW_MINUTES = (() => {
12
+ const v = Number(process.env.PAYPAL_WEBHOOK_REPLAY_WINDOW_MINUTES)
13
+ return Number.isFinite(v) && v > 0 ? v : 60
14
+ })()
15
+
16
+ function getHeader(
17
+ headers: Record<string, string | string[] | undefined>,
18
+ name: string
19
+ ): string | undefined {
20
+ const direct = headers[name]
21
+ if (Array.isArray(direct)) return direct[0]
22
+ if (typeof direct === "string") return direct
23
+ const lower = name.toLowerCase()
24
+ const key = Object.keys(headers).find((h) => h.toLowerCase() === lower)
25
+ if (!key) return undefined
26
+ const val = headers[key]
27
+ return Array.isArray(val) ? val[0] : val
28
+ }
29
+
30
+ interface ValidationFail {
31
+ ok: false
32
+ status: number
33
+ message: string
34
+ }
35
+
36
+ interface ValidationPass {
37
+ ok: true
38
+ eventId: string
39
+ eventType: string
40
+ transmissionId: string | null
41
+ transmissionTime: Date | null
42
+ }
43
+
44
+ function validateRequest(req: MedusaRequest): ValidationFail | ValidationPass {
45
+ const payload = (req.body || {}) as Record<string, any>
46
+ const eventId = String(payload?.id || payload?.event_id || "").trim()
47
+ const eventType = String(payload?.event_type || payload?.eventType || "").trim()
48
+
49
+ if (!eventId || !eventType) {
50
+ return { ok: false, status: 400, message: "Missing required fields: id and event_type" }
51
+ }
52
+
53
+ const transmissionTimeHeader = getHeader(req.headers, "paypal-transmission-time")
54
+ if (!transmissionTimeHeader) {
55
+ return {
56
+ ok: false,
57
+ status: 400,
58
+ message: "Missing required header: paypal-transmission-time",
59
+ }
60
+ }
61
+
62
+ const transmissionMs = Date.parse(transmissionTimeHeader)
63
+ if (!Number.isFinite(transmissionMs)) {
64
+ return {
65
+ ok: false,
66
+ status: 400,
67
+ message: "Invalid paypal-transmission-time header value",
68
+ }
69
+ }
70
+
71
+ const ageMs = Math.abs(Date.now() - transmissionMs)
72
+ if (ageMs > REPLAY_WINDOW_MINUTES * 60 * 1000) {
73
+ return {
74
+ ok: false,
75
+ status: 400,
76
+ message: `Webhook rejected: outside ${REPLAY_WINDOW_MINUTES}-minute replay window`,
77
+ }
78
+ }
79
+
80
+ return {
81
+ ok: true,
82
+ eventId,
83
+ eventType,
84
+ transmissionId: getHeader(req.headers, "paypal-transmission-id") || null,
85
+ transmissionTime: new Date(transmissionMs),
86
+ }
87
+ }
88
+
89
+ function resolveWebhookId(
90
+ environment: string,
91
+ settings: Record<string, unknown>
92
+ ): string | undefined {
93
+ const ids = (settings?.webhook_ids || {}) as Record<string, string | undefined>
94
+ if (environment === "live") {
95
+ return (
96
+ ids.live ||
97
+ (settings?.webhook_id_live as string) ||
98
+ process.env.PAYPAL_WEBHOOK_ID_LIVE
99
+ )
100
+ }
101
+ return (
102
+ ids.sandbox ||
103
+ (settings?.webhook_id_sandbox as string) ||
104
+ process.env.PAYPAL_WEBHOOK_ID_SANDBOX
105
+ )
106
+ }
107
+
108
+ async function verifyWebhookSignature(
109
+ paypal: PayPalModuleService,
110
+ environment: string,
111
+ body: Record<string, unknown>,
112
+ headers: Record<string, string | string[] | undefined>
113
+ ): Promise<void> {
114
+ const settings = await paypal.getSettings().catch(() => ({ data: {} }))
115
+ const webhookId = resolveWebhookId(
116
+ environment,
117
+ (settings?.data as Record<string, unknown>) || {}
118
+ )
119
+
120
+ if (!webhookId) {
121
+ throw new Error(
122
+ `PayPal webhook ID not configured for environment "${environment}". Set PAYPAL_WEBHOOK_ID_${environment.toUpperCase()} or configure it in admin settings.`
123
+ )
124
+ }
125
+
126
+ const base =
127
+ environment === "live"
128
+ ? "https://api-m.paypal.com"
129
+ : "https://api-m.sandbox.paypal.com"
130
+
131
+ const accessToken = await paypal.getAppAccessToken()
132
+
133
+ const verifyPayload = {
134
+ auth_algo: getHeader(headers, "paypal-auth-algo"),
135
+ cert_url: getHeader(headers, "paypal-cert-url"),
136
+ transmission_id: getHeader(headers, "paypal-transmission-id"),
137
+ transmission_sig: getHeader(headers, "paypal-transmission-sig"),
138
+ transmission_time: getHeader(headers, "paypal-transmission-time"),
139
+ webhook_id: webhookId,
140
+ webhook_event: body,
141
+ }
142
+
143
+ const missing = Object.entries(verifyPayload)
144
+ .filter(([k, v]) => k !== "webhook_id" && k !== "webhook_event" && !v)
145
+ .map(([k]) => k)
146
+
147
+ if (missing.length > 0) {
148
+ throw new Error(`Missing required PayPal webhook headers: ${missing.join(", ")}`)
149
+ }
150
+
151
+ const resp = await fetch(`${base}/v1/notifications/verify-webhook-signature`, {
152
+ method: "POST",
153
+ headers: {
154
+ Authorization: `Bearer ${accessToken}`,
155
+ "Content-Type": "application/json",
156
+ },
157
+ body: JSON.stringify(verifyPayload),
158
+ })
159
+
160
+ const json = await resp.json().catch(() => ({}))
161
+ const debugId = resp.headers.get("paypal-debug-id") || json?.debug_id
162
+
163
+ if (!resp.ok) {
164
+ throw new Error(
165
+ `PayPal signature verification API error (${resp.status}): ${JSON.stringify(json)}` +
166
+ (debugId ? ` debug_id=${debugId}` : "")
167
+ )
168
+ }
169
+ if (json?.verification_status !== "VERIFIED") {
170
+ throw new Error(
171
+ `PayPal webhook signature not verified. Status: ${json?.verification_status}` +
172
+ (debugId ? ` debug_id=${debugId}` : "")
173
+ )
174
+ }
175
+ }
176
+
177
+ export async function POST(req: MedusaRequest, res: MedusaResponse) {
178
+ const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
179
+
180
+ const validation = validateRequest(req)
181
+ if (!validation.ok) {
182
+ console.warn("[PayPal] webhook: validation failed:", validation.message)
183
+ return res.status(validation.status).json({ message: validation.message })
184
+ }
185
+
186
+ const { eventId, eventType, transmissionId, transmissionTime } = validation
187
+ const payload = (req.body || {}) as Record<string, any>
188
+
189
+ if (transmissionId) {
190
+ try {
191
+ const existing = await paypal.listPayPalWebhookEvents({ transmission_id: transmissionId })
192
+ if ((existing || []).length > 0) {
193
+ console.info("[PayPal] webhook: duplicate transmission_id", {
194
+ transmissionId,
195
+ eventId,
196
+ })
197
+ return res.json({ ok: true, duplicate: true })
198
+ }
199
+ } catch (e: any) {
200
+ console.warn("[PayPal] webhook: transmission_id dedup check failed:", e?.message)
201
+ }
202
+ }
203
+
204
+ try {
205
+ const creds = await paypal.getActiveCredentials()
206
+ await verifyWebhookSignature(paypal, creds.environment, payload, req.headers)
207
+ } catch (e: any) {
208
+ console.error("[PayPal] webhook: signature verification failed:", e?.message)
209
+ return res
210
+ .status(401)
211
+ .json({ message: e?.message || "Webhook signature verification failed" })
212
+ }
213
+
214
+ const eventVersion = normalizeEventVersion(payload)
215
+ let recordId: string | null = null
216
+
217
+ try {
218
+ const recordResult = await paypal.createWebhookEventRecord({
219
+ event_id: eventId,
220
+ event_type: eventType,
221
+ payload,
222
+ event_version: eventVersion,
223
+ transmission_id: transmissionId,
224
+ transmission_time: transmissionTime,
225
+ status: "processing",
226
+ attempt_count: 1,
227
+ })
228
+
229
+ if (!recordResult.created) {
230
+ console.info("[PayPal] webhook: duplicate event_id", { eventId, eventType })
231
+ return res.json({ ok: true, duplicate: true })
232
+ }
233
+
234
+ recordId = recordResult.event?.id ?? null
235
+ } catch (e: any) {
236
+ console.error("[PayPal] webhook: failed to create DB record:", e?.message)
237
+ return res.status(500).json({ message: "Failed to record webhook event" })
238
+ }
239
+
240
+ if (!isAllowedEventType(eventType)) {
241
+ console.info("[PayPal] webhook: unsupported event type, ignoring", { eventType })
242
+ await paypal.recordAuditEvent("webhook_unsupported_event", {
243
+ event_id: eventId,
244
+ event_type: eventType,
245
+ })
246
+ if (recordId) {
247
+ await paypal
248
+ .updateWebhookEventRecord({
249
+ id: recordId,
250
+ status: "ignored",
251
+ processed_at: new Date(),
252
+ })
253
+ .catch(() => {})
254
+ }
255
+ return res.json({ ok: true, ignored: true })
256
+ }
257
+
258
+ try {
259
+ const processed = await processPayPalWebhookEvent(req.scope, { eventType, payload })
260
+
261
+ if (recordId) {
262
+ await paypal
263
+ .updateWebhookEventRecord({
264
+ id: recordId,
265
+ status: "processed",
266
+ processed_at: new Date(),
267
+ resource_id:
268
+ processed.refundId || processed.captureId || processed.orderId || null,
269
+ })
270
+ .catch(() => {})
271
+ }
272
+
273
+ console.info("[PayPal] webhook: processed", {
274
+ event_id: eventId,
275
+ event_type: eventType,
276
+ order_id: processed.orderId,
277
+ capture_id: processed.captureId,
278
+ refund_id: processed.refundId,
279
+ cart_id: processed.cartId,
280
+ session_updated: processed.sessionUpdated,
281
+ })
282
+
283
+ await paypal.recordMetric("webhook_success").catch(() => {})
284
+ return res.json({ ok: true })
285
+ } catch (e: any) {
286
+ console.error("[PayPal] webhook: processing failed", {
287
+ event_id: eventId,
288
+ event_type: eventType,
289
+ error: e?.message,
290
+ })
291
+
292
+ const retryable = isRetryableError(e)
293
+ const nextStatus = retryable ? "failed" : "dead_letter"
294
+
295
+ if (recordId) {
296
+ await paypal
297
+ .updateWebhookEventRecord({
298
+ id: recordId,
299
+ status: nextStatus,
300
+ attempt_count: 1,
301
+ next_retry_at: retryable ? computeNextRetryAt(1) : null,
302
+ last_error: e?.message || String(e),
303
+ })
304
+ .catch(() => {})
305
+ }
306
+
307
+ await paypal
308
+ .recordAuditEvent("webhook_processing_failed", {
309
+ event_id: eventId,
310
+ event_type: eventType,
311
+ retryable,
312
+ message: e?.message || String(e),
313
+ })
314
+ .catch(() => {})
315
+
316
+ await paypal.recordMetric("webhook_failed").catch(() => {})
317
+
318
+ if (!retryable) {
319
+ return res.status(200).json({ ok: false, message: e?.message })
320
+ }
321
+ return res
322
+ .status(500)
323
+ .json({ message: e?.message || "PayPal webhook processing error" })
324
+ }
325
+ }
@@ -0,0 +1,95 @@
1
+ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
2
+ import type { IPaymentModuleService } from "@medusajs/framework/types"
3
+ import { Modules } from "@medusajs/framework/utils"
4
+ import type PayPalModuleService from "../../../modules/paypal/service"
5
+
6
+ export async function POST(req: MedusaRequest, res: MedusaResponse) {
7
+ const { cart_id } = req.body as { cart_id: string }
8
+
9
+ if (!cart_id) {
10
+ return res.status(400).json({ error: "cart_id is required" })
11
+ }
12
+
13
+ try {
14
+ const query = req.scope.resolve("query")
15
+ const { data: carts } = await query.graph({
16
+ entity: "cart",
17
+ fields: [
18
+ "id",
19
+ "payment_collection.payment_sessions.id",
20
+ "payment_collection.payment_sessions.data",
21
+ "payment_collection.payment_sessions.status",
22
+ "payment_collection.payment_sessions.provider_id",
23
+ "payment_collection.payment_sessions.created_at",
24
+ "payment_collection.payment_sessions.amount",
25
+ "payment_collection.payment_sessions.currency_code",
26
+ ],
27
+ filters: { id: cart_id },
28
+ })
29
+
30
+ const sessions = carts?.[0]?.payment_collection?.payment_sessions || []
31
+ const session = sessions
32
+ .filter((s: any) => String(s.provider_id || "").includes("paypal"))
33
+ .sort(
34
+ (a: any, b: any) =>
35
+ new Date(b.created_at || 0).getTime() - new Date(a.created_at || 0).getTime()
36
+ )[0]
37
+
38
+ if (!session) {
39
+ return res.status(400).json({ error: "No PayPal payment session found for cart" })
40
+ }
41
+
42
+ const currentStatus = String(session.status || "")
43
+ if (currentStatus === "authorized" || currentStatus === "captured") {
44
+ console.info("[paypal-complete] session already in terminal status:", currentStatus)
45
+ return res.json({ success: true, session_id: session.id, status: currentStatus })
46
+ }
47
+
48
+ const paymentModule = req.scope.resolve(Modules.PAYMENT) as IPaymentModuleService
49
+
50
+ const [liveSession] = await paymentModule.listPaymentSessions(
51
+ { id: [session.id] },
52
+ { take: 1 }
53
+ )
54
+
55
+ const liveData = (liveSession?.data || {}) as Record<string, any>
56
+
57
+ const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
58
+ const settings = await paypal.getSettings().catch(() => ({}))
59
+ const settingsData =
60
+ settings && typeof settings === "object" && "data" in settings
61
+ ? ((settings as { data?: Record<string, any> }).data ?? {})
62
+ : {}
63
+ const additionalSettings = (settingsData.additional_settings || {}) as Record<string, any>
64
+ const paymentAction =
65
+ typeof additionalSettings.paymentAction === "string"
66
+ ? additionalSettings.paymentAction
67
+ : "capture"
68
+
69
+ const timestampKey = paymentAction === "authorize" ? "authorized_at" : "captured_at"
70
+
71
+ if (!liveData[timestampKey]) {
72
+ await (paymentModule as any).updatePaymentSession({
73
+ id: session.id,
74
+ data: {
75
+ ...liveData,
76
+ [timestampKey]: new Date().toISOString(),
77
+ },
78
+ amount: liveSession?.amount ?? session.amount,
79
+ currency_code: liveSession?.currency_code ?? session.currency_code,
80
+ })
81
+ }
82
+
83
+ try {
84
+ await (paymentModule as any).authorizePaymentSession(session.id, {})
85
+ console.info("[paypal-complete] authorizePaymentSession succeeded for session", session.id)
86
+ } catch (e: any) {
87
+ console.warn("[paypal-complete] authorizePaymentSession non-fatal:", e?.message)
88
+ }
89
+
90
+ return res.json({ success: true, session_id: session.id })
91
+ } catch (e: any) {
92
+ console.error("[paypal-complete] error:", e?.message || e)
93
+ return res.status(500).json({ error: e?.message || "Internal error" })
94
+ }
95
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from "./modules/paypal"
@@ -0,0 +1,149 @@
1
+ import type { MedusaContainer } from "@medusajs/framework/types"
2
+ import type PayPalModuleService from "../modules/paypal/service"
3
+ import {
4
+ computeNextRetryAt,
5
+ isAllowedEventType,
6
+ isRetryableError,
7
+ MAX_WEBHOOK_ATTEMPTS,
8
+ processPayPalWebhookEvent,
9
+ } from "../modules/paypal/webhook-processor"
10
+
11
+ export default async function paypalWebhookRetry(container: MedusaContainer) {
12
+ const paypal = container.resolve<PayPalModuleService>("paypal_onboarding")
13
+ const now = Date.now()
14
+
15
+ const candidates = await paypal.listPayPalWebhookEvents({ status: "failed" })
16
+ if (!candidates?.length) return
17
+
18
+ console.info(
19
+ `[PayPal] webhook-retry: evaluating ${candidates.length} failed event(s)`
20
+ )
21
+
22
+ for (const event of candidates) {
23
+ const nextRetryAt = event?.next_retry_at
24
+ ? new Date(event.next_retry_at).getTime()
25
+ : null
26
+ if (!nextRetryAt || nextRetryAt > now) continue
27
+
28
+ const attemptCount = Number(event.attempt_count || 0)
29
+
30
+ if (attemptCount >= MAX_WEBHOOK_ATTEMPTS) {
31
+ await paypal
32
+ .updateWebhookEventRecord({
33
+ id: event.id,
34
+ status: "dead_letter",
35
+ next_retry_at: null,
36
+ last_error: `Exceeded max attempts (${MAX_WEBHOOK_ATTEMPTS})`,
37
+ })
38
+ .catch(() => {})
39
+ console.warn("[PayPal] webhook-retry: dead-lettered (max attempts)", {
40
+ id: event.id,
41
+ event_type: event.event_type,
42
+ attempts: attemptCount,
43
+ })
44
+ await paypal.recordMetric("webhook_dead_letter").catch(() => {})
45
+ continue
46
+ }
47
+
48
+ await paypal
49
+ .updateWebhookEventRecord({
50
+ id: event.id,
51
+ status: "processing",
52
+ attempt_count: attemptCount + 1,
53
+ next_retry_at: null,
54
+ last_error: null,
55
+ })
56
+ .catch(() => {})
57
+
58
+ const eventType = String(event.event_type || "")
59
+
60
+ if (!isAllowedEventType(eventType)) {
61
+ await paypal
62
+ .updateWebhookEventRecord({
63
+ id: event.id,
64
+ status: "ignored",
65
+ processed_at: new Date(),
66
+ })
67
+ .catch(() => {})
68
+ console.info("[PayPal] webhook-retry: ignored unsupported event type", {
69
+ id: event.id,
70
+ event_type: eventType,
71
+ })
72
+ continue
73
+ }
74
+
75
+ try {
76
+ const payload = (event.payload || {}) as Record<string, any>
77
+ const processed = await processPayPalWebhookEvent(container, { eventType, payload })
78
+
79
+ await paypal
80
+ .updateWebhookEventRecord({
81
+ id: event.id,
82
+ status: "processed",
83
+ processed_at: new Date(),
84
+ resource_id:
85
+ processed.refundId || processed.captureId || processed.orderId || null,
86
+ })
87
+ .catch(() => {})
88
+
89
+ console.info("[PayPal] webhook-retry: processed successfully", {
90
+ id: event.id,
91
+ event_type: eventType,
92
+ attempt: attemptCount + 1,
93
+ order_id: processed.orderId,
94
+ capture_id: processed.captureId,
95
+ cart_id: processed.cartId,
96
+ session_updated: processed.sessionUpdated,
97
+ })
98
+
99
+ await paypal.recordMetric("webhook_retry_success").catch(() => {})
100
+ } catch (error: any) {
101
+ const retryable = isRetryableError(error)
102
+ const nextAttempt = attemptCount + 1
103
+
104
+ if (!retryable || nextAttempt >= MAX_WEBHOOK_ATTEMPTS) {
105
+ await paypal
106
+ .updateWebhookEventRecord({
107
+ id: event.id,
108
+ status: "dead_letter",
109
+ attempt_count: nextAttempt,
110
+ next_retry_at: null,
111
+ last_error: error?.message || String(error),
112
+ })
113
+ .catch(() => {})
114
+ console.error("[PayPal] webhook-retry: dead-lettered after error", {
115
+ id: event.id,
116
+ event_type: eventType,
117
+ attempt: nextAttempt,
118
+ retryable,
119
+ error: error?.message,
120
+ })
121
+ await paypal.recordMetric("webhook_dead_letter").catch(() => {})
122
+ } else {
123
+ const nextRetry = computeNextRetryAt(nextAttempt)
124
+ await paypal
125
+ .updateWebhookEventRecord({
126
+ id: event.id,
127
+ status: "failed",
128
+ attempt_count: nextAttempt,
129
+ next_retry_at: nextRetry,
130
+ last_error: error?.message || String(error),
131
+ })
132
+ .catch(() => {})
133
+ console.warn("[PayPal] webhook-retry: scheduled retry", {
134
+ id: event.id,
135
+ event_type: eventType,
136
+ attempt: nextAttempt,
137
+ next_retry_at: nextRetry?.toISOString(),
138
+ error: error?.message,
139
+ })
140
+ await paypal.recordMetric("webhook_retry_failed").catch(() => {})
141
+ }
142
+ }
143
+ }
144
+ }
145
+
146
+ export const config = {
147
+ name: "paypal-webhook-retry",
148
+ schedule: "*/10 * * * *",
149
+ }
@@ -0,0 +1,62 @@
1
+ export class PayPalSellerClient {
2
+ private static readonly BN_CODE = "MBJTechnolabs_SI_SPB"
3
+
4
+ constructor(private opts: { environment: "sandbox" | "live"; accessToken: string }) {}
5
+
6
+ private baseUrl() {
7
+ return this.opts.environment === "live"
8
+ ? "https://api-m.paypal.com"
9
+ : "https://api-m.sandbox.paypal.com"
10
+ }
11
+
12
+ private headers(extra?: Record<string, string>) {
13
+ return {
14
+ "Content-Type": "application/json",
15
+ Authorization: `Bearer ${this.opts.accessToken}`,
16
+ "PayPal-Partner-Attribution-Id": PayPalSellerClient.BN_CODE,
17
+ ...(extra ?? {}),
18
+ }
19
+ }
20
+
21
+ async createOrder(body: any) {
22
+ const res = await fetch(`${this.baseUrl()}/v2/checkout/orders`, {
23
+ method: "POST",
24
+ headers: this.headers(),
25
+ body: JSON.stringify(body),
26
+ })
27
+ const json = await res.json().catch(() => ({}))
28
+ if (!res.ok) throw new Error(`PayPal createOrder failed (${res.status}): ${JSON.stringify(json)}`)
29
+ return json
30
+ }
31
+
32
+ async getOrder(orderId: string) {
33
+ const res = await fetch(`${this.baseUrl()}/v2/checkout/orders/${orderId}`, {
34
+ method: "GET",
35
+ headers: this.headers(),
36
+ })
37
+ const json = await res.json().catch(() => ({}))
38
+ if (!res.ok) throw new Error(`PayPal getOrder failed (${res.status}): ${JSON.stringify(json)}`)
39
+ return json
40
+ }
41
+
42
+ async captureOrder(orderId: string) {
43
+ const res = await fetch(`${this.baseUrl()}/v2/checkout/orders/${orderId}/capture`, {
44
+ method: "POST",
45
+ headers: this.headers(),
46
+ })
47
+ const json = await res.json().catch(() => ({}))
48
+ if (!res.ok) throw new Error(`PayPal captureOrder failed (${res.status}): ${JSON.stringify(json)}`)
49
+ return json
50
+ }
51
+
52
+ async refundCapture(captureId: string, body?: any) {
53
+ const res = await fetch(`${this.baseUrl()}/v2/payments/captures/${captureId}/refund`, {
54
+ method: "POST",
55
+ headers: this.headers(),
56
+ body: body ? JSON.stringify(body) : "{}",
57
+ })
58
+ const json = await res.json().catch(() => ({}))
59
+ if (!res.ok) throw new Error(`PayPal refund failed (${res.status}): ${JSON.stringify(json)}`)
60
+ return json
61
+ }
62
+ }
@@ -0,0 +1,8 @@
1
+ import { Module } from "@medusajs/framework/utils"
2
+ import PayPalModuleService from "./service"
3
+
4
+ export const PAYPAL_MODULE = "paypal_onboarding"
5
+
6
+ export default Module(PAYPAL_MODULE, {
7
+ service: PayPalModuleService,
8
+ })
@@ -0,0 +1,33 @@
1
+ import { Migration } from "@medusajs/framework/mikro-orm/migrations"
2
+
3
+ export class Migration20260115120000 extends Migration {
4
+ async up(): Promise<void> {
5
+ this.addSql(`
6
+ CREATE TABLE IF NOT EXISTS "paypal_connection" (
7
+ "id" text NOT NULL,
8
+ "environment" text NOT NULL DEFAULT 'sandbox',
9
+ "status" text NOT NULL DEFAULT 'disconnected',
10
+ "shared_id" text NULL,
11
+ "auth_code" text NULL,
12
+ "seller_client_id" text NULL,
13
+ "seller_client_secret" text NULL,
14
+ "app_access_token" text NULL,
15
+ "app_access_token_expires_at" timestamptz NULL,
16
+ "metadata" jsonb NOT NULL DEFAULT '{}'::jsonb,
17
+ "created_at" timestamptz NOT NULL DEFAULT now(),
18
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
19
+ "deleted_at" timestamptz NULL,
20
+ CONSTRAINT "paypal_connection_pkey" PRIMARY KEY ("id")
21
+ );
22
+
23
+ CREATE INDEX IF NOT EXISTS "idx_paypal_connection_deleted_at"
24
+ ON "paypal_connection" ("deleted_at");
25
+ `)
26
+ }
27
+
28
+ async down(): Promise<void> {
29
+ this.addSql(`
30
+ DROP TABLE IF EXISTS "paypal_connection" CASCADE;
31
+ `)
32
+ }
33
+ }
@@ -0,0 +1,22 @@
1
+ import { Migration } from "@medusajs/framework/mikro-orm/migrations"
2
+
3
+ export class Migration20260123090000 extends Migration {
4
+ async up(): Promise<void> {
5
+ this.addSql(`
6
+ CREATE TABLE IF NOT EXISTS "paypal_settings" (
7
+ "id" text NOT NULL,
8
+ "data" jsonb NULL,
9
+ "created_at" timestamptz NOT NULL DEFAULT now(),
10
+ "updated_at" timestamptz NOT NULL DEFAULT now(),
11
+ "deleted_at" timestamptz NULL,
12
+ CONSTRAINT "paypal_settings_pkey" PRIMARY KEY ("id")
13
+ );
14
+ CREATE INDEX IF NOT EXISTS "idx_paypal_settings_deleted_at"
15
+ ON "paypal_settings" ("deleted_at");
16
+ `)
17
+ }
18
+
19
+ async down(): Promise<void> {
20
+ this.addSql(`DROP TABLE IF EXISTS "paypal_settings" CASCADE;`)
21
+ }
22
+ }