cabloy 5.1.115 → 5.1.117

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 (207) hide show
  1. package/.cabloy-version +1 -1
  2. package/.claude/skills/cabloy-contract-loop/SKILL.md +8 -2
  3. package/.claude/skills/cabloy-contract-loop/evals/evals.json +6 -0
  4. package/.claude/skills/cabloy-contract-loop/references/contract-loop-map.md +13 -0
  5. package/.claude/skills/cabloy-contract-loop/references/resource-custom-state-pattern.md +16 -3
  6. package/.claude/skills/cabloy-contract-loop/references/verification-checklist.md +12 -0
  7. package/.github/workflows/vona-test-mysql.yml +6 -10
  8. package/.github/workflows/vona-test-pg.yml +9 -10
  9. package/.github/workflows/vona-test-sqlite3.yml +3 -0
  10. package/CHANGELOG.md +35 -0
  11. package/CLAUDE.md +2 -0
  12. package/cabloy-docs/.vitepress/config.mjs +6 -0
  13. package/cabloy-docs/ai/docs-skills-rules-mapping.md +7 -0
  14. package/cabloy-docs/backend/aop-overview.md +16 -24
  15. package/cabloy-docs/backend/backend-source-reading-roadmap.md +26 -2
  16. package/cabloy-docs/backend/controller-aop-guide.md +38 -14
  17. package/cabloy-docs/backend/logger-guide.md +1 -0
  18. package/cabloy-docs/backend/menu-guide.md +1 -1
  19. package/cabloy-docs/backend/orm-mutation-guide.md +36 -10
  20. package/cabloy-docs/backend/orm-select-guide.md +15 -10
  21. package/cabloy-docs/backend/rate-limit-guide.md +97 -0
  22. package/cabloy-docs/backend/telemetry-guide.md +93 -0
  23. package/cabloy-docs/backend/vona-source-reading-map.md +44 -1
  24. package/cabloy-docs/frontend/model-resource-owner-pattern.md +2 -0
  25. package/cabloy-docs/frontend/ssr-overview.md +2 -0
  26. package/cabloy-docs/fullstack/admin-resource-and-web-self-service.md +329 -0
  27. package/cabloy-docs/fullstack/contract-loop-playbook.md +1 -1
  28. package/cabloy-docs/fullstack/introduction.md +1 -0
  29. package/e2e/specs/a-commerce/commerce.spec.ts +479 -1
  30. package/package.json +1 -1
  31. package/vona/packages-cli/cli/package.json +1 -1
  32. package/vona/packages-cli/cli-set-api/cli/templates/tools/masterDetail/boilerplate/dto/<%=argv.detailDtoBaseName%>.tsx_ +1 -1
  33. package/vona/packages-cli/cli-set-api/cli/templates/tools/masterDetail/boilerplate/dto/<%=argv.detailDtoMutateName%>.tsx_ +2 -2
  34. package/vona/packages-cli/cli-set-api/cli/templates/tools/masterDetail/boilerplate/dto/<%=argv.detailDtoResItemName%>.tsx_ +10 -10
  35. package/vona/packages-cli/cli-set-api/cli/templates/tools/masterDetail/boilerplate/dto/<%=argv.detailDtoViewName%>.tsx_ +2 -2
  36. package/vona/packages-cli/cli-set-api/package.json +1 -1
  37. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.tools.masterDetail.ts +13 -4
  38. package/vona/packages-vona/vona/package.json +1 -1
  39. package/vona/packages-vona/vona-core/package.json +1 -1
  40. package/vona/packages-vona/vona-core/src/lib/core/logger/utils.ts +12 -3
  41. package/vona/packages-vona/vona-mock/package.json +1 -1
  42. package/vona/pnpm-lock.yaml +237 -164
  43. package/vona/src/backend/config/config/config.ts +1 -0
  44. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/sku.test.ts +1 -1
  45. package/vona/src/suite/a-commerce/modules/commerce-member/src/.metadata/index.ts +81 -25
  46. package/vona/src/suite/a-commerce/modules/commerce-member/src/bean/ssrMenu.address.ts +30 -0
  47. package/vona/src/suite/a-commerce/modules/commerce-member/src/controller/address.ts +42 -20
  48. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineCreate.tsx +35 -0
  49. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineItem.tsx +39 -0
  50. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineReq.tsx +11 -0
  51. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineRes.tsx +11 -0
  52. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineUpdate.tsx +10 -0
  53. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressMineView.tsx +10 -0
  54. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressSelectResItem.tsx +1 -7
  55. package/vona/src/suite/a-commerce/modules/commerce-member/src/service/address.ts +43 -42
  56. package/vona/src/suite/a-commerce/modules/commerce-member/test/addressOwnership.test.ts +168 -127
  57. package/vona/src/suite/a-commerce/modules/commerce-payment/src/.metadata/index.ts +76 -3
  58. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.index.ts +3 -0
  59. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.version.ts +37 -0
  60. package/vona/src/suite/a-commerce/modules/commerce-payment/src/dto/paymentAttemptView.tsx +2 -2
  61. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/paymentAttempt.tsx +5 -2
  62. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/paymentAudit.tsx +54 -0
  63. package/vona/src/suite/a-commerce/modules/commerce-payment/src/model/paymentAudit.ts +10 -0
  64. package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/mockPaymentAdapter.ts +18 -0
  65. package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/paymentAttempt.ts +22 -7
  66. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/dto/couponIssue.tsx +1 -1
  67. package/vona/src/suite/a-commerce/modules/commerce-promotion/src/service/coupon.ts +6 -1
  68. package/vona/src/suite/a-commerce/modules/commerce-promotion/test/couponReservation.test.ts +480 -8
  69. package/vona/src/suite/a-commerce/modules/commerce-siteadmin/test/ssrMenu.test.ts +14 -0
  70. package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +309 -3
  71. package/vona/src/suite/a-commerce/modules/commerce-trade/src/bean/meta.index.ts +2 -0
  72. package/vona/src/suite/a-commerce/modules/commerce-trade/src/bean/meta.version.ts +16 -0
  73. package/vona/src/suite/a-commerce/modules/commerce-trade/src/bean/ssrMenu.order.ts +30 -0
  74. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +69 -0
  75. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/payment.ts +23 -0
  76. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/checkoutResult.tsx +4 -4
  77. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderDetail.tsx +72 -0
  78. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderMineReq.tsx +21 -0
  79. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderMineRes.tsx +11 -0
  80. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectReq.tsx +25 -0
  81. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectRes.tsx +11 -0
  82. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectResItem.tsx +38 -0
  83. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderShip.tsx +15 -0
  84. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSummary.tsx +26 -0
  85. package/vona/src/suite/a-commerce/modules/{commerce-member/src/dto/addressCreate.tsx → commerce-trade/src/dto/orderView.tsx} +5 -17
  86. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/paymentOutcomeCreate.tsx +16 -0
  87. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/paymentOutcomeResult.tsx +29 -0
  88. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/shipmentView.tsx +22 -0
  89. package/vona/src/suite/a-commerce/modules/commerce-trade/src/entity/orderAudit.tsx +13 -7
  90. package/vona/src/suite/a-commerce/modules/commerce-trade/src/entity/shipment.tsx +28 -0
  91. package/vona/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +1 -0
  92. package/vona/src/suite/a-commerce/modules/commerce-trade/src/model/shipment.ts +10 -0
  93. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/cart.ts +14 -0
  94. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +436 -34
  95. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockBalance.ts +4 -3
  96. package/vona/src/suite/a-commerce/modules/commerce-trade/test/cartOwnership.test.ts +160 -80
  97. package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutReservation.test.ts +773 -2
  98. package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutTransaction.test.ts +212 -0
  99. package/vona/src/suite/a-commerce/modules/commerce-trade/test/order.test.ts +37 -0
  100. package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +29 -5
  101. package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +714 -0
  102. package/vona/src/suite/a-commerce/modules/commerce-trade/test/reservationExpiry.test.ts +282 -9
  103. package/vona/src/suite/a-commerce/modules/commerce-trade/test/shipment.test.ts +260 -0
  104. package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockBalance.test.ts +15 -1
  105. package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockReservation.test.ts +20 -2
  106. package/vona/src/suite/a-commerce/modules/commerce-trade/test/testLock.ts +11 -0
  107. package/vona/src/suite/a-home/modules/home-user/src/.metadata/index.ts +21 -0
  108. package/vona/src/suite/a-home/modules/home-user/src/controller/passportTest.ts +21 -0
  109. package/vona/src/suite/a-home/modules/home-user/test/passportTest.test.ts +77 -0
  110. package/vona/src/suite-vendor/a-vona/modules/a-broadcast/package.json +2 -1
  111. package/vona/src/suite-vendor/a-vona/modules/a-broadcast/src/service/broadcast.ts +84 -23
  112. package/vona/src/suite-vendor/a-vona/modules/a-broadcast/src/types/broadcast.ts +7 -1
  113. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  114. package/vona/src/suite-vendor/a-vona/modules/a-core/src/lib/core.ts +8 -0
  115. package/vona/src/suite-vendor/a-vona/modules/a-executor/package.json +4 -2
  116. package/vona/src/suite-vendor/a-vona/modules/a-executor/src/service/executor.ts +68 -53
  117. package/vona/src/suite-vendor/a-vona/modules/a-orm/cli/model/metadata/generate.ts +10 -0
  118. package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
  119. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/bean.model/bean.model_cache.ts +12 -0
  120. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/bean.model/bean.model_crud_inner.ts +3 -0
  121. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/bean.model/bean.model_utils.ts +1 -1
  122. package/vona/src/suite-vendor/a-vona/modules/a-queue/package.json +4 -2
  123. package/vona/src/suite-vendor/a-vona/modules/a-queue/src/service/queue.ts +103 -54
  124. package/vona/src/suite-vendor/a-vona/modules/a-queue/src/types/queue.ts +5 -0
  125. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/package.json +48 -0
  126. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/.metadata/index.ts +100 -0
  127. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/.metadata/this.ts +2 -0
  128. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/bean/interceptor.rateLimit.ts +72 -0
  129. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/index.ts +2 -0
  130. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/main.ts +28 -0
  131. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/service/rateLimit.ts +75 -0
  132. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/types/index.ts +1 -0
  133. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/src/types/rateLimit.ts +19 -0
  134. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/tsconfig.build.json +11 -0
  135. package/vona/src/suite-vendor/a-vona/modules/a-ratelimit/tsconfig.json +7 -0
  136. package/vona/src/suite-vendor/a-vona/modules/a-redis/package.json +1 -1
  137. package/vona/src/suite-vendor/a-vona/modules/a-redis/src/service/redis.ts +1 -2
  138. package/vona/src/suite-vendor/a-vona/modules/a-redis/src/types/redis.ts +1 -0
  139. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/package.json +63 -0
  140. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/.metadata/index.ts +132 -0
  141. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/.metadata/this.ts +2 -0
  142. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/bean/bean.telemetry.ts +71 -0
  143. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/bean/middlewareSystem.trace.ts +73 -0
  144. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/config/config.ts +83 -0
  145. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/index.ts +2 -0
  146. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/lib/ingress.ts +34 -0
  147. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/monkey.ts +22 -0
  148. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/service/telemetry.ts +201 -0
  149. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/types/index.ts +1 -0
  150. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/src/types/telemetry.ts +22 -0
  151. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/test/telemetry.test.ts +339 -0
  152. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/tsconfig.build.json +11 -0
  153. package/vona/src/suite-vendor/a-vona/modules/a-telemetry/tsconfig.json +7 -0
  154. package/vona/src/suite-vendor/a-vona/package.json +3 -1
  155. package/vona/src/suite-vendor/a-vona/tsconfig.json +3 -0
  156. package/zova/package.original.json +1 -1
  157. package/zova/packages-cli/cli/package.json +2 -2
  158. package/zova/packages-cli/cli-set-front/package.json +1 -1
  159. package/zova/packages-cli/cli-set-front/src/lib/bean/cli.bin.buildRest.ts +3 -2
  160. package/zova/packages-zova/zova/package.json +2 -2
  161. package/zova/pnpm-lock.yaml +87 -127
  162. package/zova/src/front/config/config/config.cabloyCommerce.ts +4 -0
  163. package/zova/src/suite/a-commerce/modules/commerce-member/cli/openapi.config.ts +9 -1
  164. package/zova/src/suite/a-commerce/modules/commerce-member/src/.metadata/index.ts +16 -0
  165. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/commerceMemberAddress.ts +94 -50
  166. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +162 -52
  167. package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +2656 -1298
  168. package/zova/src/suite/a-commerce/modules/commerce-member/src/apiSchema/commerceMemberAddress.ts +23 -13
  169. package/zova/src/suite/a-commerce/modules/commerce-member/src/model/addressMine.ts +67 -0
  170. package/zova/src/suite/a-commerce/modules/commerce-member/src/page/address/controller.tsx +21 -11
  171. package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/schemas.ts +40 -32
  172. package/zova/src/suite/a-commerce/modules/commerce-promotion/src/api/openapi/types.ts +638 -633
  173. package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +6 -0
  174. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/component/tableCellActionShip.ts +31 -0
  175. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +248 -1
  176. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/page/checkout.ts +19 -0
  177. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/page/order.ts +19 -0
  178. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/page/orders.ts +19 -0
  179. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/page/payment.ts +19 -0
  180. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +114 -0
  181. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradePayment.ts +36 -0
  182. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +75 -8
  183. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +762 -46
  184. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +35 -0
  185. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradePayment.ts +13 -0
  186. package/zova/src/suite/a-commerce/modules/commerce-trade/src/bean/tableCell.actionShip.tsx +41 -0
  187. package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionShip/controller.tsx +66 -0
  188. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +2 -0
  189. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +2 -0
  190. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +38 -0
  191. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/orderMine.ts +31 -0
  192. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/payment.ts +25 -0
  193. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/cart/controller.tsx +14 -3
  194. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +124 -0
  195. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/order/controller.tsx +105 -0
  196. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/orders/controller.tsx +95 -0
  197. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +88 -0
  198. package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +28 -0
  199. package/zova/src/suite/cabloy-basic/modules/basic-details/src/bean/command.delete.tsx +3 -2
  200. package/zova/src/suite/cabloy-basic/modules/basic-details/src/bean/tableCell.actionUpdate.tsx +2 -1
  201. package/zova/src/suite/cabloy-basic/modules/basic-details/src/bean/tableCell.actionView.tsx +1 -1
  202. package/zova/src/suite/cabloy-basic/modules/basic-details/src/config/locale/en-us.ts +1 -0
  203. package/zova/src/suite/cabloy-basic/modules/basic-details/src/config/locale/zh-cn.ts +1 -0
  204. package/zova/src/suite-vendor/a-zova/modules/a-ssr/package.json +1 -1
  205. package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssr.ts +4 -0
  206. package/zova/src/suite-vendor/a-zova/package.json +2 -2
  207. package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressUpdate.tsx +0 -39
@@ -1,6 +1,6 @@
1
1
  import type {
2
- DtoAddressCreate,
3
- DtoAddressUpdate,
2
+ DtoAddressMineCreate,
3
+ DtoAddressMineUpdate,
4
4
  EntityAddress,
5
5
  } from 'vona-module-commerce-member';
6
6
 
@@ -11,12 +11,17 @@ import { describe, it } from 'node:test';
11
11
  import { app } from 'vona-mock';
12
12
 
13
13
  const actionPath = '/commerce/member/address';
14
+ const minePath = `${actionPath}/mine`;
15
+ const viewMinePath = `${actionPath}/viewMine/:id`;
16
+ const createMinePath = `${actionPath}/createMine`;
17
+ const updateMinePath = `${actionPath}/updateMine/:id`;
18
+ const deleteMinePath = `${actionPath}/deleteMine/:id`;
14
19
 
15
20
  function createTestId() {
16
21
  return randomUUID().slice(0, 12);
17
22
  }
18
23
 
19
- function createAddress(suffix: string): DtoAddressCreate {
24
+ function createAddress(suffix: string): DtoAddressMineCreate {
20
25
  return {
21
26
  recipientName: `Recipient ${suffix}`,
22
27
  phone: '15555550123',
@@ -45,15 +50,23 @@ async function registerAndSignin(name: string) {
45
50
  return { token: token.accessToken, user: app.bean.passport.currentUser! };
46
51
  }
47
52
 
48
- describe('address.test.ts', () => {
49
- it('denies anonymous address actions', async () => {
53
+ async function deleteOwnedAddresses(ids: Array<number | string | undefined>) {
54
+ for (const id of ids) {
55
+ if (id !== undefined) await app.scope('commerce-member').model.address.deleteById(id);
56
+ }
57
+ }
58
+
59
+ describe('addressOwnership.test.ts', () => {
60
+ it('denies anonymous Admin and Web Address actions', async () => {
50
61
  await app.bean.executor.mockCtx(async () => {
51
62
  for (const [method, path, options] of [
52
- ['post', actionPath, { body: createAddress('anonymous') }],
53
63
  ['get', actionPath, {}],
54
64
  ['get', `${actionPath}/:id`, { params: { id: 999999 } }],
55
- ['patch', `${actionPath}/:id`, { params: { id: 999999 }, body: {} }],
56
- ['delete', `${actionPath}/:id`, { params: { id: 999999 } }],
65
+ ['get', minePath, {}],
66
+ ['get', viewMinePath, { params: { id: 999999 } }],
67
+ ['post', createMinePath, { body: createAddress('anonymous') }],
68
+ ['patch', updateMinePath, { params: { id: 999999 }, body: createAddress('anonymous') }],
69
+ ['delete', deleteMinePath, { params: { id: 999999 } }],
57
70
  ] as const) {
58
71
  const [_, err] = await catchError(() =>
59
72
  app.bean.executor.performAction(method, path, { ...options, innerAccess: false }),
@@ -63,146 +76,174 @@ describe('address.test.ts', () => {
63
76
  });
64
77
  });
65
78
 
66
- it('derives ownership from the authenticated customer and scopes every action', async () => {
67
- await app.bean.executor.mockCtx(async () => {
68
- const suffix = createTestId();
69
- const customerA = await registerAndSignin(`address-a-${suffix}`);
70
- const customerB = await registerAndSignin(`address-b-${suffix}`);
71
- const addressData = createAddress(suffix);
72
- const addressId = await performAs(customerA.token, 'post', actionPath, {
73
- body: { ...addressData, userId: customerB.user.id, iid: 999999 } as any,
74
- });
75
-
76
- const persisted = await app.scope('commerce-member').model.address.getById(addressId);
77
- assert.equal(String(persisted?.userId), String(customerA.user.id));
78
- assert.equal(persisted?.iid, app.ctx.instance.id);
79
-
80
- const ownList = await performAs(customerA.token, 'get', actionPath);
81
- assert.equal(
82
- ownList.list.some(item => String(item.id) === String(addressId)),
83
- true,
84
- );
85
- assert.equal(
86
- ownList.list.every(item => !Object.hasOwn(item, 'userId')),
87
- true,
88
- );
89
- assert.equal(
90
- ownList.list.every(item => !Object.hasOwn(item, 'iid')),
91
- true,
92
- );
93
-
94
- const update: DtoAddressUpdate = { ...addressData, city: 'Oakland', addressLine2: undefined };
95
- assert.equal(
96
- await performAs(customerA.token, 'patch', `${actionPath}/:id`, {
97
- params: { id: addressId },
98
- body: update,
99
- }),
100
- null,
101
- );
102
- const ownAddress: EntityAddress = await performAs(
103
- customerA.token,
104
- 'get',
105
- `${actionPath}/:id`,
106
- {
107
- params: { id: addressId },
108
- },
109
- );
110
- assert.equal(ownAddress.city, update.city);
111
- assert.equal(ownAddress.addressLine2, addressData.addressLine2);
112
- assert.equal(Object.hasOwn(ownAddress, 'userId'), false);
113
- assert.equal(Object.hasOwn(ownAddress, 'iid'), false);
114
-
115
- const foreignList = await performAs(customerB.token, 'get', actionPath);
116
- assert.equal(
117
- foreignList.list.some(item => String(item.id) === String(addressId)),
118
- false,
119
- );
120
- assert.equal(
121
- await performAs(customerB.token, 'get', `${actionPath}/:id`, { params: { id: addressId } }),
122
- undefined,
123
- );
124
- assert.equal(
125
- await performAs(customerB.token, 'patch', `${actionPath}/:id`, {
126
- params: { id: addressId },
127
- body: { ...addressData, city: 'Los Angeles' },
128
- }),
129
- null,
130
- );
131
- assert.equal(
132
- await performAs(customerB.token, 'delete', `${actionPath}/:id`, {
133
- params: { id: addressId },
134
- }),
135
- null,
136
- );
137
- assert.equal(
138
- (await app.scope('commerce-member').model.address.getById(addressId))?.city,
139
- 'Oakland',
140
- );
141
-
142
- assert.equal(
143
- await performAs(customerA.token, 'delete', `${actionPath}/:id`, {
144
- params: { id: addressId },
145
- }),
146
- null,
147
- );
148
- assert.equal(
149
- await performAs(customerA.token, 'get', `${actionPath}/:id`, { params: { id: addressId } }),
150
- undefined,
151
- );
152
- });
153
- });
154
-
155
- it('treats another instance address as absent', async () => {
156
- let addressId!: number;
157
- let customerDefault!: Awaited<ReturnType<typeof registerAndSignin>>;
158
- const addressDefault = createAddress('default');
79
+ it('derives Web ownership from Passport and treats foreign rows as absent', async () => {
159
80
  await app.bean.executor.mockCtx(async () => {
160
- customerDefault = await registerAndSignin(`address-default-${Date.now()}`);
161
- addressId = await performAs(customerDefault.token, 'post', actionPath, {
162
- body: addressDefault,
163
- });
164
- });
81
+ let addressId: number | undefined;
82
+ try {
83
+ const suffix = createTestId();
84
+ const customerA = await registerAndSignin(`address-a-${suffix}`);
85
+ const customerB = await registerAndSignin(`address-b-${suffix}`);
86
+ const addressData = createAddress(suffix);
87
+ addressId = await performAs(customerA.token, 'post', createMinePath, {
88
+ body: { ...addressData, userId: customerB.user.id, iid: 999999 } as any,
89
+ });
90
+
91
+ const persisted = await app.scope('commerce-member').model.address.getById(addressId);
92
+ assert.equal(String(persisted?.userId), String(customerA.user.id));
93
+ assert.equal(persisted?.iid, app.ctx.instance.id);
94
+
95
+ const ownList = await performAs(customerA.token, 'get', minePath);
96
+ assert.equal(
97
+ ownList.list.some(item => String(item.id) === String(addressId)),
98
+ true,
99
+ );
100
+ assert.equal(
101
+ ownList.list.every(item => !Object.hasOwn(item, 'userId')),
102
+ true,
103
+ );
104
+ assert.equal(
105
+ ownList.list.every(item => !Object.hasOwn(item, 'iid')),
106
+ true,
107
+ );
165
108
 
166
- await app.bean.executor.mockCtx(
167
- async () => {
168
- const customer = await registerAndSignin(`address-share-${Date.now()}`);
109
+ const { addressLine2: _, ...update } = {
110
+ ...addressData,
111
+ city: 'Oakland',
112
+ } satisfies DtoAddressMineUpdate;
169
113
  assert.equal(
170
- await performAs(customer.token, 'get', `${actionPath}/:id`, {
114
+ await performAs(customerA.token, 'patch', updateMinePath, {
171
115
  params: { id: addressId },
116
+ body: update,
172
117
  }),
173
- undefined,
118
+ null,
174
119
  );
175
- const list = await performAs(customer.token, 'get', actionPath);
120
+ const ownAddress: EntityAddress = await performAs(customerA.token, 'get', viewMinePath, {
121
+ params: { id: addressId },
122
+ });
123
+ assert.equal(ownAddress.city, update.city);
124
+ assert.equal(ownAddress.addressLine2, addressData.addressLine2);
125
+ assert.equal(Object.hasOwn(ownAddress, 'userId'), false);
126
+ assert.equal(Object.hasOwn(ownAddress, 'iid'), false);
127
+
128
+ const foreignList = await performAs(customerB.token, 'get', minePath);
176
129
  assert.equal(
177
- list.list.some(item => String(item.id) === String(addressId)),
130
+ foreignList.list.some(item => String(item.id) === String(addressId)),
178
131
  false,
179
132
  );
180
133
  assert.equal(
181
- await performAs(customer.token, 'patch', `${actionPath}/:id`, {
134
+ await performAs(customerB.token, 'get', viewMinePath, { params: { id: addressId } }),
135
+ undefined,
136
+ );
137
+ assert.equal(
138
+ await performAs(customerB.token, 'patch', updateMinePath, {
182
139
  params: { id: addressId },
183
- body: { ...createAddress('foreign'), city: 'Other city' },
140
+ body: { ...addressData, city: 'Los Angeles' },
184
141
  }),
185
142
  null,
186
143
  );
187
144
  assert.equal(
188
- await performAs(customer.token, 'delete', `${actionPath}/:id`, {
189
- params: { id: addressId },
190
- }),
145
+ await performAs(customerB.token, 'delete', deleteMinePath, { params: { id: addressId } }),
191
146
  null,
192
147
  );
193
148
  assert.equal(
194
- await app.scope('commerce-member').model.address.getById(addressId),
195
- undefined,
149
+ (await app.scope('commerce-member').model.address.getById(addressId))?.city,
150
+ 'Oakland',
196
151
  );
197
- },
198
- { instanceName: 'shareTest' as any },
199
- );
152
+ } finally {
153
+ await deleteOwnedAddresses([addressId]);
154
+ }
155
+ });
156
+ });
200
157
 
158
+ it('exposes active-instance Address inspection only to systemAdmin', async () => {
201
159
  await app.bean.executor.mockCtx(async () => {
202
- const address = await performAs(customerDefault.token, 'get', `${actionPath}/:id`, {
203
- params: { id: addressId },
204
- });
205
- assert.equal(address.city, addressDefault.city);
160
+ let addressId: number | undefined;
161
+ try {
162
+ const suffix = createTestId();
163
+ const customer = await registerAndSignin(`address-admin-${suffix}`);
164
+ addressId = await performAs(customer.token, 'post', createMinePath, {
165
+ body: createAddress(suffix),
166
+ });
167
+
168
+ const [_, nonAdminError] = await catchError(() =>
169
+ performAs(customer.token, 'get', actionPath),
170
+ );
171
+ assert.equal(nonAdminError?.code, 403);
172
+
173
+ const admin = await app.bean.passport.signinMock();
174
+ const list = await performAs(admin.accessToken, 'get', actionPath);
175
+ assert.equal(
176
+ list.list.some(item => String(item.id) === String(addressId)),
177
+ true,
178
+ );
179
+ const address = await performAs(admin.accessToken, 'get', `${actionPath}/:id`, {
180
+ params: { id: addressId },
181
+ });
182
+ assert.equal(address?.id, addressId);
183
+
184
+ const permissions = await Promise.all(
185
+ ['create', 'update', 'delete'].map(action =>
186
+ app.bean.permission.retrievePermissionAction('commerce-member:address', action),
187
+ ),
188
+ );
189
+ assert.deepEqual(permissions, [false, false, false]);
190
+ } finally {
191
+ await deleteOwnedAddresses([addressId]);
192
+ }
206
193
  });
207
194
  });
195
+
196
+ it('treats another instance Address as absent on Web actions', async () => {
197
+ let addressId: number | undefined;
198
+ let customerDefault!: Awaited<ReturnType<typeof registerAndSignin>>;
199
+ const addressDefault = createAddress('default');
200
+ try {
201
+ await app.bean.executor.mockCtx(async () => {
202
+ customerDefault = await registerAndSignin(`address-default-${createTestId()}`);
203
+ addressId = await performAs(customerDefault.token, 'post', createMinePath, {
204
+ body: addressDefault,
205
+ });
206
+ });
207
+
208
+ await app.bean.executor.mockCtx(
209
+ async () => {
210
+ const customer = await registerAndSignin(`address-share-${createTestId()}`);
211
+ assert.equal(
212
+ await performAs(customer.token, 'get', viewMinePath, { params: { id: addressId } }),
213
+ undefined,
214
+ );
215
+ const list = await performAs(customer.token, 'get', minePath);
216
+ assert.equal(
217
+ list.list.some(item => String(item.id) === String(addressId)),
218
+ false,
219
+ );
220
+ assert.equal(
221
+ await performAs(customer.token, 'patch', updateMinePath, {
222
+ params: { id: addressId },
223
+ body: { ...createAddress('foreign'), city: 'Other city' },
224
+ }),
225
+ null,
226
+ );
227
+ assert.equal(
228
+ await performAs(customer.token, 'delete', deleteMinePath, {
229
+ params: { id: addressId },
230
+ }),
231
+ null,
232
+ );
233
+ },
234
+ { instanceName: 'shareTest' as any },
235
+ );
236
+
237
+ await app.bean.executor.mockCtx(async () => {
238
+ const address = await performAs(customerDefault.token, 'get', viewMinePath, {
239
+ params: { id: addressId },
240
+ });
241
+ assert.equal(address.city, addressDefault.city);
242
+ });
243
+ } finally {
244
+ await app.bean.executor.mockCtx(async () => {
245
+ await deleteOwnedAddresses([addressId]);
246
+ });
247
+ }
248
+ });
208
249
  });
@@ -4,12 +4,15 @@ import type { TypeEntityOptionsFields } from 'vona-module-a-openapi';
4
4
  import type { TableIdentity } from 'table-identity';
5
5
  /** entity: begin */
6
6
  export * from '../entity/paymentAttempt.tsx';
7
+ export * from '../entity/paymentAudit.tsx';
7
8
  import type { IEntityOptionsPaymentAttempt } from '../entity/paymentAttempt.tsx';
9
+ import type { IEntityOptionsPaymentAudit } from '../entity/paymentAudit.tsx';
8
10
  import 'vona-module-a-orm';
9
11
  declare module 'vona-module-a-orm' {
10
12
 
11
13
  export interface IEntityRecord {
12
14
  'commerce-payment:paymentAttempt': IEntityOptionsPaymentAttempt;
15
+ 'commerce-payment:paymentAudit': IEntityOptionsPaymentAudit;
13
16
  }
14
17
 
15
18
 
@@ -20,16 +23,21 @@ declare module 'vona-module-commerce-payment' {
20
23
  /** entity: end */
21
24
  /** entity: begin */
22
25
  import type { EntityPaymentAttempt } from '../entity/paymentAttempt.tsx';
26
+ import type { EntityPaymentAudit } from '../entity/paymentAudit.tsx';
23
27
  export interface IModuleEntity {
24
28
  'paymentAttempt': EntityPaymentAttemptMeta;
29
+ 'paymentAudit': EntityPaymentAuditMeta;
25
30
  }
26
31
  /** entity: end */
27
32
  /** entity: begin */
28
33
  export type EntityPaymentAttemptTableName = 'commercePaymentAttempt';
34
+ export type EntityPaymentAuditTableName = 'commercePaymentAudit';
29
35
  export type EntityPaymentAttemptMeta=TypeEntityMeta<EntityPaymentAttempt,EntityPaymentAttemptTableName>;
36
+ export type EntityPaymentAuditMeta=TypeEntityMeta<EntityPaymentAudit,EntityPaymentAuditTableName>;
30
37
  declare module 'vona-module-a-orm' {
31
38
  export interface ITableRecord {
32
39
  'commercePaymentAttempt': EntityPaymentAttemptMeta;
40
+ 'commercePaymentAudit': EntityPaymentAuditMeta;
33
41
  }
34
42
  }
35
43
  declare module 'vona-module-commerce-payment' {
@@ -37,16 +45,23 @@ declare module 'vona-module-commerce-payment' {
37
45
  export interface IEntityOptionsPaymentAttempt {
38
46
  fields?: TypeEntityOptionsFields<EntityPaymentAttempt, IEntityOptionsPaymentAttempt[TypeSymbolKeyFieldsMore]>;
39
47
  }
48
+
49
+ export interface IEntityOptionsPaymentAudit {
50
+ fields?: TypeEntityOptionsFields<EntityPaymentAudit, IEntityOptionsPaymentAudit[TypeSymbolKeyFieldsMore]>;
51
+ }
40
52
  }
41
53
  /** entity: end */
42
54
  /** model: begin */
43
55
  export * from '../model/paymentAttempt.ts';
56
+ export * from '../model/paymentAudit.ts';
44
57
  import type { IModelOptionsPaymentAttempt } from '../model/paymentAttempt.ts';
58
+ import type { IModelOptionsPaymentAudit } from '../model/paymentAudit.ts';
45
59
  import 'vona-module-a-orm';
46
60
  declare module 'vona-module-a-orm' {
47
61
 
48
62
  export interface IModelRecord {
49
63
  'commerce-payment:paymentAttempt': IModelOptionsPaymentAttempt;
64
+ 'commerce-payment:paymentAudit': IModelOptionsPaymentAudit;
50
65
  }
51
66
 
52
67
 
@@ -62,13 +77,26 @@ declare module 'vona-module-commerce-payment' {
62
77
  get $beanFullName(): 'commerce-payment.model.paymentAttempt';
63
78
  get $onionName(): 'commerce-payment:paymentAttempt';
64
79
  get $onionOptions(): IModelOptionsPaymentAttempt;
80
+ }
81
+
82
+ export interface ModelPaymentAudit {
83
+ /** @internal */
84
+ get scope(): ScopeModuleCommercePayment;
85
+ }
86
+
87
+ export interface ModelPaymentAudit {
88
+ get $beanFullName(): 'commerce-payment.model.paymentAudit';
89
+ get $onionName(): 'commerce-payment:paymentAudit';
90
+ get $onionOptions(): IModelOptionsPaymentAudit;
65
91
  }
66
92
  }
67
93
  /** model: end */
68
94
  /** model: begin */
69
95
  import type { ModelPaymentAttempt } from '../model/paymentAttempt.ts';
96
+ import type { ModelPaymentAudit } from '../model/paymentAudit.ts';
70
97
  export interface IModuleModel {
71
98
  'paymentAttempt': ModelPaymentAttempt;
99
+ 'paymentAudit': ModelPaymentAudit;
72
100
  }
73
101
  /** model: end */
74
102
  /** model: begin */
@@ -77,6 +105,7 @@ import 'vona';
77
105
  declare module 'vona' {
78
106
  export interface IBeanRecordGeneral {
79
107
  'commerce-payment.model.paymentAttempt': ModelPaymentAttempt;
108
+ 'commerce-payment.model.paymentAudit': ModelPaymentAudit;
80
109
  }
81
110
  }
82
111
  /** model: end */
@@ -112,27 +141,68 @@ declare module 'vona-module-commerce-payment' {
112
141
  updateById<T extends IModelUpdateOptions<EntityPaymentAttempt,ModelPaymentAttempt>>(id: TableIdentity, data: TypeModelMutateRelationData<EntityPaymentAttempt,ModelPaymentAttempt, T>, options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAttempt,ModelPaymentAttempt, T>>;
113
142
  deleteById<T extends IModelDeleteOptions<EntityPaymentAttempt,ModelPaymentAttempt>>(id: TableIdentity, options?: T): Promise<void>;
114
143
  }
144
+ export interface ModelPaymentAudit {
145
+ [SymbolKeyEntity]: EntityPaymentAudit;
146
+ [SymbolKeyEntityMeta]: EntityPaymentAuditMeta;
147
+ [SymbolKeyModelOptions]: IModelOptionsPaymentAudit;
148
+ get<T extends IModelGetOptions<EntityPaymentAudit,ModelPaymentAudit>>(where: TypeModelWhere<EntityPaymentAudit>, options?: T): Promise<TypeModelRelationResult<EntityPaymentAudit, ModelPaymentAudit, T> | undefined>;
149
+ getForUpdate<T extends IModelGetOptions<EntityPaymentAudit,ModelPaymentAudit>>(where: TypeModelWhere<EntityPaymentAudit>, options?: T): Promise<TypeModelRelationResult<EntityPaymentAudit, ModelPaymentAudit, T> | undefined>;
150
+ getByIdForUpdate<T extends IModelGetOptions<EntityPaymentAudit,ModelPaymentAudit>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityPaymentAudit, ModelPaymentAudit, T> | undefined>;
151
+ mget<T extends IModelGetOptions<EntityPaymentAudit,ModelPaymentAudit>>(ids: TableIdentity[], options?: T): Promise<TypeModelRelationResult<EntityPaymentAudit, ModelPaymentAudit, T>[]>;
152
+ selectAndCount<T extends IModelSelectParams<EntityPaymentAudit,ModelPaymentAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelSelectAndCount<EntityPaymentAudit, ModelPaymentAudit, T>>;
153
+ select<T extends IModelSelectParams<EntityPaymentAudit,ModelPaymentAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelRelationResult<EntityPaymentAudit, ModelPaymentAudit, T>[]>;
154
+ insert<T extends IModelInsertOptions<EntityPaymentAudit,ModelPaymentAudit>>(data?: TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>, options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T, true>>;
155
+ insertBulk<T extends IModelInsertOptions<EntityPaymentAudit,ModelPaymentAudit>>(items: TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T, true>[]>;
156
+ update<T extends IModelUpdateOptions<EntityPaymentAudit,ModelPaymentAudit>>(data: TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>, options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>>;
157
+ updateBulk<T extends IModelUpdateOptions<EntityPaymentAudit,ModelPaymentAudit>>(items: TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>[]>;
158
+ delete<T extends IModelDeleteOptions<EntityPaymentAudit,ModelPaymentAudit>>(where?: TypeModelWhere<EntityPaymentAudit>, options?: T): Promise<void>;
159
+ deleteBulk<T extends IModelDeleteOptions<EntityPaymentAudit,ModelPaymentAudit>>(ids: TableIdentity[], options?: T): Promise<void>;
160
+ mutate<T extends IModelMutateOptions<EntityPaymentAudit,ModelPaymentAudit>>(data?: TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>, options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>>;
161
+ mutateBulk<T extends IModelMutateOptions<EntityPaymentAudit,ModelPaymentAudit>>(items: TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>[], options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>[]>;
162
+ count<T extends IModelSelectCountParams<EntityPaymentAudit,ModelPaymentAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<string | undefined>;
163
+ increment<T extends IModelIncrementParams<EntityPaymentAudit,ModelPaymentAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<number>;
164
+ decrement<T extends IModelIncrementParams<EntityPaymentAudit,ModelPaymentAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<number>;
165
+ aggregate<T extends IModelSelectAggrParams<EntityPaymentAudit,ModelPaymentAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelAggrRelationResult<T>>;
166
+ group<T extends IModelSelectGroupParams<EntityPaymentAudit,ModelPaymentAudit,ModelJoins>, ModelJoins extends TypeModelsClassLikeGeneral | undefined = undefined>(params?: T, options?: IModelMethodOptions, modelJoins?: ModelJoins): Promise<TypeModelGroupRelationResult<EntityPaymentAudit, T>[]>;
167
+ getById<T extends IModelGetOptions<EntityPaymentAudit,ModelPaymentAudit>>(id: TableIdentity, options?: T): Promise<TypeModelRelationResult<EntityPaymentAudit, ModelPaymentAudit, T> | undefined>;
168
+ updateById<T extends IModelUpdateOptions<EntityPaymentAudit,ModelPaymentAudit>>(id: TableIdentity, data: TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>, options?: T): Promise<TypeModelMutateRelationData<EntityPaymentAudit,ModelPaymentAudit, T>>;
169
+ deleteById<T extends IModelDeleteOptions<EntityPaymentAudit,ModelPaymentAudit>>(id: TableIdentity, options?: T): Promise<void>;
170
+ }
115
171
  }
116
172
  declare module 'vona-module-a-orm' {
117
173
  export interface IModelClassRecord {
118
174
  'commerce-payment:paymentAttempt': ModelPaymentAttempt;
175
+ 'commerce-payment:paymentAudit': ModelPaymentAudit;
119
176
  }
120
177
  }
121
178
  /** model: end */
122
179
  /** service: begin */
180
+ export * from '../service/mockPaymentAdapter.ts';
123
181
  export * from '../service/paymentAttempt.ts';
124
182
 
125
183
  import 'vona-module-a-bean';
126
184
  declare module 'vona-module-a-bean' {
127
185
 
128
186
  export interface IServiceRecord {
129
- 'commerce-payment:paymentAttempt': never;
187
+ 'commerce-payment:mockPaymentAdapter': never;
188
+ 'commerce-payment:paymentAttempt': never;
130
189
  }
131
190
 
132
191
 
133
192
  }
134
193
  declare module 'vona-module-commerce-payment' {
135
194
 
195
+ export interface ServiceMockPaymentAdapter {
196
+ /** @internal */
197
+ get scope(): ScopeModuleCommercePayment;
198
+ }
199
+
200
+ export interface ServiceMockPaymentAdapter {
201
+ get $beanFullName(): 'commerce-payment.service.mockPaymentAdapter';
202
+ get $onionName(): 'commerce-payment:mockPaymentAdapter';
203
+
204
+ }
205
+
136
206
  export interface ServicePaymentAttempt {
137
207
  /** @internal */
138
208
  get scope(): ScopeModuleCommercePayment;
@@ -146,9 +216,11 @@ declare module 'vona-module-commerce-payment' {
146
216
  }
147
217
  /** service: end */
148
218
  /** service: begin */
219
+ import type { ServiceMockPaymentAdapter } from '../service/mockPaymentAdapter.ts';
149
220
  import type { ServicePaymentAttempt } from '../service/paymentAttempt.ts';
150
221
  export interface IModuleService {
151
- 'paymentAttempt': ServicePaymentAttempt;
222
+ 'mockPaymentAdapter': ServiceMockPaymentAdapter;
223
+ 'paymentAttempt': ServicePaymentAttempt;
152
224
  }
153
225
  /** service: end */
154
226
  /** service: begin */
@@ -156,7 +228,8 @@ export interface IModuleService {
156
228
  import 'vona';
157
229
  declare module 'vona' {
158
230
  export interface IBeanRecordGeneral {
159
- 'commerce-payment.service.paymentAttempt': ServicePaymentAttempt;
231
+ 'commerce-payment.service.mockPaymentAdapter': ServiceMockPaymentAdapter;
232
+ 'commerce-payment.service.paymentAttempt': ServicePaymentAttempt;
160
233
  }
161
234
  }
162
235
  /** service: end */
@@ -10,6 +10,9 @@ import { $tableColumns } from 'vona-module-a-ormutils';
10
10
  ...$tableColumns('commercePaymentAttempt', 'userId'),
11
11
  ...$tableColumns('commercePaymentAttempt', 'state'),
12
12
  ...$tableColumns('commercePaymentAttempt', 'correlationId'),
13
+ ...$tableColumns('commercePaymentAudit', 'paymentAttemptId'),
14
+ ...$tableColumns('commercePaymentAudit', 'orderId'),
15
+ ...$tableColumns('commercePaymentAudit', 'idempotencyKey'),
13
16
  },
14
17
  })
15
18
  export class MetaIndex extends BeanBase {}
@@ -26,10 +26,47 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate {
26
26
  table
27
27
  .string(entityPaymentAttempt.correlationId, 100)
28
28
  .comment(entityPaymentAttempt.$comment.correlationId);
29
+ table
30
+ .dateTime(entityPaymentAttempt.finalizedAt)
31
+ .nullable()
32
+ .comment(entityPaymentAttempt.$comment.finalizedAt);
29
33
  table
30
34
  .dateTime(entityPaymentAttempt.cancelledAt)
31
35
  .nullable()
32
36
  .comment(entityPaymentAttempt.$comment.cancelledAt);
33
37
  });
38
+
39
+ const entityPaymentAudit = this.scope.entity.paymentAudit;
40
+ await this.bean.model.createTable(entityPaymentAudit.$table, table => {
41
+ table.comment(entityPaymentAudit.$comment.$table);
42
+ table.basicFields();
43
+ table
44
+ .tableIdentity(entityPaymentAudit.paymentAttemptId)
45
+ .comment(entityPaymentAudit.$comment.paymentAttemptId);
46
+ table.tableIdentity(entityPaymentAudit.orderId).comment(entityPaymentAudit.$comment.orderId);
47
+ table.userId(entityPaymentAudit.userId).comment(entityPaymentAudit.$comment.userId);
48
+ table.string(entityPaymentAudit.provider, 20).comment(entityPaymentAudit.$comment.provider);
49
+ table.string(entityPaymentAudit.outcome, 20).comment(entityPaymentAudit.$comment.outcome);
50
+ table
51
+ .string(entityPaymentAudit.fromAttemptState, 20)
52
+ .comment(entityPaymentAudit.$comment.fromAttemptState);
53
+ table
54
+ .string(entityPaymentAudit.toOrderState, 30)
55
+ .comment(entityPaymentAudit.$comment.toOrderState);
56
+ table
57
+ .string(entityPaymentAudit.idempotencyKey, 100)
58
+ .comment(entityPaymentAudit.$comment.idempotencyKey);
59
+ table
60
+ .string(entityPaymentAudit.correlationId, 100)
61
+ .comment(entityPaymentAudit.$comment.correlationId);
62
+ table.string(entityPaymentAudit.reason, 255).comment(entityPaymentAudit.$comment.reason);
63
+ table
64
+ .userId(entityPaymentAudit.actorId)
65
+ .nullable()
66
+ .comment(entityPaymentAudit.$comment.actorId);
67
+ table
68
+ .dateTime(entityPaymentAudit.processedAt)
69
+ .comment(entityPaymentAudit.$comment.processedAt);
70
+ });
34
71
  }
35
72
  }
@@ -15,8 +15,8 @@ export class DtoPaymentAttemptView {
15
15
  @Api.field(v.tableIdentity())
16
16
  orderId: TableIdentity;
17
17
 
18
- @Api.field(z.enum(['created', 'cancelled']))
19
- state: 'created' | 'cancelled';
18
+ @Api.field(z.enum(['created', 'succeeded', 'failed', 'cancelled']))
19
+ state: 'created' | 'succeeded' | 'failed' | 'cancelled';
20
20
 
21
21
  @Api.field(z.literal('USD'))
22
22
  currency: 'USD';
@@ -5,7 +5,7 @@ import { Api, v } from 'vona-module-a-openapiutils';
5
5
  import { Entity, EntityBase } from 'vona-module-a-orm';
6
6
  import { z } from 'zod';
7
7
 
8
- export type TypePaymentAttemptState = 'created' | 'cancelled';
8
+ export type TypePaymentAttemptState = 'created' | 'succeeded' | 'failed' | 'cancelled';
9
9
 
10
10
  export interface IEntityOptionsPaymentAttempt extends IDecoratorEntityOptions {}
11
11
 
@@ -17,7 +17,7 @@ export class EntityPaymentAttempt extends EntityBase {
17
17
  @Api.field(v.tableIdentity())
18
18
  userId: TableIdentity;
19
19
 
20
- @Api.field(z.enum(['created', 'cancelled']))
20
+ @Api.field(z.enum(['created', 'succeeded', 'failed', 'cancelled']))
21
21
  state: TypePaymentAttemptState;
22
22
 
23
23
  @Api.field(z.literal('USD'))
@@ -29,6 +29,9 @@ export class EntityPaymentAttempt extends EntityBase {
29
29
  @Api.field(v.required(), v.min(1), v.max(100))
30
30
  correlationId: string;
31
31
 
32
+ @Api.field(v.optional())
33
+ finalizedAt?: Date;
34
+
32
35
  @Api.field(v.optional())
33
36
  cancelledAt?: Date;
34
37
  }