cabloy 5.1.122 → 5.1.124

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 (244) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +13 -3
  3. package/.claude/skills/cabloy-workflow/SKILL.md +6 -0
  4. package/.claude/skills/cabloy-workflow/evals/evals.json +6 -0
  5. package/CHANGELOG.md +24 -0
  6. package/CLAUDE.md +1 -1
  7. package/cabloy-docs/.vitepress/config.mjs +4 -0
  8. package/cabloy-docs/frontend/form-layout-guide.md +29 -7
  9. package/cabloy-docs/fullstack/parallel-worktree-environment.md +87 -0
  10. package/e2e/scripts/e2e.ts +13 -1
  11. package/e2e/scripts/startE2eVona.ts +4 -1
  12. package/e2e/specs/a-commerce/commerce.spec.ts +129 -32
  13. package/package.json +2 -1
  14. package/playwright-report/data/24ac790ec112339c76cfb0c8e2c2539c2f953a0b.zip +0 -0
  15. package/playwright-report/data/2fddcabcdbd0b695061a565acfff243cb3a4f5e3.zip +0 -0
  16. package/playwright-report/data/4738038d9e861d63fd25937c9a3570934786a62f.zip +0 -0
  17. package/playwright-report/data/72f99c7da67c7f6ea53cab7d8681798b70d79a10.md +222 -0
  18. package/playwright-report/data/7b9684a7c793e9798b898f8ff50177b660a7a733.md +222 -0
  19. package/playwright-report/data/8b31595f5f1cc9d23863af51a592e6b90dcbc4ce.zip +0 -0
  20. package/playwright-report/data/95b578407a68806202dda917a61c50c750bd285b.md +222 -0
  21. package/playwright-report/data/ad960b3a58f224f5b4cad04a24067600064ffb7b.md +222 -0
  22. package/playwright-report/index.html +90 -0
  23. package/playwright-report/trace/assets/codeMirrorModule-LEHpjmcn.js +32 -0
  24. package/playwright-report/trace/assets/defaultSettingsView-BNmKHKpQ.js +264 -0
  25. package/playwright-report/trace/assets/urlMatch-BYQrIQwR.js +1 -0
  26. package/playwright-report/trace/codeMirrorModule.DYBRYzYX.css +1 -0
  27. package/playwright-report/trace/codicon.DCmgc-ay.ttf +0 -0
  28. package/playwright-report/trace/defaultSettingsView.CjdS-WJx.css +1 -0
  29. package/playwright-report/trace/index.CzXZzn5A.css +1 -0
  30. package/playwright-report/trace/index.DMMX1gXU.js +2 -0
  31. package/playwright-report/trace/index.html +44 -0
  32. package/playwright-report/trace/manifest.webmanifest +16 -0
  33. package/playwright-report/trace/playwright-logo.svg +9 -0
  34. package/playwright-report/trace/snapshot.html +10 -0
  35. package/playwright-report/trace/snapshot.v8KI4P3m.js +2 -0
  36. package/playwright-report/trace/sw.bundle.js +5 -0
  37. package/playwright-report/trace/uiMode.BZQ54Kgt.css +1 -0
  38. package/playwright-report/trace/uiMode.Ut8wwJNp.js +6 -0
  39. package/playwright-report/trace/uiMode.html +18 -0
  40. package/playwright-report/trace/xtermModule.DYP7pi_n.css +32 -0
  41. package/vona/env/.env +12 -0
  42. package/vona/env/.env.test +7 -0
  43. package/vona/packages-cli/cli/package.json +1 -1
  44. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}Create.tsx_ +19 -1
  45. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}Update.tsx_ +19 -1
  46. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}View.tsx_ +19 -1
  47. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/3-en-us.ts +6 -1
  48. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/4-zh-cn.ts +6 -1
  49. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}Create.tsx_ +19 -1
  50. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}Update.tsx_ +19 -1
  51. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}View.tsx_ +19 -1
  52. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/snippets/3-en-us.ts +6 -1
  53. package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/snippets/4-zh-cn.ts +6 -1
  54. package/vona/packages-cli/cli-set-api/package.json +1 -1
  55. package/vona/pnpm-lock.yaml +255 -12
  56. package/vona/pnpm-workspace.yaml +1 -1
  57. package/vona/src/suite/a-commerce/modules/commerce-payment/package.json +4 -1
  58. package/vona/src/suite/a-commerce/modules/commerce-payment/src/.metadata/index.ts +45 -3
  59. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.index.ts +1 -0
  60. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.version.ts +25 -1
  61. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/payScene.commerceOrder.ts +20 -0
  62. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/paymentAttempt.tsx +9 -0
  63. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/paymentAudit.tsx +5 -2
  64. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/refundAttempt.tsx +6 -0
  65. package/vona/src/suite/a-commerce/modules/commerce-payment/src/index.ts +2 -0
  66. package/vona/src/suite/a-commerce/modules/commerce-payment/src/lib/index.ts +1 -0
  67. package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +54 -0
  68. package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/paymentAttempt.ts +7 -1
  69. package/vona/src/suite/a-commerce/modules/commerce-payment/src/types/index.ts +1 -0
  70. package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +21 -0
  71. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/.metadata/index.ts +30 -0
  72. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/en-us.ts +4 -0
  73. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/zh-cn.ts +4 -0
  74. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateCreate.tsx +88 -1
  75. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateUpdate.tsx +44 -1
  76. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateView.tsx +72 -1
  77. package/vona/src/suite/a-commerce/modules/commerce-promotion/test/couponTemplateFormLayout.test.ts +121 -0
  78. package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/bean/ssrMenu.home.ts +4 -1
  79. package/vona/src/suite/a-commerce/modules/commerce-trade/package.json +4 -1
  80. package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +0 -21
  81. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/checkoutResult.tsx +3 -0
  82. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +79 -0
  83. package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +227 -0
  84. package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +121 -13
  85. package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +312 -0
  86. package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +76 -0
  87. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +842 -0
  88. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/this.ts +2 -0
  89. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payProvider.ts +92 -0
  90. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payScene.ts +105 -0
  91. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +28 -0
  92. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.redlock.ts +11 -0
  93. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +113 -0
  94. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/queue.outboxDispatch.ts +31 -0
  95. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.outboxDispatch.ts +11 -0
  96. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/controller/paymentSession.ts +55 -0
  97. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/controller/webhook.ts +47 -0
  98. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/dto/paymentSessionStart.tsx +8 -0
  99. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/dto/paymentSessionView.tsx +69 -0
  100. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/dto/webhookReceipt.tsx +12 -0
  101. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/outboxEvent.tsx +46 -0
  102. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentAudit.tsx +36 -0
  103. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentSession.tsx +72 -0
  104. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +54 -0
  105. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/refundOperation.tsx +37 -0
  106. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/webhookInbox.tsx +59 -0
  107. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/index.ts +3 -0
  108. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/index.ts +2 -0
  109. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/payProvider.ts +7 -0
  110. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/payScene.ts +7 -0
  111. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/outboxEvent.ts +10 -0
  112. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentAudit.ts +10 -0
  113. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +10 -0
  114. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/providerOperation.ts +10 -0
  115. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/refundOperation.ts +10 -0
  116. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/webhookInbox.ts +10 -0
  117. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/outbox.ts +156 -0
  118. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +278 -0
  119. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +5 -0
  120. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +127 -0
  121. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/index.ts +3 -0
  122. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts +74 -0
  123. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payScene.ts +63 -0
  124. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +151 -0
  125. package/vona/src/suite-vendor/a-pay/modules/a-pay/test/outbox.test.ts +209 -0
  126. package/vona/src/suite-vendor/a-pay/modules/a-pay/test/paymentSession.test.ts +153 -0
  127. package/vona/src/suite-vendor/a-pay/modules/a-pay/test/webhook.test.ts +278 -0
  128. package/vona/src/suite-vendor/a-pay/modules/a-pay/tsconfig.build.json +11 -0
  129. package/vona/src/suite-vendor/a-pay/modules/a-pay/tsconfig.json +7 -0
  130. package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +55 -0
  131. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/index.ts +182 -0
  132. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/this.ts +2 -0
  133. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/bean/payProvider.mock.ts +149 -0
  134. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/controller/mockPayment.ts +25 -0
  135. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockPaymentComplete.tsx +13 -0
  136. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockPaymentReceipt.tsx +16 -0
  137. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/index.ts +3 -0
  138. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/lib/index.ts +1 -0
  139. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +78 -0
  140. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/types/index.ts +10 -0
  141. package/vona/src/suite-vendor/a-pay/modules/pay-mock/test/payMock.test.ts +141 -0
  142. package/vona/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.build.json +11 -0
  143. package/vona/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.json +7 -0
  144. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +55 -0
  145. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/index.ts +62 -0
  146. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/this.ts +2 -0
  147. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +91 -0
  148. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/index.ts +3 -0
  149. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/index.ts +1 -0
  150. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/types/index.ts +9 -0
  151. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.build.json +11 -0
  152. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.json +7 -0
  153. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +55 -0
  154. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/index.ts +62 -0
  155. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/this.ts +2 -0
  156. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/bean/payProvider.stripe.ts +88 -0
  157. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/index.ts +2 -0
  158. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/types/index.ts +8 -0
  159. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.build.json +11 -0
  160. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.json +7 -0
  161. package/vona/src/suite-vendor/a-pay/package.json +15 -0
  162. package/vona/src/suite-vendor/a-pay/tsconfig.base.json +4 -0
  163. package/vona/src/suite-vendor/a-pay/tsconfig.json +19 -0
  164. package/zova/env/.env +1 -0
  165. package/zova/openapi.config.ts +5 -1
  166. package/zova/package.original.json +1 -1
  167. package/zova/packages-cli/cli/package.json +2 -2
  168. package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/project/openapi.config.ts +5 -1
  169. package/zova/packages-cli/cli-set-front/package.json +1 -1
  170. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +8 -0
  171. package/zova/packages-cli/cli-set-front/src/lib/common/cliCreatePage.ts +7 -24
  172. package/zova/packages-cli/cli-set-front/src/lib/common/utils.ts +10 -1
  173. package/zova/packages-utils/zova-jsx/package.json +2 -2
  174. package/zova/packages-zova/zova/package.json +3 -3
  175. package/zova/packages-zova/zova-core/package.json +1 -1
  176. package/zova/packages-zova/zova-core/src/types/interface/component.ts +5 -0
  177. package/zova/pnpm-lock.yaml +96 -26
  178. package/zova/src/front/config/config/config.cabloyCommerce.ts +1 -1
  179. package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/schemas.ts +110 -12
  180. package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/types.ts +1292 -160
  181. package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +0 -1
  182. package/zova/src/suite/a-commerce/modules/commerce-trade/package.json +4 -1
  183. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +1 -47
  184. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +23 -8
  185. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +249 -62
  186. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +5 -1
  187. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +152 -39
  188. package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +1 -1
  189. package/zova/src/suite-vendor/a-pay/modules/a-pay/cli/openapi.config.ts +9 -0
  190. package/zova/src/suite-vendor/a-pay/modules/a-pay/package.json +53 -0
  191. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/component/paymentNextAction.ts +31 -0
  192. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +217 -0
  193. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/this.ts +2 -0
  194. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/baseURL.ts +5 -0
  195. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/index.ts +3 -0
  196. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/schemas.ts +584 -0
  197. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/types.ts +9324 -0
  198. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/paymentSession.ts +52 -0
  199. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/apiSchema/paymentSession.ts +20 -0
  200. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/component/paymentNextAction/controller.tsx +76 -0
  201. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/index.ts +3 -0
  202. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/lib/index.ts +1 -0
  203. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +32 -0
  204. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentCoordinator.ts +13 -0
  205. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/types/index.ts +1 -0
  206. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +25 -0
  207. package/zova/src/suite-vendor/a-pay/modules/a-pay/tsconfig.build.json +13 -0
  208. package/zova/src/suite-vendor/a-pay/modules/a-pay/tsconfig.json +5 -0
  209. package/zova/src/suite-vendor/a-pay/modules/pay-mock/cli/openapi.config.ts +9 -0
  210. package/zova/src/suite-vendor/a-pay/modules/pay-mock/package.json +53 -0
  211. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/index.ts +140 -0
  212. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/this.ts +2 -0
  213. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/baseURL.ts +5 -0
  214. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/index.ts +3 -0
  215. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/schemas.ts +584 -0
  216. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/types.ts +9324 -0
  217. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/payMockPayment.ts +34 -0
  218. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/apiSchema/payMockPayment.ts +13 -0
  219. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/index.ts +1 -0
  220. package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/model/payMockPayment.ts +20 -0
  221. package/zova/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.build.json +13 -0
  222. package/zova/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.json +5 -0
  223. package/zova/src/suite-vendor/a-pay/modules/pay-paypal/package.json +52 -0
  224. package/zova/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/index.ts +26 -0
  225. package/zova/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/this.ts +2 -0
  226. package/zova/src/suite-vendor/a-pay/modules/pay-paypal/src/index.ts +1 -0
  227. package/zova/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.build.json +13 -0
  228. package/zova/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.json +5 -0
  229. package/zova/src/suite-vendor/a-pay/modules/pay-stripe/package.json +52 -0
  230. package/zova/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/index.ts +26 -0
  231. package/zova/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/this.ts +2 -0
  232. package/zova/src/suite-vendor/a-pay/modules/pay-stripe/src/index.ts +1 -0
  233. package/zova/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.build.json +13 -0
  234. package/zova/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.json +5 -0
  235. package/zova/src/suite-vendor/a-pay/package.json +15 -0
  236. package/zova/src/suite-vendor/a-pay/tsconfig.base.json +4 -0
  237. package/zova/src/suite-vendor/a-pay/tsconfig.json +4 -0
  238. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  239. package/zova/src/suite-vendor/a-zova/package.json +2 -2
  240. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/payment.ts +0 -23
  241. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradePayment.ts +0 -36
  242. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradePayment.ts +0 -13
  243. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/payment.ts +0 -25
  244. /package/vona/patches/{zova-core@5.1.79.patch → zova-core@5.1.81.patch} +0 -0
@@ -0,0 +1,151 @@
1
+ import type { TableIdentity } from 'table-identity';
2
+
3
+ import type { IPayProviderClientOptions } from './payProvider.ts';
4
+
5
+ export type TypePayEnvironment = 'sandbox' | 'live';
6
+
7
+ export type TypePaymentSessionState =
8
+ | 'created'
9
+ | 'starting'
10
+ | 'requires_action'
11
+ | 'processing'
12
+ | 'succeeded'
13
+ | 'failed'
14
+ | 'cancelled'
15
+ | 'expired';
16
+
17
+ export type TypeRefundOperationState =
18
+ | 'created'
19
+ | 'submitting'
20
+ | 'pending'
21
+ | 'succeeded'
22
+ | 'failed'
23
+ | 'cancelled';
24
+
25
+ export type TypeProviderOperationKind = 'start' | 'confirm' | 'query' | 'refund';
26
+
27
+ export type TypeProviderOperationState =
28
+ | 'created'
29
+ | 'claimed'
30
+ | 'submitted'
31
+ | 'succeeded'
32
+ | 'failed'
33
+ | 'reconciliation_required';
34
+
35
+ export type TypeOutboxEventState = 'pending' | 'claimed' | 'dispatched' | 'failed';
36
+
37
+ export type TypePaymentNextAction =
38
+ | { kind: 'redirect'; url: string }
39
+ | { kind: 'embedded'; clientToken: string; publishableConfig?: Record<string, string> }
40
+ | { kind: 'pending'; retryAfterSeconds?: number }
41
+ | { kind: 'completed' };
42
+
43
+ export interface IPayMoney {
44
+ amountMinor: number;
45
+ currency: string;
46
+ }
47
+
48
+ export interface IPayProviderCapabilities {
49
+ redirectCheckout: boolean;
50
+ embeddedCheckout: boolean;
51
+ automaticCapture: boolean;
52
+ manualCapture: boolean;
53
+ refunds: boolean;
54
+ partialRefunds: boolean;
55
+ webhooks: boolean;
56
+ }
57
+
58
+ export interface IPayProviderPaymentInput extends IPayMoney {
59
+ paymentSessionId: TableIdentity;
60
+ businessReference: string;
61
+ idempotencyKey: string;
62
+ returnUrl?: string;
63
+ cancelUrl?: string;
64
+ providerOrderId?: string;
65
+ }
66
+
67
+ export interface IPayProviderRefundInput extends IPayMoney {
68
+ paymentSessionId: TableIdentity;
69
+ refundOperationId: TableIdentity;
70
+ businessReference: string;
71
+ idempotencyKey: string;
72
+ providerCaptureId: string;
73
+ }
74
+
75
+ export interface IPayProviderPaymentSnapshot {
76
+ state: Extract<
77
+ TypePaymentSessionState,
78
+ 'requires_action' | 'processing' | 'succeeded' | 'failed' | 'cancelled'
79
+ >;
80
+ providerPaymentId?: string;
81
+ providerOrderId?: string;
82
+ providerCaptureId?: string;
83
+ nextAction?: TypePaymentNextAction;
84
+ summary?: Record<string, string | number | boolean | null>;
85
+ }
86
+
87
+ export interface IPayProviderRefundSnapshot {
88
+ state: Extract<TypeRefundOperationState, 'pending' | 'succeeded' | 'failed' | 'cancelled'>;
89
+ providerRefundId?: string;
90
+ summary?: Record<string, string | number | boolean | null>;
91
+ }
92
+
93
+ export interface IPayProviderWebhookInput {
94
+ rawBody?: string;
95
+ body: unknown;
96
+ headers: Record<string, string | string[] | undefined>;
97
+ }
98
+
99
+ export interface IPayProviderVerifiedWebhook {
100
+ eventId: string;
101
+ eventType: string;
102
+ paymentSessionId?: TableIdentity;
103
+ refundOperationId?: TableIdentity;
104
+ payment?: IPayProviderPaymentSnapshot;
105
+ refund?: IPayProviderRefundSnapshot;
106
+ summary?: Record<string, string | number | boolean | null>;
107
+ }
108
+
109
+ export interface IPayProviderExecute<
110
+ TClientOptions extends IPayProviderClientOptions = IPayProviderClientOptions,
111
+ > {
112
+ startPayment(
113
+ input: IPayProviderPaymentInput,
114
+ clientOptions: TClientOptions,
115
+ ): Promise<IPayProviderPaymentSnapshot>;
116
+ queryPayment(
117
+ input: IPayProviderPaymentInput,
118
+ clientOptions: TClientOptions,
119
+ ): Promise<IPayProviderPaymentSnapshot>;
120
+ createRefund(
121
+ input: IPayProviderRefundInput,
122
+ clientOptions: TClientOptions,
123
+ ): Promise<IPayProviderRefundSnapshot>;
124
+ queryRefund?(
125
+ input: IPayProviderRefundInput,
126
+ clientOptions: TClientOptions,
127
+ ): Promise<IPayProviderRefundSnapshot>;
128
+ verifyWebhook(
129
+ input: IPayProviderWebhookInput,
130
+ clientOptions: TClientOptions,
131
+ ): Promise<IPayProviderVerifiedWebhook>;
132
+ }
133
+
134
+ export interface IPaymentOutcomeEvent extends IPayMoney {
135
+ eventId: string;
136
+ paymentSessionId: TableIdentity;
137
+ businessReference: string;
138
+ providerName: string;
139
+ state: Extract<TypePaymentSessionState, 'succeeded' | 'failed' | 'cancelled'>;
140
+ providerCaptureId?: string;
141
+ }
142
+
143
+ export interface IRefundOutcomeEvent extends IPayMoney {
144
+ eventId: string;
145
+ paymentSessionId: TableIdentity;
146
+ refundOperationId: TableIdentity;
147
+ businessReference: string;
148
+ providerName: string;
149
+ state: Extract<TypeRefundOperationState, 'succeeded' | 'failed' | 'cancelled'>;
150
+ providerRefundId?: string;
151
+ }
@@ -0,0 +1,209 @@
1
+ import assert from 'node:assert';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { describe, it } from 'node:test';
4
+ import { app } from 'vona-mock';
5
+
6
+ import type { IPaymentOutcomeEvent } from '../src/types/payment.ts';
7
+
8
+ interface IFixture {
9
+ userId?: number;
10
+ paymentSessionId?: number;
11
+ outboxEventIds: number[];
12
+ }
13
+
14
+ async function createFixture(suffix: string): Promise<IFixture> {
15
+ const scope = app.scope('a-pay');
16
+ const user = await app.bean.user.register({ name: `pay-outbox-${suffix}` }, true);
17
+ const session = await scope.service.paymentSession.create({
18
+ userId: user.id,
19
+ payScene: 'commerce-payment:commerceOrder',
20
+ businessReference: `business-${suffix}`,
21
+ amountMinor: 1299,
22
+ currency: 'USD',
23
+ correlationId: `payment-${suffix}`,
24
+ });
25
+ return { userId: user.id as number, paymentSessionId: session.id as number, outboxEventIds: [] };
26
+ }
27
+
28
+ function createOutcomePayload(fixture: IFixture): IPaymentOutcomeEvent {
29
+ return {
30
+ eventId: randomUUID(),
31
+ paymentSessionId: fixture.paymentSessionId!,
32
+ businessReference: 'outbox-test',
33
+ providerName: 'test-provider',
34
+ state: 'succeeded',
35
+ amountMinor: 1299,
36
+ currency: 'USD',
37
+ };
38
+ }
39
+
40
+ async function insertOutbox(
41
+ fixture: IFixture,
42
+ overrides?: Partial<{
43
+ eventType: 'payment.outcome.v1';
44
+ state: 'pending' | 'claimed';
45
+ attemptCount: number;
46
+ nextAttemptAt: Date;
47
+ claimToken: string;
48
+ claimedAt: Date;
49
+ claimExpiresAt: Date;
50
+ }>,
51
+ ) {
52
+ const event = await app.scope('a-pay').model.outboxEvent.insert({
53
+ eventType: overrides?.eventType ?? 'payment.outcome.v1',
54
+ paymentSessionId: fixture.paymentSessionId!,
55
+ payload: createOutcomePayload(fixture),
56
+ state: overrides?.state ?? 'pending',
57
+ attemptCount: overrides?.attemptCount ?? 0,
58
+ nextAttemptAt: overrides?.nextAttemptAt ?? new Date(Date.now() - 1_000),
59
+ claimToken: overrides?.claimToken,
60
+ claimedAt: overrides?.claimedAt,
61
+ claimExpiresAt: overrides?.claimExpiresAt,
62
+ });
63
+ fixture.outboxEventIds.push(event.id as number);
64
+ return event;
65
+ }
66
+
67
+ async function cleanup(fixture: IFixture) {
68
+ const scope = app.scope('a-pay');
69
+ for (const id of fixture.outboxEventIds) await scope.model.outboxEvent.delete({ id });
70
+ if (fixture.paymentSessionId !== undefined) {
71
+ await scope.model.paymentAudit.delete({ paymentSessionId: fixture.paymentSessionId });
72
+ await scope.model.webhookInbox.delete({ paymentSessionId: fixture.paymentSessionId });
73
+ await scope.model.paymentSession.delete({ id: fixture.paymentSessionId });
74
+ }
75
+ if (fixture.userId !== undefined) {
76
+ await app.scope('home-user').model.roleUser.delete({ userId: fixture.userId });
77
+ await app.bean.user.removeById(fixture.userId);
78
+ }
79
+ }
80
+
81
+ describe('outbox.test.ts', { concurrency: false }, () => {
82
+ it('claims, backs off, and exhausts durable delivery attempts', async () => {
83
+ await app.bean.executor.mockCtx(async () => {
84
+ const fixture = await createFixture(randomUUID().slice(0, 12));
85
+ try {
86
+ const event = await insertOutbox(fixture);
87
+ const scope = app.scope('a-pay');
88
+ const first = await scope.service.outbox.claim(event.id);
89
+ assert.equal(first?.attemptCount, 1);
90
+ assert.ok(first?.claimToken);
91
+ const releaseStart = Date.now();
92
+ await scope.service.outbox.release(
93
+ event.id,
94
+ first!.claimToken!,
95
+ new Error('first failure'),
96
+ );
97
+ let persisted = await scope.model.outboxEvent.getById(event.id);
98
+ assert.equal(persisted?.state, 'pending');
99
+ assert.equal(persisted?.errorSummary, 'first failure');
100
+ assert.ok((persisted?.nextAttemptAt?.getTime() ?? 0) >= releaseStart + 900);
101
+ assert.equal(await scope.service.outbox.claim(event.id), undefined);
102
+ await scope.model.outboxEvent.updateById(event.id, {
103
+ nextAttemptAt: new Date(Date.now() - 1),
104
+ });
105
+ const second = await scope.service.outbox.claim(event.id);
106
+ assert.equal(second?.attemptCount, 2);
107
+ const secondReleaseStart = Date.now();
108
+ await scope.service.outbox.release(
109
+ event.id,
110
+ second!.claimToken!,
111
+ new Error('second failure'),
112
+ );
113
+ persisted = await scope.model.outboxEvent.getById(event.id);
114
+ assert.ok((persisted?.nextAttemptAt?.getTime() ?? 0) >= secondReleaseStart + 1_900);
115
+
116
+ const exhausted = await insertOutbox(fixture, { attemptCount: 10 });
117
+ assert.equal(await scope.service.outbox.claim(exhausted.id), undefined);
118
+ assert.equal((await scope.model.outboxEvent.getById(exhausted.id))?.state, 'failed');
119
+ } finally {
120
+ await cleanup(fixture);
121
+ }
122
+ });
123
+ });
124
+
125
+ it('retries a dispatch when the persisted payment scene is unavailable', async () => {
126
+ await app.bean.executor.mockCtx(async () => {
127
+ const fixture = await createFixture(randomUUID().slice(0, 12));
128
+ try {
129
+ const scope = app.scope('a-pay');
130
+ await scope.model.paymentSession.updateById(fixture.paymentSessionId!, {
131
+ payScene: 'test-payment',
132
+ });
133
+ const event = await insertOutbox(fixture);
134
+ await scope.queue.outboxDispatch.pushAsync({ outboxEventId: event.id });
135
+ const persisted = await scope.model.outboxEvent.getById(event.id);
136
+ assert.equal(persisted?.state, 'pending');
137
+ assert.equal(persisted?.attemptCount, 1);
138
+ assert.match(persisted?.errorSummary ?? '', /payment scene not found/);
139
+ } finally {
140
+ await cleanup(fixture);
141
+ }
142
+ });
143
+ });
144
+
145
+ it('reclaims expired leases and fences stale claim tokens', async () => {
146
+ await app.bean.executor.mockCtx(async () => {
147
+ const fixture = await createFixture(randomUUID().slice(0, 12));
148
+ try {
149
+ const event = await insertOutbox(fixture);
150
+ const scope = app.scope('a-pay');
151
+ const first = await scope.service.outbox.claim(event.id);
152
+ await scope.model.outboxEvent.updateById(event.id, {
153
+ claimExpiresAt: new Date(Date.now() - 1),
154
+ });
155
+ const second = await scope.service.outbox.claim(event.id);
156
+ assert.ok(second?.claimToken);
157
+ assert.notEqual(second?.claimToken, first?.claimToken);
158
+ assert.equal(second?.attemptCount, 2);
159
+ assert.equal(
160
+ await scope.service.outbox.markDispatched(event.id, first!.claimToken!),
161
+ undefined,
162
+ );
163
+ assert.equal(
164
+ await scope.service.outbox.release(event.id, first!.claimToken!, new Error('stale')),
165
+ undefined,
166
+ );
167
+ assert.equal(
168
+ (await scope.model.outboxEvent.getById(event.id))?.claimToken,
169
+ second?.claimToken,
170
+ );
171
+ await scope.service.outbox.markDispatched(event.id, second!.claimToken!);
172
+ const persisted = await scope.model.outboxEvent.getById(event.id);
173
+ assert.equal(persisted?.state, 'dispatched');
174
+ assert.equal(persisted?.claimToken, undefined);
175
+ } finally {
176
+ await cleanup(fixture);
177
+ }
178
+ });
179
+ });
180
+
181
+ it('rolls back enqueued durable rows with the enclosing transaction', async () => {
182
+ await app.bean.executor.mockCtx(async () => {
183
+ const fixture = await createFixture(randomUUID().slice(0, 12));
184
+ try {
185
+ const scope = app.scope('a-pay');
186
+ const eventId = await assert.rejects(
187
+ app.ctx.db.transaction.begin(async () => {
188
+ const event = await scope.service.outbox.enqueue(
189
+ fixture.paymentSessionId!,
190
+ 'payment.outcome.v1',
191
+ createOutcomePayload(fixture),
192
+ );
193
+ fixture.outboxEventIds.push(event.id as number);
194
+ throw new Error(String(event.id));
195
+ }),
196
+ /\d+/,
197
+ );
198
+ assert.equal(eventId, undefined);
199
+ const events = await scope.model.outboxEvent.select({
200
+ where: { paymentSessionId: fixture.paymentSessionId },
201
+ });
202
+ assert.deepEqual(events, []);
203
+ fixture.outboxEventIds = [];
204
+ } finally {
205
+ await cleanup(fixture);
206
+ }
207
+ });
208
+ });
209
+ });
@@ -0,0 +1,153 @@
1
+ import assert from 'node:assert';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { describe, it } from 'node:test';
4
+ import { app } from 'vona-mock';
5
+
6
+ interface IFixture {
7
+ userId?: number;
8
+ paymentSessionId?: number;
9
+ }
10
+
11
+ async function createFixture(expiresAt: Date): Promise<IFixture> {
12
+ const scope = app.scope('a-pay');
13
+ const suffix = randomUUID().slice(0, 12);
14
+ const user = await app.bean.user.register({ name: `payment-session-${suffix}` }, true);
15
+ const session = await scope.service.paymentSession.create({
16
+ userId: user.id,
17
+ payScene: 'commerce-payment:commerceOrder',
18
+ businessReference: `business-${suffix}`,
19
+ amountMinor: 1299,
20
+ currency: 'USD',
21
+ correlationId: `payment-${suffix}`,
22
+ });
23
+ await scope.model.paymentSession.updateById(session.id, { expiresAt });
24
+ return { userId: user.id as number, paymentSessionId: session.id as number };
25
+ }
26
+
27
+ async function cleanup(fixture: IFixture) {
28
+ const scope = app.scope('a-pay');
29
+ if (fixture.paymentSessionId !== undefined) {
30
+ await scope.model.paymentAudit.delete({ paymentSessionId: fixture.paymentSessionId });
31
+ await scope.model.paymentSession.delete({ id: fixture.paymentSessionId });
32
+ }
33
+ if (fixture.userId !== undefined) {
34
+ await app.scope('home-user').model.roleUser.delete({ userId: fixture.userId });
35
+ await app.bean.user.removeById(fixture.userId);
36
+ }
37
+ }
38
+
39
+ describe('paymentSession.test.ts', { concurrency: false }, () => {
40
+ it('derives provider facts and expiry from the payment scene', async () => {
41
+ await app.bean.executor.mockCtx(async () => {
42
+ const scope = app.scope('a-pay');
43
+ const suffix = randomUUID().slice(0, 12);
44
+ const user = await app.bean.user.register({ name: `payment-session-${suffix}` }, true);
45
+ const fixture: IFixture = { userId: user.id as number };
46
+ try {
47
+ const createdAt = Date.now();
48
+ const session = await scope.service.paymentSession.create({
49
+ userId: user.id,
50
+ payScene: 'commerce-payment:commerceOrder',
51
+ businessReference: `business-${suffix}`,
52
+ amountMinor: 1299,
53
+ currency: 'USD',
54
+ correlationId: `payment-${suffix}`,
55
+ });
56
+ fixture.paymentSessionId = session.id as number;
57
+ assert.equal(session.providerName, 'pay-mock:mock');
58
+ assert.equal(session.clientName, 'default');
59
+ assert.equal(session.environment, 'sandbox');
60
+ assert.ok(session.expiresAt.getTime() >= createdAt + 30 * 60 * 1000);
61
+ assert.ok(session.expiresAt.getTime() <= Date.now() + 30 * 60 * 1000);
62
+ } finally {
63
+ await cleanup(fixture);
64
+ }
65
+ });
66
+ });
67
+
68
+ it('rejects a currency outside the payment scene policy', async () => {
69
+ await app.bean.executor.mockCtx(async () => {
70
+ const scope = app.scope('a-pay');
71
+ const suffix = randomUUID().slice(0, 12);
72
+ const user = await app.bean.user.register({ name: `payment-session-${suffix}` }, true);
73
+ const fixture: IFixture = { userId: user.id as number };
74
+ try {
75
+ await assert.rejects(
76
+ scope.service.paymentSession.create({
77
+ userId: user.id,
78
+ payScene: 'commerce-payment:commerceOrder',
79
+ businessReference: `business-${suffix}`,
80
+ amountMinor: 1299,
81
+ currency: 'EUR',
82
+ correlationId: `payment-${suffix}`,
83
+ }),
84
+ { status: 422 },
85
+ );
86
+ assert.deepEqual(
87
+ await scope.model.paymentSession.select({
88
+ where: { correlationId: `payment-${suffix}` },
89
+ }),
90
+ [],
91
+ );
92
+ } finally {
93
+ await cleanup(fixture);
94
+ }
95
+ });
96
+ });
97
+
98
+ it('starts only an unexpired created payment session', async () => {
99
+ await app.bean.executor.mockCtx(async () => {
100
+ const fixture = await createFixture(new Date(Date.now() + 60_000));
101
+ try {
102
+ const scope = app.scope('a-pay');
103
+ const session = await scope.service.paymentSession.start(fixture.paymentSessionId!);
104
+ assert.equal(session.state, 'requires_action');
105
+ await assert.rejects(scope.service.paymentSession.start(fixture.paymentSessionId!), {
106
+ status: 409,
107
+ });
108
+ } finally {
109
+ await cleanup(fixture);
110
+ }
111
+ });
112
+ });
113
+
114
+ it('does not start an expired payment session', async () => {
115
+ await app.bean.executor.mockCtx(async () => {
116
+ const fixture = await createFixture(new Date(Date.now() - 1));
117
+ try {
118
+ const scope = app.scope('a-pay');
119
+ await assert.rejects(scope.service.paymentSession.start(fixture.paymentSessionId!), {
120
+ status: 409,
121
+ });
122
+ assert.equal(
123
+ (await scope.model.paymentSession.getById(fixture.paymentSessionId!))?.state,
124
+ 'created',
125
+ );
126
+ } finally {
127
+ await cleanup(fixture);
128
+ }
129
+ });
130
+ });
131
+
132
+ it('allows only one competing start to call the provider', async () => {
133
+ const fixture = await app.bean.executor.mockCtx(async () => {
134
+ return await createFixture(new Date(Date.now() + 60_000));
135
+ });
136
+ try {
137
+ const results = await Promise.allSettled([
138
+ app.bean.executor.mockCtx(async () => {
139
+ return await app.scope('a-pay').service.paymentSession.start(fixture.paymentSessionId!);
140
+ }),
141
+ app.bean.executor.mockCtx(async () => {
142
+ return await app.scope('a-pay').service.paymentSession.start(fixture.paymentSessionId!);
143
+ }),
144
+ ]);
145
+ assert.equal(results.filter(result => result.status === 'fulfilled').length, 1);
146
+ assert.equal(results.filter(result => result.status === 'rejected').length, 1);
147
+ } finally {
148
+ await app.bean.executor.mockCtx(async () => {
149
+ await cleanup(fixture);
150
+ });
151
+ }
152
+ });
153
+ });