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
@@ -1 +1,3 @@
1
+ export * from './types/index.ts';
2
+ export * from './lib/index.ts';
1
3
  export * from './.metadata/index.ts';
@@ -0,0 +1,54 @@
1
+ import type { TableIdentity } from 'table-identity';
2
+ import type { IRefundOutcomeEvent } from 'vona-module-a-pay';
3
+
4
+ import { BeanBase } from 'vona';
5
+ import { Service } from 'vona-module-a-bean';
6
+ import { Core } from 'vona-module-a-core';
7
+
8
+ import type { EntityPaymentAttempt } from '../entity/paymentAttempt.tsx';
9
+
10
+ @Service()
11
+ export class ServiceCommercePayScene extends BeanBase {
12
+ async createSession(attempt: EntityPaymentAttempt) {
13
+ const session = await this.$scope.pay.service.paymentSession.create({
14
+ userId: attempt.userId,
15
+ payScene: 'commerce-payment:commerceOrder',
16
+ businessReference: String(attempt.id),
17
+ amountMinor: attempt.amountCents,
18
+ currency: attempt.currency,
19
+ correlationId: `${attempt.correlationId}:session`,
20
+ });
21
+ await this.scope.model.paymentAttempt.updateById(attempt.id, {
22
+ paymentSessionId: session.id,
23
+ providerName: session.providerName,
24
+ });
25
+ return session;
26
+ }
27
+
28
+ @Core.transaction({ isolationLevel: 'SERIALIZABLE' })
29
+ async linkRefundOperation(refundAttemptId: TableIdentity, refundOperationId: TableIdentity) {
30
+ const refundAttempt = await this.scope.model.refundAttempt.getByIdForUpdate(refundAttemptId);
31
+ if (!refundAttempt) this.app.throw(404, 'commerce refund attempt not found');
32
+ await this.scope.model.refundAttempt.updateById(refundAttempt.id, { refundOperationId });
33
+ return { ...refundAttempt, refundOperationId };
34
+ }
35
+
36
+ @Core.transaction({ isolationLevel: 'SERIALIZABLE' })
37
+ async acceptRefundOutcome(event: IRefundOutcomeEvent) {
38
+ const refundAttempt = await this.scope.model.refundAttempt.getForUpdate({
39
+ refundOperationId: event.refundOperationId,
40
+ });
41
+ if (!refundAttempt) this.app.throw(404, 'commerce refund attempt not found');
42
+ if (
43
+ refundAttempt.amountCents !== event.amountMinor ||
44
+ refundAttempt.currency !== event.currency
45
+ ) {
46
+ this.app.throw(409, 'commerce refund amount conflicts with the refund operation');
47
+ }
48
+ if (refundAttempt.state !== 'created') return refundAttempt;
49
+ await this.scope.model.refundAttempt.updateById(refundAttempt.id, {
50
+ providerRefundId: event.providerRefundId,
51
+ });
52
+ return { ...refundAttempt, providerRefundId: event.providerRefundId };
53
+ }
54
+ }
@@ -22,7 +22,7 @@ export type TypePaymentAttemptFinalState = Extract<
22
22
  @Service()
23
23
  export class ServicePaymentAttempt extends BeanBase {
24
24
  async create(command: IPaymentAttemptCreateCommand): Promise<EntityPaymentAttempt> {
25
- return await this.scope.model.paymentAttempt.insert({
25
+ const attempt = await this.scope.model.paymentAttempt.insert({
26
26
  orderId: command.orderId,
27
27
  userId: command.userId,
28
28
  state: 'created',
@@ -30,6 +30,12 @@ export class ServicePaymentAttempt extends BeanBase {
30
30
  amountCents: command.amountCents,
31
31
  correlationId: command.correlationId,
32
32
  });
33
+ const session = await this.scope.service.commercePayScene.createSession(attempt);
34
+ return {
35
+ ...attempt,
36
+ paymentSessionId: session.id,
37
+ providerName: session.providerName,
38
+ };
33
39
  }
34
40
 
35
41
  async finalize(
@@ -9,8 +9,11 @@ describe('paymentAttempt.test.ts', { concurrency: false }, () => {
9
9
  const scope = app.scope('commerce-payment');
10
10
  const suffix = randomUUID().slice(0, 12);
11
11
  let attemptId: number | undefined;
12
+ let paymentSessionId: number | undefined;
13
+ let userId: number | undefined;
12
14
  try {
13
15
  const user = await app.bean.user.register({ name: `payment-${suffix}` }, true);
16
+ userId = user.id as number;
14
17
  const created = await scope.service.paymentAttempt.create({
15
18
  orderId: 900_001,
16
19
  userId: user.id,
@@ -19,14 +22,32 @@ describe('paymentAttempt.test.ts', { concurrency: false }, () => {
19
22
  correlationId: `payment-${suffix}`,
20
23
  });
21
24
  attemptId = created.id as number;
25
+ paymentSessionId = created.paymentSessionId as number;
22
26
  assert.equal(created.state, 'created');
27
+ const session = await app.scope('a-pay').model.paymentSession.getById(paymentSessionId);
28
+ assert.equal(session?.payScene, 'commerce-payment:commerceOrder');
29
+ assert.equal(session?.providerName, 'pay-mock:mock');
30
+ assert.equal(session?.clientName, 'default');
31
+ assert.equal(session?.environment, 'sandbox');
32
+ assert.ok((session?.expiresAt.getTime() ?? 0) > Date.now() + 29 * 60 * 1000);
23
33
  const cancelled = await scope.service.paymentAttempt.cancel(created.orderId);
24
34
  assert.equal(cancelled?.state, 'cancelled');
25
35
  const replay = await scope.service.paymentAttempt.cancel(created.orderId);
26
36
  assert.equal(replay?.id, created.id);
27
37
  assert.equal(replay?.state, 'cancelled');
28
38
  } finally {
39
+ if (paymentSessionId !== undefined) {
40
+ const pay = app.scope('a-pay');
41
+ await pay.model.outboxEvent.delete({ paymentSessionId });
42
+ await pay.model.paymentAudit.delete({ paymentSessionId });
43
+ await pay.model.webhookInbox.delete({ paymentSessionId });
44
+ await pay.model.paymentSession.delete({ id: paymentSessionId });
45
+ }
29
46
  if (attemptId !== undefined) await scope.model.paymentAttempt.delete({ id: attemptId });
47
+ if (userId !== undefined) {
48
+ await app.scope('home-user').model.roleUser.delete({ userId });
49
+ await app.bean.user.removeById(userId);
50
+ }
30
51
  }
31
52
  });
32
53
  });
@@ -148,7 +148,17 @@ declare module 'vona-module-commerce-promotion' {
148
148
  [SymbolKeyEntityMeta]: EntityCouponAuditMeta;
149
149
  [SymbolKeyModelOptions]: IModelOptionsCouponAudit;
150
150
  get<T extends IModelGetOptions<EntityCouponAudit,ModelCouponAudit>>(where: TypeModelWhere<EntityCouponAudit>, options?: T): Promise<TypeModelRelationResult<EntityCouponAudit, ModelCouponAudit, T> | undefined>;
151
+ /**
152
+ * Retrieves one matching primary row with a pessimistic FOR UPDATE lock.
153
+ * Requires an active transaction. The lock is released when that transaction completes.
154
+ * Entity and query caches are bypassed.
155
+ */
151
156
  getForUpdate<T extends IModelGetOptions<EntityCouponAudit,ModelCouponAudit>>(where: TypeModelWhere<EntityCouponAudit>, options?: T): Promise<TypeModelRelationResult<EntityCouponAudit, ModelCouponAudit, T> | undefined>;
157
+ /**
158
+ * Retrieves a primary row by ID with the same pessimistic FOR UPDATE lock semantics.
159
+ * Requires an active transaction. The lock is released when that transaction completes.
160
+ * Entity and query caches are bypassed.
161
+ */
152
162
  getByIdForUpdate<T extends IModelGetOptions<EntityCouponAudit,ModelCouponAudit>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityCouponAudit, ModelCouponAudit, T> | undefined>;
153
163
  mget<T extends IModelGetOptions<EntityCouponAudit,ModelCouponAudit>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityCouponAudit, ModelCouponAudit, T>[]>;
154
164
  selectAndCount<T extends IModelSelectParams<EntityCouponAudit,ModelCouponAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityCouponAudit, ModelCouponAudit, T>>;
@@ -175,7 +185,17 @@ export interface ModelCouponGrant {
175
185
  [SymbolKeyEntityMeta]: EntityCouponGrantMeta;
176
186
  [SymbolKeyModelOptions]: IModelOptionsCouponGrant;
177
187
  get<T extends IModelGetOptions<EntityCouponGrant,ModelCouponGrant>>(where: TypeModelWhere<EntityCouponGrant>, options?: T): Promise<TypeModelRelationResult<EntityCouponGrant, ModelCouponGrant, T> | undefined>;
188
+ /**
189
+ * Retrieves one matching primary row with a pessimistic FOR UPDATE lock.
190
+ * Requires an active transaction. The lock is released when that transaction completes.
191
+ * Entity and query caches are bypassed.
192
+ */
178
193
  getForUpdate<T extends IModelGetOptions<EntityCouponGrant,ModelCouponGrant>>(where: TypeModelWhere<EntityCouponGrant>, options?: T): Promise<TypeModelRelationResult<EntityCouponGrant, ModelCouponGrant, T> | undefined>;
194
+ /**
195
+ * Retrieves a primary row by ID with the same pessimistic FOR UPDATE lock semantics.
196
+ * Requires an active transaction. The lock is released when that transaction completes.
197
+ * Entity and query caches are bypassed.
198
+ */
179
199
  getByIdForUpdate<T extends IModelGetOptions<EntityCouponGrant,ModelCouponGrant>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityCouponGrant, ModelCouponGrant, T> | undefined>;
180
200
  mget<T extends IModelGetOptions<EntityCouponGrant,ModelCouponGrant>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityCouponGrant, ModelCouponGrant, T>[]>;
181
201
  selectAndCount<T extends IModelSelectParams<EntityCouponGrant,ModelCouponGrant,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityCouponGrant, ModelCouponGrant, T>>;
@@ -202,7 +222,17 @@ export interface ModelCouponTemplate {
202
222
  [SymbolKeyEntityMeta]: EntityCouponTemplateMeta;
203
223
  [SymbolKeyModelOptions]: IModelOptionsCouponTemplate;
204
224
  get<T extends IModelGetOptions<EntityCouponTemplate,ModelCouponTemplate>>(where: TypeModelWhere<EntityCouponTemplate>, options?: T): Promise<TypeModelRelationResult<EntityCouponTemplate, ModelCouponTemplate, T> | undefined>;
225
+ /**
226
+ * Retrieves one matching primary row with a pessimistic FOR UPDATE lock.
227
+ * Requires an active transaction. The lock is released when that transaction completes.
228
+ * Entity and query caches are bypassed.
229
+ */
205
230
  getForUpdate<T extends IModelGetOptions<EntityCouponTemplate,ModelCouponTemplate>>(where: TypeModelWhere<EntityCouponTemplate>, options?: T): Promise<TypeModelRelationResult<EntityCouponTemplate, ModelCouponTemplate, T> | undefined>;
231
+ /**
232
+ * Retrieves a primary row by ID with the same pessimistic FOR UPDATE lock semantics.
233
+ * Requires an active transaction. The lock is released when that transaction completes.
234
+ * Entity and query caches are bypassed.
235
+ */
206
236
  getByIdForUpdate<T extends IModelGetOptions<EntityCouponTemplate,ModelCouponTemplate>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityCouponTemplate, ModelCouponTemplate, T> | undefined>;
207
237
  mget<T extends IModelGetOptions<EntityCouponTemplate,ModelCouponTemplate>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityCouponTemplate, ModelCouponTemplate, T>[]>;
208
238
  selectAndCount<T extends IModelSelectParams<EntityCouponTemplate,ModelCouponTemplate,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityCouponTemplate, ModelCouponTemplate, T>>;
@@ -1,5 +1,6 @@
1
1
  export default {
2
2
  ActorId: 'Actor ID',
3
+ BasicInformation: 'Basic Information',
3
4
  CouponAudit: 'Coupon Audit',
4
5
  CouponCode: 'Coupon Code',
5
6
  CouponGrant: 'Coupon Grant',
@@ -13,6 +14,7 @@ export default {
13
14
  Currency: 'Currency',
14
15
  Description: 'Description',
15
16
  DiscountCents: 'Fixed Discount (Cents)',
17
+ DiscountPolicy: 'Discount Policy',
16
18
  FromState: 'Previous State',
17
19
  IssuedCount: 'Issued Count',
18
20
  MinSpendCents: 'Minimum Spend (Cents)',
@@ -31,7 +33,9 @@ export default {
31
33
  ToState: 'New State',
32
34
  TotalIssueLimit: 'Total Issue Limit',
33
35
  TotalUsageLimit: 'Total Usage Limit',
36
+ UsageLimits: 'Usage Limits',
34
37
  UserId: 'User ID',
35
38
  ValidFrom: 'Valid From',
39
+ ValidityWindow: 'Validity Window',
36
40
  ValidUntil: 'Valid Until',
37
41
  };
@@ -1,5 +1,6 @@
1
1
  export default {
2
2
  ActorId: '操作人 ID',
3
+ BasicInformation: '基本信息',
3
4
  CouponAudit: '优惠券审计',
4
5
  CouponCode: '优惠券代码',
5
6
  CouponGrant: '优惠券发放',
@@ -13,6 +14,7 @@ export default {
13
14
  Currency: '币种',
14
15
  Description: '描述',
15
16
  DiscountCents: '固定优惠(分)',
17
+ DiscountPolicy: '优惠策略',
16
18
  FromState: '原状态',
17
19
  IssuedCount: '已发放数',
18
20
  MinSpendCents: '最低消费(分)',
@@ -31,7 +33,9 @@ export default {
31
33
  ToState: '新状态',
32
34
  TotalIssueLimit: '总发放上限',
33
35
  TotalUsageLimit: '总使用上限',
36
+ UsageLimits: '使用限制',
34
37
  UserId: '用户 ID',
35
38
  ValidFrom: '开始时间',
39
+ ValidityWindow: '有效期',
36
40
  ValidUntil: '结束时间',
37
41
  };
@@ -3,10 +3,97 @@ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
3
3
  import { Api, v } from 'vona-module-a-openapiutils';
4
4
  import { Dto } from 'vona-module-a-web';
5
5
  import { z } from 'zod';
6
+ import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
7
+
8
+ import { $locale } from '../.metadata/locales.ts';
6
9
 
7
10
  export interface IDtoOptionsCouponTemplateCreate extends IDecoratorDtoOptions {}
8
11
 
9
- @Dto<IDtoOptionsCouponTemplateCreate>()
12
+ @Dto<IDtoOptionsCouponTemplateCreate>({
13
+ blocks: [
14
+ ZovaRender.block('basic-pageentry:blockPageEntry', {
15
+ blocks: [
16
+ ZovaRender.block('basic-pageentry:blockForm', {
17
+ blocks: [
18
+ ZovaRender.block('basic-form:blockFormLayout', {
19
+ formLayout: {
20
+ children: [
21
+ {
22
+ type: 'group',
23
+ title: $locale('BasicInformation'),
24
+ children: [
25
+ {
26
+ type: 'section',
27
+ columns: { default: 1, md: 2 },
28
+ children: [
29
+ { type: 'field', name: 'name' },
30
+ { type: 'field', name: 'state' },
31
+ { type: 'field', name: 'description', span: { default: 1, md: 2 } },
32
+ ],
33
+ },
34
+ ],
35
+ },
36
+ {
37
+ type: 'group',
38
+ title: $locale('DiscountPolicy'),
39
+ children: [
40
+ {
41
+ type: 'section',
42
+ columns: { default: 1, md: 2 },
43
+ children: [
44
+ { type: 'field', name: 'currency' },
45
+ { type: 'field', name: 'discountCents' },
46
+ { type: 'field', name: 'minSpendCents' },
47
+ ],
48
+ },
49
+ ],
50
+ },
51
+ {
52
+ type: 'group',
53
+ title: $locale('ValidityWindow'),
54
+ children: [
55
+ {
56
+ type: 'section',
57
+ columns: { default: 1, md: 2 },
58
+ children: [
59
+ { type: 'field', name: 'validFrom' },
60
+ { type: 'field', name: 'validUntil' },
61
+ ],
62
+ },
63
+ ],
64
+ },
65
+ {
66
+ type: 'group',
67
+ title: $locale('UsageLimits'),
68
+ children: [
69
+ {
70
+ type: 'section',
71
+ columns: { default: 1, md: 2 },
72
+ children: [
73
+ { type: 'field', name: 'totalIssueLimit' },
74
+ { type: 'field', name: 'totalUsageLimit' },
75
+ { type: 'field', name: 'perCustomerIssueLimit' },
76
+ ],
77
+ },
78
+ ],
79
+ },
80
+ ],
81
+ },
82
+ }),
83
+ ],
84
+ }),
85
+ ZovaRender.block('basic-pageentry:blockToolbarRow', {
86
+ actions: [
87
+ ZovaRender.formActionRow('basic-form:actionSubmit', {
88
+ permission: { actionInherit: 'update', formScene: ['create', 'edit'] },
89
+ }),
90
+ ZovaRender.formActionRow('basic-form:actionBack', { permission: { public: true } }),
91
+ ],
92
+ }),
93
+ ],
94
+ }),
95
+ ],
96
+ })
10
97
  export class DtoCouponTemplateCreate {
11
98
  @Api.field(v.required(), v.min(2), v.max(100))
12
99
  name: string;
@@ -3,10 +3,53 @@ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
3
3
  import { Api, v } from 'vona-module-a-openapiutils';
4
4
  import { Dto } from 'vona-module-a-web';
5
5
  import { z } from 'zod';
6
+ import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
7
+
8
+ import { $locale } from '../.metadata/locales.ts';
6
9
 
7
10
  export interface IDtoOptionsCouponTemplateUpdate extends IDecoratorDtoOptions {}
8
11
 
9
- @Dto<IDtoOptionsCouponTemplateUpdate>()
12
+ @Dto<IDtoOptionsCouponTemplateUpdate>({
13
+ blocks: [
14
+ ZovaRender.block('basic-pageentry:blockPageEntry', {
15
+ blocks: [
16
+ ZovaRender.block('basic-pageentry:blockForm', {
17
+ blocks: [
18
+ ZovaRender.block('basic-form:blockFormLayout', {
19
+ formLayout: {
20
+ children: [
21
+ {
22
+ type: 'group',
23
+ title: $locale('BasicInformation'),
24
+ children: [
25
+ {
26
+ type: 'section',
27
+ columns: { default: 1, md: 2 },
28
+ children: [
29
+ { type: 'field', name: 'name' },
30
+ { type: 'field', name: 'state' },
31
+ { type: 'field', name: 'description', span: { default: 1, md: 2 } },
32
+ ],
33
+ },
34
+ ],
35
+ },
36
+ ],
37
+ },
38
+ }),
39
+ ],
40
+ }),
41
+ ZovaRender.block('basic-pageentry:blockToolbarRow', {
42
+ actions: [
43
+ ZovaRender.formActionRow('basic-form:actionSubmit', {
44
+ permission: { actionInherit: 'update', formScene: ['create', 'edit'] },
45
+ }),
46
+ ZovaRender.formActionRow('basic-form:actionBack', { permission: { public: true } }),
47
+ ],
48
+ }),
49
+ ],
50
+ }),
51
+ ],
52
+ })
10
53
  export class DtoCouponTemplateUpdate {
11
54
  @Api.field(v.optional(), v.min(2), v.max(100))
12
55
  name?: string;
@@ -4,6 +4,7 @@ import { $Dto } from 'vona-module-a-orm';
4
4
  import { Dto } from 'vona-module-a-web';
5
5
  import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
6
6
 
7
+ import { $locale } from '../.metadata/locales.ts';
7
8
  import { ModelCouponTemplate } from '../model/couponTemplate.ts';
8
9
 
9
10
  export interface IDtoOptionsCouponTemplateView extends IDecoratorDtoOptions {}
@@ -12,7 +13,77 @@ export interface IDtoOptionsCouponTemplateView extends IDecoratorDtoOptions {}
12
13
  blocks: [
13
14
  ZovaRender.block('basic-pageentry:blockPageEntry', {
14
15
  blocks: [
15
- ZovaRender.block('basic-pageentry:blockForm'),
16
+ ZovaRender.block('basic-pageentry:blockForm', {
17
+ blocks: [
18
+ ZovaRender.block('basic-form:blockFormLayout', {
19
+ formLayout: {
20
+ children: [
21
+ {
22
+ type: 'group',
23
+ title: $locale('BasicInformation'),
24
+ children: [
25
+ {
26
+ type: 'section',
27
+ columns: { default: 1, md: 2 },
28
+ children: [
29
+ { type: 'field', name: 'name' },
30
+ { type: 'field', name: 'state' },
31
+ { type: 'field', name: 'description', span: { default: 1, md: 2 } },
32
+ ],
33
+ },
34
+ ],
35
+ },
36
+ {
37
+ type: 'group',
38
+ title: $locale('DiscountPolicy'),
39
+ children: [
40
+ {
41
+ type: 'section',
42
+ columns: { default: 1, md: 2 },
43
+ children: [
44
+ { type: 'field', name: 'currency' },
45
+ { type: 'field', name: 'discountCents' },
46
+ { type: 'field', name: 'minSpendCents' },
47
+ ],
48
+ },
49
+ ],
50
+ },
51
+ {
52
+ type: 'group',
53
+ title: $locale('ValidityWindow'),
54
+ children: [
55
+ {
56
+ type: 'section',
57
+ columns: { default: 1, md: 2 },
58
+ children: [
59
+ { type: 'field', name: 'validFrom' },
60
+ { type: 'field', name: 'validUntil' },
61
+ ],
62
+ },
63
+ ],
64
+ },
65
+ {
66
+ type: 'group',
67
+ title: $locale('UsageLimits'),
68
+ children: [
69
+ {
70
+ type: 'section',
71
+ columns: { default: 1, md: 2 },
72
+ children: [
73
+ { type: 'field', name: 'totalIssueLimit' },
74
+ { type: 'field', name: 'totalUsageLimit' },
75
+ { type: 'field', name: 'perCustomerIssueLimit' },
76
+ { type: 'field', name: 'issuedCount' },
77
+ { type: 'field', name: 'redeemedCount' },
78
+ ],
79
+ },
80
+ ],
81
+ },
82
+ ],
83
+ },
84
+ }),
85
+ ],
86
+ }),
16
87
  ZovaRender.block('basic-pageentry:blockToolbarRow', {
17
88
  actions: [
18
89
  ZovaRender.formActionRow('basic-form:actionBack', { permission: { public: true } }),
@@ -0,0 +1,121 @@
1
+ import assert from 'node:assert';
2
+ import { describe, it } from 'node:test';
3
+ import { app } from 'vona-mock';
4
+ import {
5
+ DtoCouponTemplateCreate,
6
+ DtoCouponTemplateSelectResItem,
7
+ DtoCouponTemplateUpdate,
8
+ DtoCouponTemplateView,
9
+ } from 'vona-module-commerce-promotion';
10
+
11
+ function getEntryFormLayout(component: any) {
12
+ const pageEntry = component?.rest?.blocks?.[0];
13
+ const formBlock = pageEntry?.options?.blocks?.[0];
14
+ const layoutBlock = formBlock?.options?.blocks?.[0];
15
+ assert.equal(pageEntry?.render, 'basic-pageentry:blockPageEntry');
16
+ assert.equal(formBlock?.render, 'basic-pageentry:blockForm');
17
+ assert.equal(layoutBlock?.render, 'basic-form:blockFormLayout');
18
+ return layoutBlock?.options?.formLayout;
19
+ }
20
+
21
+ function getGroupFields(group: any) {
22
+ const section = group?.children?.[0];
23
+ assert.equal(group?.type, 'group');
24
+ assert.equal(section?.type, 'section');
25
+ assert.deepEqual(section?.columns, { default: 1, md: 2 });
26
+ return section?.children;
27
+ }
28
+
29
+ function findComponent(apiJson: any, predicate: (properties: any) => boolean) {
30
+ return Object.values(apiJson.components!.schemas as any).find(item => {
31
+ return predicate((item as any).properties);
32
+ });
33
+ }
34
+
35
+ describe('couponTemplateFormLayout.test.ts', () => {
36
+ it('action:couponTemplate:formLayoutMetadata', async () => {
37
+ await app.bean.executor.mockCtx(async () => {
38
+ const createJson = await app.bean.openapi.generateJsonOfClass(DtoCouponTemplateCreate);
39
+ const createComponent = findComponent(createJson, properties => {
40
+ return properties?.discountCents && properties?.totalIssueLimit;
41
+ });
42
+ const createLayout = getEntryFormLayout(createComponent);
43
+ assert.deepEqual(
44
+ createLayout?.children.map((group: any) =>
45
+ getGroupFields(group).map((field: any) => field.name),
46
+ ),
47
+ [
48
+ ['name', 'state', 'description'],
49
+ ['currency', 'discountCents', 'minSpendCents'],
50
+ ['validFrom', 'validUntil'],
51
+ ['totalIssueLimit', 'totalUsageLimit', 'perCustomerIssueLimit'],
52
+ ],
53
+ );
54
+ assert.deepEqual(getGroupFields(createLayout?.children[0])?.[2]?.span, { default: 1, md: 2 });
55
+
56
+ const updateJson = await app.bean.openapi.generateJsonOfClass(DtoCouponTemplateUpdate);
57
+ const updateComponent = findComponent(updateJson, properties => {
58
+ return (
59
+ properties?.name && properties?.state && properties?.description && !properties?.currency
60
+ );
61
+ });
62
+ const updateLayout = getEntryFormLayout(updateComponent);
63
+ assert.equal(updateLayout?.children.length, 1);
64
+ assert.deepEqual(
65
+ getGroupFields(updateLayout?.children[0]).map((field: any) => field.name),
66
+ ['name', 'state', 'description'],
67
+ );
68
+ assert.deepEqual(getGroupFields(updateLayout?.children[0])?.[2]?.span, { default: 1, md: 2 });
69
+
70
+ const viewJson = await app.bean.openapi.generateJsonOfClass(DtoCouponTemplateView);
71
+ const viewComponent = findComponent(viewJson, properties => {
72
+ return properties?.issuedCount && properties?.redeemedCount;
73
+ });
74
+ const viewLayout = getEntryFormLayout(viewComponent);
75
+ assert.deepEqual(
76
+ viewLayout?.children.map((group: any) =>
77
+ getGroupFields(group).map((field: any) => field.name),
78
+ ),
79
+ [
80
+ ['name', 'state', 'description'],
81
+ ['currency', 'discountCents', 'minSpendCents'],
82
+ ['validFrom', 'validUntil'],
83
+ [
84
+ 'totalIssueLimit',
85
+ 'totalUsageLimit',
86
+ 'perCustomerIssueLimit',
87
+ 'issuedCount',
88
+ 'redeemedCount',
89
+ ],
90
+ ],
91
+ );
92
+ });
93
+ });
94
+
95
+ it('action:couponTemplate:filterFormLayoutMetadata', async () => {
96
+ await app.bean.executor.mockCtx(async () => {
97
+ const apiJson = await app.bean.openapi.generateJsonOfClass(DtoCouponTemplateSelectResItem);
98
+ const component = findComponent(apiJson, properties => properties?._operationsRow);
99
+ const filterBlock = (component as any)?.rest?.blocks?.[0]?.options?.blocks?.[0];
100
+ assert.equal(filterBlock?.render, 'basic-page:blockFilter');
101
+ assert.equal(filterBlock?.options?.formFieldLayout?.inline, true);
102
+ assert.deepEqual(
103
+ filterBlock?.options?.blocks?.map((block: any) => block.render),
104
+ ['basic-form:blockFormLayout'],
105
+ );
106
+ const filterLayout = filterBlock?.options?.blocks?.[0]?.options?.formLayout;
107
+ const section = filterLayout?.children?.[0];
108
+ assert.equal(section?.type, 'section');
109
+ assert.equal(section?.layout, 'flow');
110
+ assert.deepEqual(
111
+ section?.children?.map((child: any) => child.type),
112
+ ['field', 'field', 'block'],
113
+ );
114
+ assert.deepEqual(
115
+ section?.children?.slice(0, 2).map((field: any) => field.name),
116
+ ['name', 'createdAt'],
117
+ );
118
+ assert.equal(section?.children?.[2]?.block?.render, 'basic-page:blockFilterActions');
119
+ });
120
+ });
121
+ });
@@ -13,7 +13,10 @@ export interface ISsrMenuOptionsHome extends IDecoratorSsrMenuOptions<ISsrSiteOp
13
13
  title: 'Commerce',
14
14
  order: $order(1),
15
15
  icon: undefined,
16
- link: '/',
16
+ link: '/:locale' as never,
17
+ meta: {
18
+ params: { locale: true },
19
+ },
17
20
  },
18
21
  site: ['commerce-siteweb:commerce'],
19
22
  })
@@ -30,7 +30,9 @@
30
30
  "prepack": "clean-package",
31
31
  "postpack": "clean-package restore"
32
32
  },
33
- "dependencies": {},
33
+ "dependencies": {
34
+ "vona-module-a-pay": "workspace:*"
35
+ },
34
36
  "devDependencies": {
35
37
  "clean-package": "^2.2.0",
36
38
  "rimraf": "^6.1.3"
@@ -46,6 +48,7 @@
46
48
  "title": "commerce-trade",
47
49
  "vonaModule": {
48
50
  "dependencies": {
51
+ "a-pay": "5.0.0",
49
52
  "a-vona": "5.0.0",
50
53
  "commerce-member": "5.0.0",
51
54
  "commerce-payment": "5.0.0",