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.
- package/.cabloy-version +1 -1
- package/.claude/skills/cabloy-frontend-scaffold/SKILL.md +13 -3
- package/.claude/skills/cabloy-workflow/SKILL.md +6 -0
- package/.claude/skills/cabloy-workflow/evals/evals.json +6 -0
- package/CHANGELOG.md +24 -0
- package/CLAUDE.md +1 -1
- package/cabloy-docs/.vitepress/config.mjs +4 -0
- package/cabloy-docs/frontend/form-layout-guide.md +29 -7
- package/cabloy-docs/fullstack/parallel-worktree-environment.md +87 -0
- package/e2e/scripts/e2e.ts +13 -1
- package/e2e/scripts/startE2eVona.ts +4 -1
- package/e2e/specs/a-commerce/commerce.spec.ts +129 -32
- package/package.json +2 -1
- package/playwright-report/data/24ac790ec112339c76cfb0c8e2c2539c2f953a0b.zip +0 -0
- package/playwright-report/data/2fddcabcdbd0b695061a565acfff243cb3a4f5e3.zip +0 -0
- package/playwright-report/data/4738038d9e861d63fd25937c9a3570934786a62f.zip +0 -0
- package/playwright-report/data/72f99c7da67c7f6ea53cab7d8681798b70d79a10.md +222 -0
- package/playwright-report/data/7b9684a7c793e9798b898f8ff50177b660a7a733.md +222 -0
- package/playwright-report/data/8b31595f5f1cc9d23863af51a592e6b90dcbc4ce.zip +0 -0
- package/playwright-report/data/95b578407a68806202dda917a61c50c750bd285b.md +222 -0
- package/playwright-report/data/ad960b3a58f224f5b4cad04a24067600064ffb7b.md +222 -0
- package/playwright-report/index.html +90 -0
- package/playwright-report/trace/assets/codeMirrorModule-LEHpjmcn.js +32 -0
- package/playwright-report/trace/assets/defaultSettingsView-BNmKHKpQ.js +264 -0
- package/playwright-report/trace/assets/urlMatch-BYQrIQwR.js +1 -0
- package/playwright-report/trace/codeMirrorModule.DYBRYzYX.css +1 -0
- package/playwright-report/trace/codicon.DCmgc-ay.ttf +0 -0
- package/playwright-report/trace/defaultSettingsView.CjdS-WJx.css +1 -0
- package/playwright-report/trace/index.CzXZzn5A.css +1 -0
- package/playwright-report/trace/index.DMMX1gXU.js +2 -0
- package/playwright-report/trace/index.html +44 -0
- package/playwright-report/trace/manifest.webmanifest +16 -0
- package/playwright-report/trace/playwright-logo.svg +9 -0
- package/playwright-report/trace/snapshot.html +10 -0
- package/playwright-report/trace/snapshot.v8KI4P3m.js +2 -0
- package/playwright-report/trace/sw.bundle.js +5 -0
- package/playwright-report/trace/uiMode.BZQ54Kgt.css +1 -0
- package/playwright-report/trace/uiMode.Ut8wwJNp.js +6 -0
- package/playwright-report/trace/uiMode.html +18 -0
- package/playwright-report/trace/xtermModule.DYP7pi_n.css +32 -0
- package/vona/env/.env +12 -0
- package/vona/env/.env.test +7 -0
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}Create.tsx_ +19 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}Update.tsx_ +19 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/boilerplate/src/dto/{{resourceName}}View.tsx_ +19 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/3-en-us.ts +6 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudBasic/snippets/4-zh-cn.ts +6 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}Create.tsx_ +19 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}Update.tsx_ +19 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/boilerplate/src/dto/{{resourceName}}View.tsx_ +19 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/snippets/3-en-us.ts +6 -1
- package/vona/packages-cli/cli-set-api/cli/templates/tools/crudStart/snippets/4-zh-cn.ts +6 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/pnpm-lock.yaml +255 -12
- package/vona/pnpm-workspace.yaml +1 -1
- package/vona/src/suite/a-commerce/modules/commerce-payment/package.json +4 -1
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/.metadata/index.ts +45 -3
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.index.ts +1 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.version.ts +25 -1
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/payScene.commerceOrder.ts +20 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/paymentAttempt.tsx +9 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/paymentAudit.tsx +5 -2
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/refundAttempt.tsx +6 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/index.ts +2 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/lib/index.ts +1 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +54 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/paymentAttempt.ts +7 -1
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/types/index.ts +1 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +21 -0
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/.metadata/index.ts +30 -0
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/en-us.ts +4 -0
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/config/locale/zh-cn.ts +4 -0
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateCreate.tsx +88 -1
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateUpdate.tsx +44 -1
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponTemplateView.tsx +72 -1
- package/vona/src/suite/a-commerce/modules/commerce-promotion/test/couponTemplateFormLayout.test.ts +121 -0
- package/vona/src/suite/a-commerce/modules/commerce-siteweb/src/bean/ssrMenu.home.ts +4 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/package.json +4 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +0 -21
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/checkoutResult.tsx +3 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +79 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +227 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +121 -13
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +312 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +76 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +842 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payProvider.ts +92 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payScene.ts +105 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +28 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.redlock.ts +11 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +113 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/queue.outboxDispatch.ts +31 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.outboxDispatch.ts +11 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/controller/paymentSession.ts +55 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/controller/webhook.ts +47 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/dto/paymentSessionStart.tsx +8 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/dto/paymentSessionView.tsx +69 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/dto/webhookReceipt.tsx +12 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/outboxEvent.tsx +46 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentAudit.tsx +36 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentSession.tsx +72 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +54 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/refundOperation.tsx +37 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/webhookInbox.tsx +59 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/index.ts +3 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/index.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/payProvider.ts +7 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/lib/payScene.ts +7 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/outboxEvent.ts +10 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentAudit.ts +10 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +10 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/providerOperation.ts +10 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/refundOperation.ts +10 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/webhookInbox.ts +10 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/outbox.ts +156 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +278 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +5 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +127 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/index.ts +3 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts +74 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payScene.ts +63 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +151 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/test/outbox.test.ts +209 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/test/paymentSession.test.ts +153 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/test/webhook.test.ts +278 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +55 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/index.ts +182 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/bean/payProvider.mock.ts +149 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/controller/mockPayment.ts +25 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockPaymentComplete.tsx +13 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/dto/mockPaymentReceipt.tsx +16 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/index.ts +3 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/lib/index.ts +1 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +78 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/types/index.ts +10 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/test/payMock.test.ts +141 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +55 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/index.ts +62 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +91 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/index.ts +3 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/index.ts +1 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/types/index.ts +9 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +55 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/index.ts +62 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/this.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/bean/payProvider.stripe.ts +88 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/index.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/types/index.ts +8 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.build.json +11 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.json +7 -0
- package/vona/src/suite-vendor/a-pay/package.json +15 -0
- package/vona/src/suite-vendor/a-pay/tsconfig.base.json +4 -0
- package/vona/src/suite-vendor/a-pay/tsconfig.json +19 -0
- package/zova/env/.env +1 -0
- package/zova/openapi.config.ts +5 -1
- package/zova/package.original.json +1 -1
- package/zova/packages-cli/cli/package.json +2 -2
- package/zova/packages-cli/cli-set-front/cli/templates/openapi/config/boilerplate/project/openapi.config.ts +5 -1
- package/zova/packages-cli/cli-set-front/package.json +1 -1
- package/zova/packages-cli/cli-set-front/src/lib/bean/cli.openapi.generate.ts +8 -0
- package/zova/packages-cli/cli-set-front/src/lib/common/cliCreatePage.ts +7 -24
- package/zova/packages-cli/cli-set-front/src/lib/common/utils.ts +10 -1
- package/zova/packages-utils/zova-jsx/package.json +2 -2
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +1 -1
- package/zova/packages-zova/zova-core/src/types/interface/component.ts +5 -0
- package/zova/pnpm-lock.yaml +96 -26
- package/zova/src/front/config/config/config.cabloyCommerce.ts +1 -1
- package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/schemas.ts +110 -12
- package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/types.ts +1292 -160
- package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +0 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/package.json +4 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +1 -47
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +23 -8
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +249 -62
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +5 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +152 -39
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +1 -1
- package/zova/src/suite-vendor/a-pay/modules/a-pay/cli/openapi.config.ts +9 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/package.json +53 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/component/paymentNextAction.ts +31 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +217 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/this.ts +2 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/index.ts +3 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/schemas.ts +584 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/types.ts +9324 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/paymentSession.ts +52 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/apiSchema/paymentSession.ts +20 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/component/paymentNextAction/controller.tsx +76 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/index.ts +3 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/lib/index.ts +1 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +32 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentCoordinator.ts +13 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/types/index.ts +1 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +25 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/tsconfig.build.json +13 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/tsconfig.json +5 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/cli/openapi.config.ts +9 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/package.json +53 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/index.ts +140 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/.metadata/this.ts +2 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/baseURL.ts +5 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/index.ts +3 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/schemas.ts +584 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/openapi/types.ts +9324 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/api/payMockPayment.ts +34 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/apiSchema/payMockPayment.ts +13 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/index.ts +1 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/src/model/payMockPayment.ts +20 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.build.json +13 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-mock/tsconfig.json +5 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-paypal/package.json +52 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/index.ts +26 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-paypal/src/.metadata/this.ts +2 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-paypal/src/index.ts +1 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.build.json +13 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-paypal/tsconfig.json +5 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-stripe/package.json +52 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/index.ts +26 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-stripe/src/.metadata/this.ts +2 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-stripe/src/index.ts +1 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.build.json +13 -0
- package/zova/src/suite-vendor/a-pay/modules/pay-stripe/tsconfig.json +5 -0
- package/zova/src/suite-vendor/a-pay/package.json +15 -0
- package/zova/src/suite-vendor/a-pay/tsconfig.base.json +4 -0
- package/zova/src/suite-vendor/a-pay/tsconfig.json +4 -0
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/package.json +2 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/payment.ts +0 -23
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradePayment.ts +0 -36
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradePayment.ts +0 -13
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/payment.ts +0 -25
- /package/vona/patches/{zova-core@5.1.79.patch → zova-core@5.1.81.patch} +0 -0
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
|
|
3
|
+
import { BeanBase } from 'vona';
|
|
4
|
+
import { Service } from 'vona-module-a-bean';
|
|
5
|
+
import { Core } from 'vona-module-a-core';
|
|
6
|
+
|
|
7
|
+
import type { EntityPaymentSession } from '../entity/paymentSession.tsx';
|
|
8
|
+
import type {
|
|
9
|
+
IPayProviderCapabilities,
|
|
10
|
+
IPayProviderPaymentSnapshot,
|
|
11
|
+
TypePaymentNextAction,
|
|
12
|
+
TypePaymentSessionState,
|
|
13
|
+
} from '../types/payment.ts';
|
|
14
|
+
import type { IDecoratorPaySceneOptions } from '../types/payScene.ts';
|
|
15
|
+
|
|
16
|
+
export interface IPaymentSessionCreateCommand {
|
|
17
|
+
userId: TableIdentity;
|
|
18
|
+
payScene: string;
|
|
19
|
+
businessReference: string;
|
|
20
|
+
amountMinor: number;
|
|
21
|
+
currency: string;
|
|
22
|
+
correlationId: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Service()
|
|
26
|
+
export class ServicePaymentSession extends BeanBase {
|
|
27
|
+
async create(command: IPaymentSessionCreateCommand): Promise<EntityPaymentSession> {
|
|
28
|
+
const sceneOptions = this.bean.payScene.getOptions(command.payScene as never);
|
|
29
|
+
this._assertCreateCommand(command, sceneOptions);
|
|
30
|
+
const provider = await this.bean.payScene.resolveProvider(command.payScene as never, command);
|
|
31
|
+
this._assertProviderCapabilities(provider.capabilities, sceneOptions);
|
|
32
|
+
const sessionExpiresIn = sceneOptions.sessionExpiresIn;
|
|
33
|
+
if (!Number.isSafeInteger(sessionExpiresIn) || !sessionExpiresIn || sessionExpiresIn < 0) {
|
|
34
|
+
this.app.throw(500, 'payment scene has an invalid session expiration');
|
|
35
|
+
}
|
|
36
|
+
return await this.scope.model.paymentSession.insert({
|
|
37
|
+
...command,
|
|
38
|
+
providerName: provider.providerName,
|
|
39
|
+
clientName: provider.clientName,
|
|
40
|
+
environment: provider.environment,
|
|
41
|
+
expiresAt: new Date(Date.now() + sessionExpiresIn),
|
|
42
|
+
state: 'created',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private _assertCreateCommand(
|
|
47
|
+
command: IPaymentSessionCreateCommand,
|
|
48
|
+
sceneOptions: IDecoratorPaySceneOptions,
|
|
49
|
+
) {
|
|
50
|
+
if (!Number.isSafeInteger(command.amountMinor) || command.amountMinor < 0) {
|
|
51
|
+
this.app.throw(422, 'payment amount is invalid');
|
|
52
|
+
}
|
|
53
|
+
if (sceneOptions.currencies && !sceneOptions.currencies.includes(command.currency)) {
|
|
54
|
+
this.app.throw(422, 'payment currency is not allowed by the payment scene');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private _assertProviderCapabilities(
|
|
59
|
+
capabilities: IPayProviderCapabilities,
|
|
60
|
+
sceneOptions: IDecoratorPaySceneOptions,
|
|
61
|
+
) {
|
|
62
|
+
if (
|
|
63
|
+
(sceneOptions.captureMode === 'automatic' && !capabilities.automaticCapture) ||
|
|
64
|
+
(sceneOptions.captureMode === 'manual' && !capabilities.manualCapture)
|
|
65
|
+
) {
|
|
66
|
+
this.app.throw(500, 'payment scene capture mode is not supported by the payment provider');
|
|
67
|
+
}
|
|
68
|
+
if (sceneOptions.refund?.enabled && !capabilities.refunds) {
|
|
69
|
+
this.app.throw(500, 'payment scene refunds are not supported by the payment provider');
|
|
70
|
+
}
|
|
71
|
+
if (sceneOptions.refund?.allowPartial && !capabilities.partialRefunds) {
|
|
72
|
+
this.app.throw(
|
|
73
|
+
500,
|
|
74
|
+
'payment scene partial refunds are not supported by the payment provider',
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async start(paymentSessionId: TableIdentity): Promise<EntityPaymentSession> {
|
|
80
|
+
const session = await this.beginStart(paymentSessionId);
|
|
81
|
+
const { provider, clientOptions } = this.bean.payProvider.resolveByName(
|
|
82
|
+
session.providerName,
|
|
83
|
+
session.clientName,
|
|
84
|
+
);
|
|
85
|
+
if (clientOptions.environment !== session.environment) {
|
|
86
|
+
this.app.throw(500, 'payment session provider environment is inconsistent');
|
|
87
|
+
}
|
|
88
|
+
const snapshot = await provider.startPayment(
|
|
89
|
+
{
|
|
90
|
+
paymentSessionId: session.id,
|
|
91
|
+
businessReference: session.businessReference,
|
|
92
|
+
idempotencyKey: `${session.correlationId}:start`,
|
|
93
|
+
amountMinor: session.amountMinor,
|
|
94
|
+
currency: session.currency,
|
|
95
|
+
providerOrderId: session.providerOrderId,
|
|
96
|
+
},
|
|
97
|
+
clientOptions,
|
|
98
|
+
);
|
|
99
|
+
if (isTerminalPaymentSnapshot(snapshot)) {
|
|
100
|
+
return await this.settleStartSnapshot(session.id, snapshot);
|
|
101
|
+
}
|
|
102
|
+
return await this.transition(session.id, snapshot.state, {
|
|
103
|
+
nextAction: snapshot.nextAction,
|
|
104
|
+
providerPaymentId: snapshot.providerPaymentId,
|
|
105
|
+
providerOrderId: snapshot.providerOrderId,
|
|
106
|
+
providerCaptureId: snapshot.providerCaptureId,
|
|
107
|
+
source: 'paymentSession.startProvider',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@Core.transaction()
|
|
112
|
+
async beginStart(paymentSessionId: TableIdentity): Promise<EntityPaymentSession> {
|
|
113
|
+
const session = await this.scope.model.paymentSession.getByIdForUpdate(paymentSessionId);
|
|
114
|
+
if (!session) this.app.throw(404, 'payment session not found');
|
|
115
|
+
if (session.state !== 'created') this.app.throw(409, 'payment session is not ready to start');
|
|
116
|
+
if (session.expiresAt <= new Date()) this.app.throw(409, 'payment session is expired');
|
|
117
|
+
return await this.transition(session.id, 'starting', { source: 'paymentSession.start' });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@Core.transaction()
|
|
121
|
+
async settleStartSnapshot(
|
|
122
|
+
paymentSessionId: TableIdentity,
|
|
123
|
+
snapshot: IPayProviderPaymentSnapshot & {
|
|
124
|
+
state: 'succeeded' | 'failed' | 'cancelled';
|
|
125
|
+
},
|
|
126
|
+
): Promise<EntityPaymentSession> {
|
|
127
|
+
const session = await this.scope.model.paymentSession.getByIdForUpdate(paymentSessionId);
|
|
128
|
+
if (!session) this.app.throw(404, 'payment session not found');
|
|
129
|
+
if (session.state !== 'starting') this.app.throw(409, 'payment session is not starting');
|
|
130
|
+
const finalizedAt = new Date();
|
|
131
|
+
await this.scope.model.paymentSession.updateById(session.id, {
|
|
132
|
+
state: snapshot.state,
|
|
133
|
+
nextAction: snapshot.nextAction,
|
|
134
|
+
providerPaymentId: snapshot.providerPaymentId,
|
|
135
|
+
providerOrderId: snapshot.providerOrderId,
|
|
136
|
+
providerCaptureId: snapshot.providerCaptureId,
|
|
137
|
+
finalizedAt,
|
|
138
|
+
});
|
|
139
|
+
await this.scope.model.paymentAudit.insert({
|
|
140
|
+
paymentSessionId: session.id,
|
|
141
|
+
fromState: session.state,
|
|
142
|
+
toState: snapshot.state,
|
|
143
|
+
correlationId: session.correlationId,
|
|
144
|
+
source: 'paymentSession.startProvider',
|
|
145
|
+
occurredAt: finalizedAt,
|
|
146
|
+
});
|
|
147
|
+
await this.scope.service.outbox.enqueue(session.id, 'payment.outcome.v1', {
|
|
148
|
+
eventId: `${session.correlationId}:start`,
|
|
149
|
+
paymentSessionId: session.id,
|
|
150
|
+
businessReference: session.businessReference,
|
|
151
|
+
providerName: session.providerName,
|
|
152
|
+
state: snapshot.state,
|
|
153
|
+
providerCaptureId: snapshot.providerCaptureId,
|
|
154
|
+
amountMinor: session.amountMinor,
|
|
155
|
+
currency: session.currency,
|
|
156
|
+
});
|
|
157
|
+
return { ...session, ...snapshot, state: snapshot.state, finalizedAt };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@Core.transaction()
|
|
161
|
+
async transitionFromWebhook(
|
|
162
|
+
paymentSessionId: TableIdentity,
|
|
163
|
+
options: {
|
|
164
|
+
state: Extract<TypePaymentSessionState, 'succeeded' | 'failed' | 'cancelled'>;
|
|
165
|
+
providerPaymentId?: string;
|
|
166
|
+
providerCaptureId?: string;
|
|
167
|
+
webhookInboxId: TableIdentity;
|
|
168
|
+
},
|
|
169
|
+
): Promise<{
|
|
170
|
+
session: EntityPaymentSession;
|
|
171
|
+
changed: boolean;
|
|
172
|
+
ignoredReason?: string;
|
|
173
|
+
}> {
|
|
174
|
+
const session = await this.scope.model.paymentSession.getByIdForUpdate(paymentSessionId);
|
|
175
|
+
if (!session) this.app.throw(404, 'payment session not found');
|
|
176
|
+
if (session.state === options.state) {
|
|
177
|
+
this._assertWebhookProviderFactsConsistent(session, options);
|
|
178
|
+
return { session, changed: false };
|
|
179
|
+
}
|
|
180
|
+
if (['succeeded', 'failed', 'cancelled', 'expired'].includes(session.state)) {
|
|
181
|
+
return {
|
|
182
|
+
session,
|
|
183
|
+
changed: false,
|
|
184
|
+
ignoredReason: `terminal payment state ${options.state} ignored after ${session.state}`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (session.expiresAt <= new Date()) {
|
|
188
|
+
this.app.throw(409, 'payment session is expired');
|
|
189
|
+
}
|
|
190
|
+
const finalizedAt = new Date();
|
|
191
|
+
await this.scope.model.paymentSession.updateById(session.id, {
|
|
192
|
+
state: options.state,
|
|
193
|
+
providerPaymentId: options.providerPaymentId,
|
|
194
|
+
providerCaptureId: options.providerCaptureId,
|
|
195
|
+
finalizedAt,
|
|
196
|
+
});
|
|
197
|
+
await this.scope.model.paymentAudit.insert({
|
|
198
|
+
paymentSessionId: session.id,
|
|
199
|
+
webhookInboxId: options.webhookInboxId,
|
|
200
|
+
fromState: session.state,
|
|
201
|
+
toState: options.state,
|
|
202
|
+
correlationId: session.correlationId,
|
|
203
|
+
source: 'webhook',
|
|
204
|
+
occurredAt: finalizedAt,
|
|
205
|
+
});
|
|
206
|
+
return {
|
|
207
|
+
session: { ...session, ...options, state: options.state, finalizedAt },
|
|
208
|
+
changed: true,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
private _assertWebhookProviderFactsConsistent(
|
|
213
|
+
session: EntityPaymentSession,
|
|
214
|
+
options: {
|
|
215
|
+
providerPaymentId?: string;
|
|
216
|
+
providerCaptureId?: string;
|
|
217
|
+
},
|
|
218
|
+
) {
|
|
219
|
+
if (
|
|
220
|
+
(session.providerPaymentId &&
|
|
221
|
+
options.providerPaymentId &&
|
|
222
|
+
session.providerPaymentId !== options.providerPaymentId) ||
|
|
223
|
+
(session.providerCaptureId &&
|
|
224
|
+
options.providerCaptureId &&
|
|
225
|
+
session.providerCaptureId !== options.providerCaptureId)
|
|
226
|
+
) {
|
|
227
|
+
this.app.throw(409, 'payment webhook provider facts conflict with the payment session');
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@Core.transaction()
|
|
232
|
+
async transition(
|
|
233
|
+
paymentSessionId: TableIdentity,
|
|
234
|
+
state: TypePaymentSessionState,
|
|
235
|
+
options?: {
|
|
236
|
+
nextAction?: TypePaymentNextAction;
|
|
237
|
+
providerPaymentId?: string;
|
|
238
|
+
providerOrderId?: string;
|
|
239
|
+
providerCaptureId?: string;
|
|
240
|
+
source?: string;
|
|
241
|
+
},
|
|
242
|
+
): Promise<EntityPaymentSession> {
|
|
243
|
+
const session = await this.scope.model.paymentSession.getByIdForUpdate(paymentSessionId);
|
|
244
|
+
if (!session) this.app.throw(404, 'payment session not found');
|
|
245
|
+
if (session.state === state) return session;
|
|
246
|
+
if (['succeeded', 'failed', 'cancelled', 'expired'].includes(session.state)) {
|
|
247
|
+
this.app.throw(409, 'payment session is already finalized');
|
|
248
|
+
}
|
|
249
|
+
const finalizedAt = ['succeeded', 'failed', 'cancelled', 'expired'].includes(state)
|
|
250
|
+
? new Date()
|
|
251
|
+
: undefined;
|
|
252
|
+
await this.scope.model.paymentSession.updateById(session.id, {
|
|
253
|
+
state,
|
|
254
|
+
nextAction: options?.nextAction,
|
|
255
|
+
providerPaymentId: options?.providerPaymentId,
|
|
256
|
+
providerOrderId: options?.providerOrderId,
|
|
257
|
+
providerCaptureId: options?.providerCaptureId,
|
|
258
|
+
finalizedAt,
|
|
259
|
+
});
|
|
260
|
+
await this.scope.model.paymentAudit.insert({
|
|
261
|
+
paymentSessionId: session.id,
|
|
262
|
+
fromState: session.state,
|
|
263
|
+
toState: state,
|
|
264
|
+
correlationId: session.correlationId,
|
|
265
|
+
source: options?.source ?? 'paymentSession',
|
|
266
|
+
occurredAt: new Date(),
|
|
267
|
+
});
|
|
268
|
+
return { ...session, ...options, state, finalizedAt };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function isTerminalPaymentSnapshot(
|
|
273
|
+
snapshot: IPayProviderPaymentSnapshot,
|
|
274
|
+
): snapshot is IPayProviderPaymentSnapshot & {
|
|
275
|
+
state: 'succeeded' | 'failed' | 'cancelled';
|
|
276
|
+
} {
|
|
277
|
+
return ['succeeded', 'failed', 'cancelled'].includes(snapshot.state);
|
|
278
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { BeanBase } from 'vona';
|
|
3
|
+
import { Service } from 'vona-module-a-bean';
|
|
4
|
+
import { Core } from 'vona-module-a-core';
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
IPayProviderVerifiedWebhook,
|
|
8
|
+
IPaymentOutcomeEvent,
|
|
9
|
+
TypePaymentSessionState,
|
|
10
|
+
} from '../types/payment.ts';
|
|
11
|
+
|
|
12
|
+
export interface IWebhookReceiveCommand {
|
|
13
|
+
providerName: string;
|
|
14
|
+
clientName: string;
|
|
15
|
+
environment: 'sandbox' | 'live';
|
|
16
|
+
rawBody?: string;
|
|
17
|
+
verified: IPayProviderVerifiedWebhook;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Service()
|
|
21
|
+
export class ServiceWebhook extends BeanBase {
|
|
22
|
+
async receive(command: IWebhookReceiveCommand) {
|
|
23
|
+
return await this.scope.redlock.lock(
|
|
24
|
+
`pay.webhook.${command.providerName}.${command.clientName}.${command.environment}.${command.verified.eventId}`,
|
|
25
|
+
async () => await this.receiveLocked(command),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Core.transaction()
|
|
30
|
+
async receiveLocked(command: IWebhookReceiveCommand) {
|
|
31
|
+
const payment = command.verified.payment;
|
|
32
|
+
const paymentSessionId = command.verified.paymentSessionId;
|
|
33
|
+
const amountMinor = command.verified.summary?.amountMinor;
|
|
34
|
+
const currency = command.verified.summary?.currency;
|
|
35
|
+
const paymentState = payment?.state as
|
|
36
|
+
| Extract<TypePaymentSessionState, 'succeeded' | 'failed' | 'cancelled'>
|
|
37
|
+
| undefined;
|
|
38
|
+
if (
|
|
39
|
+
!payment ||
|
|
40
|
+
!paymentSessionId ||
|
|
41
|
+
!['succeeded', 'failed', 'cancelled'].includes(paymentState ?? '') ||
|
|
42
|
+
typeof amountMinor !== 'number' ||
|
|
43
|
+
!Number.isInteger(amountMinor) ||
|
|
44
|
+
amountMinor < 0 ||
|
|
45
|
+
typeof currency !== 'string' ||
|
|
46
|
+
currency.length !== 3
|
|
47
|
+
) {
|
|
48
|
+
this.app.throw(400, 'payment webhook is incomplete');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const session = await this.scope.model.paymentSession.getByIdForUpdate(paymentSessionId);
|
|
52
|
+
if (!session) this.app.throw(404, 'payment session not found');
|
|
53
|
+
if (
|
|
54
|
+
session.providerName !== command.providerName ||
|
|
55
|
+
session.clientName !== command.clientName ||
|
|
56
|
+
session.environment !== command.environment ||
|
|
57
|
+
session.amountMinor !== amountMinor ||
|
|
58
|
+
session.currency !== currency
|
|
59
|
+
) {
|
|
60
|
+
this.app.throw(409, 'payment webhook conflicts with the payment session');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const payloadHash = createHash('sha256')
|
|
64
|
+
.update(command.rawBody ?? JSON.stringify(command.verified))
|
|
65
|
+
.digest('hex');
|
|
66
|
+
const existing = await this.scope.model.webhookInbox.getForUpdate({
|
|
67
|
+
providerName: command.providerName,
|
|
68
|
+
clientName: command.clientName,
|
|
69
|
+
environment: command.environment,
|
|
70
|
+
providerEventId: command.verified.eventId,
|
|
71
|
+
});
|
|
72
|
+
if (existing) {
|
|
73
|
+
if (existing.payloadHash !== payloadHash) {
|
|
74
|
+
this.app.throw(409, 'payment webhook event conflicts with a prior payload');
|
|
75
|
+
}
|
|
76
|
+
return existing;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const inbox = await this.scope.model.webhookInbox.insert({
|
|
80
|
+
providerName: command.providerName,
|
|
81
|
+
clientName: command.clientName,
|
|
82
|
+
environment: command.environment,
|
|
83
|
+
providerEventId: command.verified.eventId,
|
|
84
|
+
eventType: command.verified.eventType,
|
|
85
|
+
paymentSessionId: session.id,
|
|
86
|
+
paymentState: paymentState!,
|
|
87
|
+
amountMinor,
|
|
88
|
+
currency,
|
|
89
|
+
providerCaptureId: payment.providerCaptureId,
|
|
90
|
+
payloadHash,
|
|
91
|
+
state: 'received',
|
|
92
|
+
retryCount: 0,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const transition = await this.scope.service.paymentSession.transitionFromWebhook(session.id, {
|
|
96
|
+
state: paymentState!,
|
|
97
|
+
providerPaymentId: payment.providerPaymentId,
|
|
98
|
+
providerCaptureId: payment.providerCaptureId,
|
|
99
|
+
webhookInboxId: inbox.id,
|
|
100
|
+
});
|
|
101
|
+
if (transition.changed) {
|
|
102
|
+
const event: IPaymentOutcomeEvent = {
|
|
103
|
+
eventId: command.verified.eventId,
|
|
104
|
+
paymentSessionId: session.id,
|
|
105
|
+
businessReference: session.businessReference,
|
|
106
|
+
providerName: session.providerName,
|
|
107
|
+
state: paymentState!,
|
|
108
|
+
providerCaptureId: payment.providerCaptureId,
|
|
109
|
+
amountMinor,
|
|
110
|
+
currency,
|
|
111
|
+
};
|
|
112
|
+
await this.scope.service.outbox.enqueue(session.id, 'payment.outcome.v1', { ...event });
|
|
113
|
+
}
|
|
114
|
+
const processedAt = new Date();
|
|
115
|
+
await this.scope.model.webhookInbox.updateById(inbox.id, {
|
|
116
|
+
state: 'processed',
|
|
117
|
+
processedAt,
|
|
118
|
+
errorSummary: transition.ignoredReason,
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
...inbox,
|
|
122
|
+
state: 'processed' as const,
|
|
123
|
+
processedAt,
|
|
124
|
+
errorSummary: transition.ignoredReason,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { OmitNever } from 'vona';
|
|
2
|
+
import type { ServiceOnion, TypeOnionOptionsEnableSimple } from 'vona-module-a-onion';
|
|
3
|
+
|
|
4
|
+
import type { IPayProviderCapabilities, IPayProviderExecute } from './payment.ts';
|
|
5
|
+
|
|
6
|
+
export interface IPayProviderRecord {}
|
|
7
|
+
|
|
8
|
+
export interface IPayProviderClientRecord {
|
|
9
|
+
default: never;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface IPayProviderClientOptions {
|
|
13
|
+
environment: 'sandbox' | 'live';
|
|
14
|
+
capabilities: IPayProviderCapabilities;
|
|
15
|
+
secretCredential: unknown;
|
|
16
|
+
secretWebhook?: unknown;
|
|
17
|
+
merchantReference?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type TypePayProviderClientOptions<T> =
|
|
21
|
+
T extends IDecoratorPayProviderOptions<any, infer O> ? O : never;
|
|
22
|
+
|
|
23
|
+
export type TypePayProviderClientName<T> =
|
|
24
|
+
T extends IDecoratorPayProviderOptions<infer R, any> ? keyof R & string : never;
|
|
25
|
+
|
|
26
|
+
export type TypePayProviderClientOptionsInput<T extends IPayProviderClientOptions> = Omit<
|
|
27
|
+
T,
|
|
28
|
+
'capabilities'
|
|
29
|
+
> &
|
|
30
|
+
Partial<Pick<T, 'capabilities'>>;
|
|
31
|
+
|
|
32
|
+
export interface IDecoratorPayProviderOptions<
|
|
33
|
+
R extends IPayProviderClientRecord = IPayProviderClientRecord,
|
|
34
|
+
T extends IPayProviderClientOptions = IPayProviderClientOptions,
|
|
35
|
+
> extends TypeOnionOptionsEnableSimple {
|
|
36
|
+
base?: Partial<T>;
|
|
37
|
+
clients?: {
|
|
38
|
+
[K in keyof R]?: R[K] extends undefined ? TypePayProviderClientOptionsInput<T> : R[K];
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type TypePayProviderOptionsByName<N extends keyof IPayProviderRecord> =
|
|
43
|
+
IPayProviderRecord[N];
|
|
44
|
+
|
|
45
|
+
export type TypePayProviderClientOptionsByName<N extends keyof IPayProviderRecord> =
|
|
46
|
+
TypePayProviderOptionsByName<N> extends IDecoratorPayProviderOptions<any, any>
|
|
47
|
+
? TypePayProviderClientOptions<TypePayProviderOptionsByName<N>>
|
|
48
|
+
: never;
|
|
49
|
+
|
|
50
|
+
export type TypePayProviderClientNameByName<N extends keyof IPayProviderRecord> =
|
|
51
|
+
TypePayProviderOptionsByName<N> extends IDecoratorPayProviderOptions<any, any>
|
|
52
|
+
? TypePayProviderClientName<TypePayProviderOptionsByName<N>>
|
|
53
|
+
: never;
|
|
54
|
+
|
|
55
|
+
export type TypePayProviderExecuteByName<N extends keyof IPayProviderRecord> =
|
|
56
|
+
TypePayProviderOptionsByName<N> extends IDecoratorPayProviderOptions<any, any>
|
|
57
|
+
? IPayProviderExecute<TypePayProviderClientOptionsByName<N>>
|
|
58
|
+
: never;
|
|
59
|
+
|
|
60
|
+
declare module 'vona-module-a-onion' {
|
|
61
|
+
export interface BeanOnion {
|
|
62
|
+
payProvider: ServiceOnion<IPayProviderRecord>;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
declare module 'vona' {
|
|
67
|
+
export interface ConfigOnions {
|
|
68
|
+
payProvider: OmitNever<IPayProviderRecord>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface IBeanSceneRecord {
|
|
72
|
+
payProvider: never;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { TableIdentity } from 'table-identity';
|
|
2
|
+
import type { OmitNever, VonaContext } from 'vona';
|
|
3
|
+
import type { ServiceOnion } from 'vona-module-a-onion';
|
|
4
|
+
|
|
5
|
+
import type { IPaymentOutcomeEvent } from './payment.ts';
|
|
6
|
+
import type { IPayProviderRecord } from './payProvider.ts';
|
|
7
|
+
|
|
8
|
+
export interface IPaySceneExecute {
|
|
9
|
+
onPaymentOutcome(event: IPaymentOutcomeEvent): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface IPaySceneRecord {}
|
|
13
|
+
|
|
14
|
+
export type TypePaySceneExecuteByName<N extends keyof IPaySceneRecord> =
|
|
15
|
+
IPaySceneRecord[N] extends IDecoratorPaySceneOptions ? IPaySceneExecute : never;
|
|
16
|
+
|
|
17
|
+
export interface IPaySceneProviderCandidate {
|
|
18
|
+
key: string;
|
|
19
|
+
providerName: keyof IPayProviderRecord;
|
|
20
|
+
clientName: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface IPaySceneResolveProviderInput {
|
|
24
|
+
payScene: keyof IPaySceneRecord;
|
|
25
|
+
userId: TableIdentity;
|
|
26
|
+
businessReference: string;
|
|
27
|
+
amountMinor: number;
|
|
28
|
+
currency: string;
|
|
29
|
+
providers: readonly IPaySceneProviderCandidate[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type TypePaySceneResolveProvider = (
|
|
33
|
+
ctx: VonaContext,
|
|
34
|
+
input: IPaySceneResolveProviderInput,
|
|
35
|
+
) => string | Promise<string>;
|
|
36
|
+
|
|
37
|
+
export interface IDecoratorPaySceneOptions {
|
|
38
|
+
providers?: readonly IPaySceneProviderCandidate[];
|
|
39
|
+
resolveProvider?: TypePaySceneResolveProvider;
|
|
40
|
+
currencies?: readonly string[];
|
|
41
|
+
captureMode?: 'automatic' | 'manual';
|
|
42
|
+
sessionExpiresIn?: number;
|
|
43
|
+
refund?: {
|
|
44
|
+
enabled?: boolean;
|
|
45
|
+
allowPartial?: boolean;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
declare module 'vona-module-a-onion' {
|
|
50
|
+
export interface BeanOnion {
|
|
51
|
+
payScene: ServiceOnion<IPaySceneRecord>;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
declare module 'vona' {
|
|
56
|
+
export interface ConfigOnions {
|
|
57
|
+
payScene: OmitNever<IPaySceneRecord>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface IBeanSceneRecord {
|
|
61
|
+
payScene: never;
|
|
62
|
+
}
|
|
63
|
+
}
|