cabloy 5.1.131 → 5.1.133

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 (210) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-worktree-environment/SKILL.md +6 -6
  3. package/.claude/skills/cabloy-worktree-environment/evals/evals.json +2 -2
  4. package/.github/workflows/vona-test-pg.yml +1 -1
  5. package/.github/workflows/vona-test-sqlite3.yml +1 -1
  6. package/CHANGELOG.md +28 -0
  7. package/cabloy-docs/backend/dto-guide.md +39 -4
  8. package/cabloy-docs/backend/dto-infer-generation.md +29 -0
  9. package/cabloy-docs/backend/openapi-guide.md +16 -0
  10. package/cabloy-docs/backend/validation-guide.md +45 -0
  11. package/cabloy-docs/frontend/environment-config-guide.md +8 -15
  12. package/cabloy-docs/frontend/navigation-guards-guide.md +3 -3
  13. package/cabloy-docs/frontend/page-route-guide.md +4 -4
  14. package/cabloy-docs/frontend/ssr-env.md +22 -29
  15. package/cabloy-docs/frontend/theme-guide.md +4 -4
  16. package/cabloy-docs/frontend/zova-router-under-the-hood.md +1 -1
  17. package/cabloy-docs/fullstack/deploy-cloudflare-docker.md +6 -6
  18. package/cabloy-docs/fullstack/parallel-worktree-environment.md +2 -2
  19. package/e2e/specs/a-commerce/commerce.spec.ts +479 -17
  20. package/e2e/specs/cabloy-basic/basic.spec.ts +30 -5
  21. package/package.json +7 -7
  22. package/vona/.claude/skills/detect-ssr-leak/SKILL.md +1 -1
  23. package/vona/packages-vona/vona/package.json +1 -1
  24. package/vona/pnpm-lock.yaml +120 -10
  25. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuCreate.tsx +3 -1
  26. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuSelectResItem.tsx +13 -1
  27. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuUpdate.tsx +3 -1
  28. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuView.tsx +13 -1
  29. package/vona/src/suite/a-commerce/modules/commerce-catalog/src/entity/sku.tsx +6 -0
  30. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/skuPresentation.test.ts +227 -0
  31. package/vona/src/suite/a-commerce/modules/commerce-member/src/.metadata/index.ts +46 -36
  32. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressSelectResItem.tsx +5 -13
  33. package/vona/src/suite/a-commerce/modules/commerce-member/src/service/address.ts +16 -1
  34. package/vona/src/suite/a-commerce/modules/commerce-member/test/addressPresentation.test.ts +210 -0
  35. package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +13 -2
  36. package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +12 -0
  37. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/service/coupon.ts +7 -1
  38. package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +45 -2
  39. package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +23 -0
  40. package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +23 -0
  41. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +31 -0
  42. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineBase.tsx +56 -0
  43. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineResItem.tsx +17 -0
  44. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineView.tsx +13 -0
  45. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectResItem.tsx +26 -2
  46. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderView.tsx +197 -3
  47. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryAction.tsx +19 -0
  48. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryView.tsx +70 -0
  49. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditSelectResItem.tsx +7 -1
  50. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditView.tsx +21 -1
  51. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceSelectResItem.tsx +7 -1
  52. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceView.tsx +3 -1
  53. package/vona/src/suite/a-commerce/modules/commerce-trade/src/entity/order.tsx +12 -0
  54. package/vona/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +15 -2
  55. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +215 -3
  56. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockAudit.ts +25 -2
  57. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockBalance.ts +14 -3
  58. package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutReservation.test.ts +4 -4
  59. package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderPresentation.test.ts +358 -0
  60. package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +8 -8
  61. package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +5 -1
  62. package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +50 -1
  63. package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockPresentation.test.ts +324 -0
  64. package/vona/src/suite/a-home/modules/home-base/package.json +3 -2
  65. package/vona/src/suite/a-home/modules/home-base/src/.metadata/index.ts +93 -16
  66. package/vona/src/suite/a-home/modules/home-base/src/controller/siteCatalog.ts +21 -0
  67. package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectRes.ts +11 -0
  68. package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectResItem.ts +15 -0
  69. package/vona/src/suite/a-home/modules/home-base/src/service/siteCatalog.ts +29 -0
  70. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/bean/ssrSite.admin.ts +3 -0
  71. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/en-us.ts +1 -0
  72. package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/zh-cn.ts +1 -0
  73. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/bean/ssrSite.web.ts +3 -0
  74. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/en-us.ts +1 -0
  75. package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/zh-cn.ts +1 -0
  76. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/cli/ssrSite/boilerplate/{{sceneName}}.{{beanName}}.ts_ +1 -0
  77. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
  78. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/env.ts +1 -3
  79. package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrSite.ts +2 -1
  80. package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
  81. package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
  82. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +67 -0
  83. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payProvider.ts +1 -0
  84. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payScene.ts +5 -4
  85. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +8 -0
  86. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +22 -0
  87. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.providerOperationDispatch.ts +1 -1
  88. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentSession.tsx +6 -0
  89. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +3 -0
  90. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperationRecoveryAudit.tsx +53 -0
  91. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/refundOperation.tsx +6 -0
  92. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/providerOperationRecoveryAudit.ts +12 -0
  93. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +6 -2
  94. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +236 -30
  95. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/refundOperation.ts +8 -5
  96. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +34 -0
  97. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts +4 -0
  98. package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +6 -0
  99. package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +1 -1
  100. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/bean/payProvider.mock.ts +15 -7
  101. package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +9 -5
  102. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +1 -1
  103. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +289 -86
  104. package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/paypalGateway.ts +9 -1
  105. package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +1 -1
  106. package/vona/src/suite-vendor/a-pay/package.json +5 -5
  107. package/vona/src/suite-vendor/a-vona/modules/a-openapi/package.json +1 -1
  108. package/vona/src/suite-vendor/a-vona/modules/a-openapi/src/types/rest.ts +1 -0
  109. package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/package.json +1 -1
  110. package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/utils.ts +12 -0
  111. package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
  112. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoCreate.ts +5 -1
  113. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoUpdate.ts +5 -1
  114. package/vona/src/suite-vendor/a-vona/modules/a-validation/package.json +1 -1
  115. package/vona/src/suite-vendor/a-vona/modules/a-validation/src/bean/bean.validator.ts +60 -1
  116. package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
  117. package/vona/src/suite-vendor/a-vona/modules/a-web/src/lib/decorator/bean.ts +7 -4
  118. package/vona/src/suite-vendor/a-vona/modules/a-web/src/types/dto.ts +2 -1
  119. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  120. package/zova/env/.env +3 -5
  121. package/zova/env/.env.cabloyBasicAdmin +1 -4
  122. package/zova/env/.env.cabloyBasicWeb +1 -5
  123. package/zova/env/.env.cabloyCommerce +1 -5
  124. package/zova/env/.env.cabloyCommerceAdmin +1 -4
  125. package/zova/env/.env.ssr.admin +1 -4
  126. package/zova/env/.env.ssr.web +1 -5
  127. package/zova/package.original.json +1 -1
  128. package/zova/packages-utils/zova-jsx/package.json +2 -2
  129. package/zova/packages-zova/zova/package.json +3 -3
  130. package/zova/packages-zova/zova-core/package.json +2 -1
  131. package/zova/packages-zova/zova-core/src/core/component/locale.ts +10 -4
  132. package/zova/packages-zova/zova-core/src/core/sys/config.ts +14 -6
  133. package/zova/packages-zova/zova-core/src/types/utils/env.ts +4 -2
  134. package/zova/pnpm-lock.yaml +24 -21
  135. package/zova/src/front/config/config/config.ts +22 -7
  136. package/zova/src/suite/a-commerce/modules/commerce-catalog/src/routes.ts +2 -2
  137. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +16 -8
  138. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +150 -216
  139. package/zova/src/suite/a-commerce/modules/commerce-member/src/model/addressMine.ts +1 -2
  140. package/zova/src/suite/a-commerce/modules/commerce-member/src/page/address/controller.tsx +5 -8
  141. package/zova/src/suite/a-commerce/modules/commerce-member/src/routes.ts +1 -1
  142. package/zova/src/suite/a-commerce/modules/commerce-promotion/src/model/coupon.ts +1 -2
  143. package/zova/src/suite/a-commerce/modules/commerce-siteadmin/src/routes.ts +3 -1
  144. package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +3 -0
  145. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +72 -0
  146. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +8 -0
  147. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +226 -16
  148. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +15 -0
  149. package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionRefund/controller.tsx +155 -36
  150. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +7 -0
  151. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +7 -0
  152. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/cart.ts +3 -4
  153. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +42 -0
  154. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/orderMine.ts +2 -4
  155. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/cart/controller.tsx +5 -1
  156. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +14 -10
  157. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/order/controller.tsx +5 -8
  158. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/orders/controller.tsx +5 -8
  159. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +151 -24
  160. package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +5 -5
  161. package/zova/src/suite/a-demo/modules/demo-basic/src/routes.ts +26 -7
  162. package/zova/src/suite/a-demo/modules/demo-todo/src/routes.ts +2 -2
  163. package/zova/src/suite/a-devui/modules/devui-adapter/src/bean/meta.themeHandler.ts +1 -1
  164. package/zova/src/suite/a-home/modules/home-base/package.json +1 -0
  165. package/zova/src/suite/a-home/modules/home-base/src/routes.ts +5 -0
  166. package/zova/src/suite/a-home/modules/home-base/src/service/routerGuards.ts +1 -1
  167. package/zova/src/suite/a-home/modules/home-base/src/service/ssrLayout.ts +18 -14
  168. package/zova/src/suite/a-home/modules/home-indexadmin/src/routes.ts +1 -1
  169. package/zova/src/suite/a-home/modules/home-indexweb/src/routes.ts +1 -0
  170. package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +12 -4
  171. package/zova/src/suite/a-home/modules/home-layoutadmin/src/config/config.ts +8 -0
  172. package/zova/src/suite/a-home/modules/home-layoutadmin/src/model/layout.ts +5 -8
  173. package/zova/src/suite/a-home/modules/home-layoutempty/src/.metadata/index.ts +10 -3
  174. package/zova/src/suite/a-home/modules/home-layoutempty/src/component/layoutEmpty/controller.tsx +9 -3
  175. package/zova/src/suite/a-home/modules/home-layoutempty/src/config/config.ts +12 -0
  176. package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +13 -8
  177. package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.header.tsx +1 -1
  178. package/zova/src/suite/a-home/modules/home-layoutweb/src/config/config.ts +4 -0
  179. package/zova/src/suite/a-home/modules/home-layoutweb/src/model/layout.ts +5 -8
  180. package/zova/src/suite/a-home/modules/home-login/src/routes.ts +1 -0
  181. package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +2 -3
  182. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/routes.ts +3 -1
  183. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
  184. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +1 -1
  185. package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/routes.ts +3 -0
  186. package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
  187. package/zova/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
  188. package/zova/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +2 -2
  189. package/zova/src/suite-vendor/a-pay/package.json +2 -2
  190. package/zova/src/suite-vendor/a-zova/modules/a-interceptor/package.json +1 -1
  191. package/zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.jwt.ts +1 -1
  192. package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
  193. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +1 -1
  194. package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +1 -0
  195. package/zova/src/suite-vendor/a-zova/modules/a-ssr/package.json +1 -1
  196. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/config/config.ts +1 -17
  197. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/bodyReadyObserver.ts +27 -0
  198. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/index.ts +2 -0
  199. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssr.ts +33 -0
  200. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrMetaStore.ts +3 -35
  201. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrProfile.ts +38 -0
  202. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/monkey.ts +10 -0
  203. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/config.ts +3 -10
  204. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/ssr.ts +17 -8
  205. package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/package.json +1 -1
  206. package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/src/service/ssrHandler.ts +33 -18
  207. package/zova/src/suite-vendor/a-zova/modules/a-style/package.json +1 -1
  208. package/zova/src/suite-vendor/a-zova/modules/a-style/src/bean/bean.theme.ts +2 -2
  209. package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
  210. package/zova/src/suite-vendor/a-zova/package.json +7 -7
@@ -7,15 +7,15 @@ export * from '../entity/address.tsx';
7
7
  import type { IEntityOptionsAddress } from '../entity/address.tsx';
8
8
  import 'vona-module-a-orm';
9
9
  declare module 'vona-module-a-orm' {
10
-
10
+
11
11
  export interface IEntityRecord {
12
12
  'commerce-member:address': IEntityOptionsAddress;
13
13
  }
14
14
 
15
-
15
+
16
16
  }
17
17
  declare module 'vona-module-commerce-member' {
18
-
18
+
19
19
  }
20
20
  /** entity: end */
21
21
  /** entity: begin */
@@ -33,7 +33,7 @@ declare module 'vona-module-a-orm' {
33
33
  }
34
34
  }
35
35
  declare module 'vona-module-commerce-member' {
36
-
36
+
37
37
  export interface IEntityOptionsAddress {
38
38
  fields?: TypeEntityOptionsFields<EntityAddress, IEntityOptionsAddress[TypeSymbolKeyFieldsMore]>;
39
39
  }
@@ -44,15 +44,15 @@ export * from '../model/address.ts';
44
44
  import type { IModelOptionsAddress } from '../model/address.ts';
45
45
  import 'vona-module-a-orm';
46
46
  declare module 'vona-module-a-orm' {
47
-
47
+
48
48
  export interface IModelRecord {
49
49
  'commerce-member:address': IModelOptionsAddress;
50
50
  }
51
51
 
52
-
52
+
53
53
  }
54
54
  declare module 'vona-module-commerce-member' {
55
-
55
+
56
56
  export interface ModelAddress {
57
57
  /** @internal */
58
58
  get scope(): ScopeModuleCommerceMember;
@@ -62,7 +62,7 @@ declare module 'vona-module-commerce-member' {
62
62
  get $beanFullName(): 'commerce-member.model.address';
63
63
  get $onionName(): 'commerce-member:address';
64
64
  get $onionOptions(): IModelOptionsAddress;
65
- }
65
+ }
66
66
  }
67
67
  /** model: end */
68
68
  /** model: begin */
@@ -84,13 +84,23 @@ declare module 'vona' {
84
84
  import type { IModelGetOptions, IModelMethodOptions, IModelSelectParams, TypeModelSelectAndCount, TypeModelRelationResult, TypeModelWhere, IModelInsertOptions, TypeModelMutateRelationData, IModelDeleteOptions, IModelUpdateOptions, IModelMutateOptions, IModelSelectCountParams, IModelIncrementParams, IModelSelectAggrParams, TypeModelAggrRelationResult, IModelSelectGroupParams, TypeModelGroupRelationResult } from 'vona-module-a-orm';
85
85
  import { SymbolKeyEntity, SymbolKeyEntityMeta, SymbolKeyModelOptions } from 'vona-module-a-orm';
86
86
  declare module 'vona-module-commerce-member' {
87
-
87
+
88
88
  export interface ModelAddress {
89
89
  [SymbolKeyEntity]: EntityAddress;
90
90
  [SymbolKeyEntityMeta]: EntityAddressMeta;
91
91
  [SymbolKeyModelOptions]: IModelOptionsAddress;
92
92
  get<T extends IModelGetOptions<EntityAddress,ModelAddress>>(where: TypeModelWhere<EntityAddress>, options?: T): Promise<TypeModelRelationResult<EntityAddress, ModelAddress, T> | undefined>;
93
+ /**
94
+ * Retrieves one matching primary row with a pessimistic FOR UPDATE lock.
95
+ * Requires an active transaction. The lock is released when that transaction completes.
96
+ * Entity and query caches are bypassed.
97
+ */
93
98
  getForUpdate<T extends IModelGetOptions<EntityAddress,ModelAddress>>(where: TypeModelWhere<EntityAddress>, options?: T): Promise<TypeModelRelationResult<EntityAddress, ModelAddress, T> | undefined>;
99
+ /**
100
+ * Retrieves a primary row by ID with the same pessimistic FOR UPDATE lock semantics.
101
+ * Requires an active transaction. The lock is released when that transaction completes.
102
+ * Entity and query caches are bypassed.
103
+ */
94
104
  getByIdForUpdate<T extends IModelGetOptions<EntityAddress,ModelAddress>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityAddress, ModelAddress, T> | undefined>;
95
105
  mget<T extends IModelGetOptions<EntityAddress,ModelAddress>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityAddress, ModelAddress, T>[]>;
96
106
  selectAndCount<T extends IModelSelectParams<EntityAddress,ModelAddress,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityAddress, ModelAddress, T>>;
@@ -124,15 +134,15 @@ export * from '../service/address.ts';
124
134
 
125
135
  import 'vona-module-a-bean';
126
136
  declare module 'vona-module-a-bean' {
127
-
137
+
128
138
  export interface IServiceRecord {
129
139
  'commerce-member:address': never;
130
140
  }
131
141
 
132
-
142
+
133
143
  }
134
144
  declare module 'vona-module-commerce-member' {
135
-
145
+
136
146
  export interface ServiceAddress {
137
147
  /** @internal */
138
148
  get scope(): ScopeModuleCommerceMember;
@@ -141,8 +151,8 @@ declare module 'vona-module-commerce-member' {
141
151
  export interface ServiceAddress {
142
152
  get $beanFullName(): 'commerce-member.service.address';
143
153
  get $onionName(): 'commerce-member:address';
144
-
145
- }
154
+
155
+ }
146
156
  }
147
157
  /** service: end */
148
158
  /** service: begin */
@@ -166,16 +176,16 @@ export * from '../bean/meta.version.ts';
166
176
  import type { IMetaOptionsIndex } from 'vona-module-a-index';
167
177
  import 'vona-module-a-meta';
168
178
  declare module 'vona-module-a-meta' {
169
-
179
+
170
180
  export interface IMetaRecord {
171
181
  'commerce-member:index': IMetaOptionsIndex;
172
182
  'commerce-member:version': never;
173
183
  }
174
184
 
175
-
185
+
176
186
  }
177
187
  declare module 'vona-module-commerce-member' {
178
-
188
+
179
189
  export interface MetaIndex {
180
190
  /** @internal */
181
191
  get scope(): ScopeModuleCommerceMember;
@@ -195,8 +205,8 @@ declare module 'vona-module-commerce-member' {
195
205
  export interface MetaVersion {
196
206
  get $beanFullName(): 'commerce-member.meta.version';
197
207
  get $onionName(): 'commerce-member:version';
198
-
199
- }
208
+
209
+ }
200
210
  }
201
211
  /** meta: end */
202
212
  /** dto: begin */
@@ -222,7 +232,7 @@ import type { IDtoOptionsAddressSelectResItem } from '../dto/addressSelectResIte
222
232
  import type { IDtoOptionsAddressView } from '../dto/addressView.tsx';
223
233
  import 'vona-module-a-web';
224
234
  declare module 'vona-module-a-web' {
225
-
235
+
226
236
  export interface IDtoRecord {
227
237
  'commerce-member:addressMineCreate': IDtoOptionsAddressMineCreate;
228
238
  'commerce-member:addressMineItem': IDtoOptionsAddressMineItem;
@@ -236,10 +246,10 @@ declare module 'vona-module-a-web' {
236
246
  'commerce-member:addressView': IDtoOptionsAddressView;
237
247
  }
238
248
 
239
-
249
+
240
250
  }
241
251
  declare module 'vona-module-commerce-member' {
242
-
252
+
243
253
  }
244
254
  /** dto: end */
245
255
  /** dto: begin */
@@ -254,7 +264,7 @@ import type { DtoAddressSelectRes } from '../dto/addressSelectRes.tsx';
254
264
  import type { DtoAddressSelectResItem } from '../dto/addressSelectResItem.tsx';
255
265
  import type { DtoAddressView } from '../dto/addressView.tsx';
256
266
  declare module 'vona-module-commerce-member' {
257
-
267
+
258
268
  export interface IDtoOptionsAddressMineCreate {
259
269
  fields?: TypeEntityOptionsFields<DtoAddressMineCreate, IDtoOptionsAddressMineCreate[TypeSymbolKeyFieldsMore]>;
260
270
  }
@@ -301,15 +311,15 @@ export * from '../controller/address.ts';
301
311
  import type { IControllerOptionsAddress } from '../controller/address.ts';
302
312
  import 'vona-module-a-web';
303
313
  declare module 'vona-module-a-web' {
304
-
314
+
305
315
  export interface IControllerRecord {
306
316
  'commerce-member:address': IControllerOptionsAddress;
307
317
  }
308
318
 
309
-
319
+
310
320
  }
311
321
  declare module 'vona-module-commerce-member' {
312
-
322
+
313
323
  export interface ControllerAddress {
314
324
  /** @internal */
315
325
  get scope(): ScopeModuleCommerceMember;
@@ -319,14 +329,14 @@ declare module 'vona-module-commerce-member' {
319
329
  get $beanFullName(): 'commerce-member.controller.address';
320
330
  get $onionName(): 'commerce-member:address';
321
331
  get $onionOptions(): IControllerOptionsAddress;
322
- }
332
+ }
323
333
  }
324
334
  /** controller: end */
325
335
  /** controller: begin */
326
336
  // @ts-ignore ignore
327
337
  import type { ControllerAddress } from '../controller/address.ts';
328
338
  declare module 'vona-module-commerce-member' {
329
-
339
+
330
340
  export interface IControllerOptionsAddress {
331
341
  actions?: TypeControllerOptionsActions<ControllerAddress>;
332
342
  }
@@ -355,22 +365,22 @@ import 'vona-module-a-openapi';
355
365
  'commerce-member:address': never;
356
366
  }
357
367
  }
358
-
368
+
359
369
  /** controller: end */
360
370
  /** ssrMenu: begin */
361
371
  export * from '../bean/ssrMenu.address.ts';
362
372
  import type { ISsrMenuOptionsAddress } from '../bean/ssrMenu.address.ts';
363
373
  import 'vona-module-a-ssr';
364
374
  declare module 'vona-module-a-ssr' {
365
-
375
+
366
376
  export interface ISsrMenuRecord {
367
377
  'commerce-member:address': ISsrMenuOptionsAddress;
368
378
  }
369
379
 
370
-
380
+
371
381
  }
372
382
  declare module 'vona-module-commerce-member' {
373
-
383
+
374
384
  export interface SsrMenuAddress {
375
385
  /** @internal */
376
386
  get scope(): ScopeModuleCommerceMember;
@@ -380,7 +390,7 @@ declare module 'vona-module-commerce-member' {
380
390
  get $beanFullName(): 'commerce-member.ssrMenu.address';
381
391
  get $onionName(): 'commerce-member:address';
382
392
  get $onionOptions(): ISsrMenuOptionsAddress;
383
- }
393
+ }
384
394
  }
385
395
  /** ssrMenu: end */
386
396
  /** locale: begin */
@@ -410,13 +420,13 @@ declare module 'vona' {
410
420
  export interface IBeanScopeContainer {
411
421
  commerceMember: ScopeModuleCommerceMember;
412
422
  }
413
-
414
-
423
+
424
+
415
425
 
416
426
  export interface IBeanScopeLocale {
417
427
  'commerce-member': (typeof locales)[TypeLocaleBase];
418
428
  }
419
429
 
420
-
430
+
421
431
  }
422
432
  /** scope: end */
@@ -6,6 +6,7 @@ import { Dto } from 'vona-module-a-web';
6
6
  import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
7
7
 
8
8
  import { $locale } from '../.metadata/locales.ts';
9
+ import { EntityAddress } from '../entity/address.tsx';
9
10
  import { ModelAddress } from '../model/address.ts';
10
11
 
11
12
  export interface IDtoOptionsAddressSelectResItem extends IDecoratorDtoOptions {}
@@ -45,20 +46,11 @@ export interface IDtoOptionsAddressSelectResItem extends IDecoratorDtoOptions {}
45
46
  ],
46
47
  })
47
48
  export class DtoAddressSelectResItem extends $Dto.get(() => ModelAddress, {
48
- columns: [
49
- 'id',
50
- 'recipientName',
51
- 'phone',
52
- 'countryCode',
53
- 'region',
54
- 'city',
55
- 'postalCode',
56
- 'addressLine1',
57
- 'addressLine2',
58
- 'createdAt',
59
- 'updatedAt',
60
- ],
49
+ columns: ['id', 'recipientName', 'phone', 'countryCode', 'city', 'createdAt'],
61
50
  }) {
51
+ @Api.field(ZovaRender.order(1, 'core'), ZovaRender.cell('basic-table:actionView'))
52
+ declare id: EntityAddress['id'];
53
+
62
54
  @Api.field(
63
55
  v.title($locale('Operations')),
64
56
  ZovaRender.order(1, 'max'),
@@ -19,12 +19,27 @@ export class ServiceAddress extends BeanBase {
19
19
  async select(params?: IQueryParams<ModelAddress>): Promise<DtoAddressSelectRes> {
20
20
  return await this.scope.model.address.selectAndCount({
21
21
  ...params,
22
+ columns: ['id', 'recipientName', 'phone', 'countryCode', 'city', 'createdAt'],
22
23
  orders: params?.orders ?? [['id', 'asc']],
23
24
  });
24
25
  }
25
26
 
26
27
  async view(id: TableIdentity): Promise<DtoAddressView | undefined> {
27
- return await this.scope.model.address.getById(id);
28
+ return await this.scope.model.address.getById(id, {
29
+ columns: [
30
+ 'id',
31
+ 'recipientName',
32
+ 'phone',
33
+ 'countryCode',
34
+ 'region',
35
+ 'city',
36
+ 'postalCode',
37
+ 'addressLine1',
38
+ 'addressLine2',
39
+ 'createdAt',
40
+ 'updatedAt',
41
+ ],
42
+ });
28
43
  }
29
44
 
30
45
  async mine(params?: IQueryParams<ModelAddress>): Promise<DtoAddressMineRes> {
@@ -0,0 +1,210 @@
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
+ import {
6
+ DtoAddressMineCreate,
7
+ DtoAddressSelectReq,
8
+ DtoAddressSelectResItem,
9
+ DtoAddressView,
10
+ } from 'vona-module-commerce-member';
11
+
12
+ const actionPath = '/commerce/member/address';
13
+ const createMinePath = `${actionPath}/createMine`;
14
+
15
+ function findComponent(apiJson: any, predicate: (properties: any) => boolean) {
16
+ return Object.values(apiJson.components!.schemas as any).find(item => {
17
+ return predicate((item as any).properties);
18
+ }) as any;
19
+ }
20
+
21
+ function getListFilter(component: any) {
22
+ const page = component?.rest?.blocks?.[0];
23
+ const [filter, table, pager] = page?.options?.blocks ?? [];
24
+ assert.equal(page?.render, 'basic-page:blockPage');
25
+ assert.equal(filter?.render, 'basic-page:blockFilter');
26
+ assert.equal(table?.render, 'basic-page:blockTable');
27
+ assert.equal(pager?.render, 'basic-page:blockPager');
28
+ return filter;
29
+ }
30
+
31
+ function getEntryToolbar(component: any) {
32
+ const pageEntry = component?.rest?.blocks?.[0];
33
+ const formBlock = pageEntry?.options?.blocks?.[0];
34
+ const toolbarBlock = pageEntry?.options?.blocks?.[1];
35
+ assert.equal(pageEntry?.render, 'basic-pageentry:blockPageEntry');
36
+ assert.equal(formBlock?.render, 'basic-pageentry:blockForm');
37
+ assert.equal(toolbarBlock?.render, 'basic-pageentry:blockToolbarRow');
38
+ return toolbarBlock;
39
+ }
40
+
41
+ function createAddress(suffix: string): DtoAddressMineCreate {
42
+ return {
43
+ recipientName: `Presentation Recipient ${suffix}`,
44
+ phone: '15555550123',
45
+ countryCode: 'US',
46
+ region: 'California',
47
+ city: 'San Francisco',
48
+ postalCode: '94105',
49
+ addressLine1: `1 Market Street ${suffix}`,
50
+ addressLine2: 'Suite 100',
51
+ };
52
+ }
53
+
54
+ async function performAs(accessToken: string, method: string, path: string, options = {}) {
55
+ return await app.bean.executor.newCtxIsolate(async () => {
56
+ return await app.bean.executor.performAction(method, path, {
57
+ ...options,
58
+ authToken: accessToken,
59
+ innerAccess: false,
60
+ });
61
+ });
62
+ }
63
+
64
+ describe('addressPresentation.test.ts', () => {
65
+ it('action:address:presentationMetadata', async () => {
66
+ await app.bean.executor.mockCtx(async () => {
67
+ const listJson = await app.bean.openapi.generateJsonOfClass(DtoAddressSelectResItem);
68
+ const list = findComponent(
69
+ listJson,
70
+ properties =>
71
+ properties?._operationsRow && properties?.recipientName && properties?.countryCode,
72
+ );
73
+ assert.deepEqual(Object.keys(list.properties).sort(), [
74
+ '_operationsRow',
75
+ 'city',
76
+ 'countryCode',
77
+ 'createdAt',
78
+ 'id',
79
+ 'phone',
80
+ 'recipientName',
81
+ ]);
82
+ assert.equal(list.properties.id.rest.table.render, 'basic-table:actionView');
83
+ assert.equal(list.properties.createdAt.rest.table.render, 'basic-date:date');
84
+ assert.deepEqual(
85
+ list.properties._operationsRow.rest.table.columnProps.actions.map(
86
+ (action: any) => action.render,
87
+ ),
88
+ ['basic-table:actionView'],
89
+ );
90
+
91
+ const filter = getListFilter(list);
92
+ const section = filter.options.blocks[0].options.formLayout.children[0];
93
+ assert.equal(section.type, 'section');
94
+ assert.equal(section.layout, 'flow');
95
+ assert.deepEqual(
96
+ section.children.slice(0, 3).map((field: any) => field.name),
97
+ ['recipientName', 'phone', 'createdAt'],
98
+ );
99
+ assert.equal(section.children[3].block.render, 'basic-page:blockFilterActions');
100
+
101
+ const filterJson = await app.bean.openapi.generateJsonOfClass(DtoAddressSelectReq);
102
+ const filterComponent = findComponent(filterJson, properties => {
103
+ return properties?.recipientName && properties?.phone && properties?.createdAt;
104
+ });
105
+ assert.equal(
106
+ filterComponent.properties.createdAt.rest.form.render,
107
+ 'basic-date:formFieldDateRange',
108
+ );
109
+
110
+ const viewJson = await app.bean.openapi.generateJsonOfClass(DtoAddressView);
111
+ const view = findComponent(
112
+ viewJson,
113
+ properties =>
114
+ properties?.recipientName && properties?.addressLine1 && properties?.updatedAt,
115
+ );
116
+ assert.deepEqual(Object.keys(view.properties).sort(), [
117
+ 'addressLine1',
118
+ 'addressLine2',
119
+ 'city',
120
+ 'countryCode',
121
+ 'createdAt',
122
+ 'id',
123
+ 'phone',
124
+ 'postalCode',
125
+ 'recipientName',
126
+ 'region',
127
+ 'updatedAt',
128
+ ]);
129
+ assert.equal(view.properties.createdAt.rest.form.render, 'basic-date:formFieldDate');
130
+ assert.equal(view.properties.updatedAt.rest.form.render, 'basic-date:formFieldDate');
131
+ assert.deepEqual(
132
+ getEntryToolbar(view).options.actions.map((action: any) => action.render),
133
+ ['basic-form:actionBack'],
134
+ );
135
+
136
+ for (const component of [list, view]) {
137
+ for (const field of ['userId', 'iid', 'deleted']) {
138
+ assert.equal(component.properties[field], undefined);
139
+ }
140
+ }
141
+ });
142
+ });
143
+
144
+ it('action:address:runtimeBoundary', async () => {
145
+ await app.bean.executor.mockCtx(async () => {
146
+ let addressId: number | undefined;
147
+ const suffix = randomUUID().slice(0, 12);
148
+ const address = createAddress(suffix);
149
+ try {
150
+ await app.bean.user.register({ name: `presentation-address-${suffix}` }, true);
151
+ const customer = await app.bean.passport.signinMock(
152
+ `presentation-address-${suffix}` as any,
153
+ );
154
+ addressId = await performAs(customer.accessToken, 'post', createMinePath, {
155
+ body: address,
156
+ });
157
+
158
+ const admin = await app.bean.passport.signinMock();
159
+ const list: any = await performAs(admin.accessToken, 'get', actionPath, {
160
+ query: { recipientName: address.recipientName },
161
+ });
162
+ const item = list.list.find((entry: any) => String(entry.id) === String(addressId));
163
+ assert.deepEqual(Object.keys(item).sort(), [
164
+ 'city',
165
+ 'countryCode',
166
+ 'createdAt',
167
+ 'id',
168
+ 'phone',
169
+ 'recipientName',
170
+ ]);
171
+ assert.equal(item.recipientName, address.recipientName);
172
+ assert.equal(item.phone, address.phone);
173
+ assert.equal(item.countryCode, address.countryCode);
174
+ assert.equal(item.city, address.city);
175
+
176
+ const view: any = await performAs(admin.accessToken, 'get', `${actionPath}/:id`, {
177
+ params: { id: addressId },
178
+ });
179
+ assert.deepEqual(Object.keys(view).sort(), [
180
+ 'addressLine1',
181
+ 'addressLine2',
182
+ 'city',
183
+ 'countryCode',
184
+ 'createdAt',
185
+ 'id',
186
+ 'phone',
187
+ 'postalCode',
188
+ 'recipientName',
189
+ 'region',
190
+ 'updatedAt',
191
+ ]);
192
+ assert.equal(view.addressLine1, address.addressLine1);
193
+ assert.equal(view.addressLine2, address.addressLine2);
194
+ assert.equal(view.region, address.region);
195
+
196
+ const permissions = await Promise.all(
197
+ ['create', 'update', 'delete'].map(action =>
198
+ app.bean.permission.retrievePermissionAction('commerce-member:address', action),
199
+ ),
200
+ );
201
+ assert.deepEqual(permissions, [false, false, false]);
202
+ } finally {
203
+ if (addressId !== undefined) {
204
+ await app.scope('commerce-member').model.address.deleteById(addressId);
205
+ }
206
+ await app.bean.passport.signout();
207
+ }
208
+ });
209
+ });
210
+ });
@@ -52,8 +52,9 @@ export class ServiceCommercePayScene extends BeanBase {
52
52
  return { ...refundAttempt, refundOperationId };
53
53
  }
54
54
 
55
+ @Core.transaction({ isolationLevel: 'SERIALIZABLE' })
55
56
  async createRefundOperation(refundAttemptId: TableIdentity) {
56
- const refundAttempt = await this.scope.model.refundAttempt.getById(refundAttemptId);
57
+ const refundAttempt = await this.scope.model.refundAttempt.getByIdForUpdate(refundAttemptId);
57
58
  if (!refundAttempt) this.app.throw(404, 'commerce refund attempt not found');
58
59
  const paymentAttempt = await this.scope.model.paymentAttempt.get({
59
60
  orderId: refundAttempt.orderId,
@@ -68,7 +69,17 @@ export class ServiceCommercePayScene extends BeanBase {
68
69
  idempotencyKey: `${refundAttempt.correlationId}:refund`,
69
70
  correlationId: refundAttempt.correlationId,
70
71
  });
71
- await this.linkRefundOperation(refundAttempt.id, refund.id);
72
+ if (
73
+ refundAttempt.refundOperationId &&
74
+ String(refundAttempt.refundOperationId) !== String(refund.id)
75
+ ) {
76
+ this.app.throw(409, 'commerce refund attempt is linked to another refund operation');
77
+ }
78
+ if (!refundAttempt.refundOperationId) {
79
+ await this.scope.model.refundAttempt.updateById(refundAttempt.id, {
80
+ refundOperationId: refund.id,
81
+ });
82
+ }
72
83
  return refund;
73
84
  }
74
85
 
@@ -46,6 +46,18 @@ describe('paymentAttempt.test.ts', { concurrency: false }, () => {
46
46
  assert.equal(session?.providerName, 'pay-mock:mock');
47
47
  assert.equal(session?.clientName, 'default');
48
48
  assert.equal(session?.environment, 'sandbox');
49
+ assert.match(
50
+ session?.providerInvoiceReference ?? '',
51
+ /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
52
+ );
53
+ assert.match(
54
+ session?.providerCorrelationReference ?? '',
55
+ /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
56
+ );
57
+ assert.notEqual(session?.providerInvoiceReference, session?.providerCorrelationReference);
58
+ const reloaded = await app.scope('a-pay').model.paymentSession.getById(paymentSessionId);
59
+ assert.equal(reloaded?.providerInvoiceReference, session?.providerInvoiceReference);
60
+ assert.equal(reloaded?.providerCorrelationReference, session?.providerCorrelationReference);
49
61
  assert.ok((session?.expiresAt.getTime() ?? 0) > Date.now() + 29 * 60 * 1000);
50
62
  const cancelled = await scope.service.paymentAttempt.cancel(created.orderId);
51
63
  assert.equal(cancelled?.state, 'cancelled');
@@ -42,7 +42,13 @@ const serializationRetryOptions = {
42
42
  minTimeout: 0,
43
43
  maxTimeout: 0,
44
44
  randomize: false,
45
- errorCodes: ['40001', 'ER_LOCK_DEADLOCK', 'ER_LOCK_WAIT_TIMEOUT'],
45
+ errorCodes: [
46
+ '40001',
47
+ 'ER_LOCK_DEADLOCK',
48
+ 'ER_LOCK_WAIT_TIMEOUT',
49
+ 'SQLITE_BUSY',
50
+ 'SQLITE_BUSY_SNAPSHOT',
51
+ ],
46
52
  ownerOnly: true,
47
53
  };
48
54