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
@@ -0,0 +1,54 @@
1
+ import type { TableIdentity } from 'table-identity';
2
+ import type { IDecoratorEntityOptions } from 'vona-module-a-orm';
3
+
4
+ import { Api, v } from 'vona-module-a-openapiutils';
5
+ import { Entity, EntityBase } from 'vona-module-a-orm';
6
+ import { z } from 'zod';
7
+
8
+ import type { TypePaymentAttemptState } from './paymentAttempt.tsx';
9
+
10
+ export type TypePaymentOutcome = Extract<
11
+ TypePaymentAttemptState,
12
+ 'succeeded' | 'failed' | 'cancelled'
13
+ >;
14
+
15
+ export interface IEntityOptionsPaymentAudit extends IDecoratorEntityOptions {}
16
+
17
+ @Entity<IEntityOptionsPaymentAudit>('commercePaymentAudit')
18
+ export class EntityPaymentAudit extends EntityBase {
19
+ @Api.field(v.tableIdentity())
20
+ paymentAttemptId: TableIdentity;
21
+
22
+ @Api.field(v.tableIdentity())
23
+ orderId: TableIdentity;
24
+
25
+ @Api.field(v.tableIdentity())
26
+ userId: TableIdentity;
27
+
28
+ @Api.field(z.literal('mock'))
29
+ provider: 'mock';
30
+
31
+ @Api.field(z.enum(['succeeded', 'failed', 'cancelled']))
32
+ outcome: TypePaymentOutcome;
33
+
34
+ @Api.field(z.enum(['created', 'succeeded', 'failed', 'cancelled']))
35
+ fromAttemptState: TypePaymentAttemptState;
36
+
37
+ @Api.field(z.enum(['paid', 'cancelled', 'expired']))
38
+ toOrderState: 'paid' | 'cancelled' | 'expired';
39
+
40
+ @Api.field(v.required(), v.min(1), v.max(100))
41
+ idempotencyKey: string;
42
+
43
+ @Api.field(v.required(), v.min(1), v.max(100))
44
+ correlationId: string;
45
+
46
+ @Api.field(v.required(), v.min(1), v.max(255))
47
+ reason: string;
48
+
49
+ @Api.field(v.optional(), v.tableIdentity())
50
+ actorId?: TableIdentity;
51
+
52
+ @Api.field(v.required())
53
+ processedAt: Date;
54
+ }
@@ -0,0 +1,10 @@
1
+ import type { IDecoratorModelOptions } from 'vona-module-a-orm';
2
+
3
+ import { BeanModelBase, Model } from 'vona-module-a-orm';
4
+
5
+ import { EntityPaymentAudit } from '../entity/paymentAudit.tsx';
6
+
7
+ export interface IModelOptionsPaymentAudit extends IDecoratorModelOptions<EntityPaymentAudit> {}
8
+
9
+ @Model<IModelOptionsPaymentAudit>({ entity: EntityPaymentAudit })
10
+ export class ModelPaymentAudit extends BeanModelBase<EntityPaymentAudit> {}
@@ -0,0 +1,18 @@
1
+ import { BeanBase } from 'vona';
2
+ import { Service } from 'vona-module-a-bean';
3
+
4
+ import type { TypePaymentOutcome } from '../entity/paymentAudit.tsx';
5
+
6
+ export interface IPaymentProviderAdapter {
7
+ readonly provider: 'mock';
8
+ normalizeOutcome(outcome: TypePaymentOutcome): TypePaymentOutcome;
9
+ }
10
+
11
+ @Service()
12
+ export class ServiceMockPaymentAdapter extends BeanBase implements IPaymentProviderAdapter {
13
+ readonly provider = 'mock' as const;
14
+
15
+ normalizeOutcome(outcome: TypePaymentOutcome): TypePaymentOutcome {
16
+ return outcome;
17
+ }
18
+ }
@@ -4,7 +4,7 @@ import { BeanBase } from 'vona';
4
4
  import { Service } from 'vona-module-a-bean';
5
5
  import { Core } from 'vona-module-a-core';
6
6
 
7
- import type { EntityPaymentAttempt } from '../entity/paymentAttempt.tsx';
7
+ import type { EntityPaymentAttempt, TypePaymentAttemptState } from '../entity/paymentAttempt.tsx';
8
8
 
9
9
  export interface IPaymentAttemptCreateCommand {
10
10
  orderId: TableIdentity;
@@ -14,6 +14,11 @@ export interface IPaymentAttemptCreateCommand {
14
14
  correlationId: string;
15
15
  }
16
16
 
17
+ export type TypePaymentAttemptFinalState = Extract<
18
+ TypePaymentAttemptState,
19
+ 'succeeded' | 'failed' | 'cancelled'
20
+ >;
21
+
17
22
  @Service()
18
23
  export class ServicePaymentAttempt extends BeanBase {
19
24
  async create(command: IPaymentAttemptCreateCommand): Promise<EntityPaymentAttempt> {
@@ -27,15 +32,25 @@ export class ServicePaymentAttempt extends BeanBase {
27
32
  });
28
33
  }
29
34
 
30
- @Core.transaction({ isolationLevel: 'SERIALIZABLE' })
31
- async cancel(orderId: TableIdentity): Promise<EntityPaymentAttempt | undefined> {
35
+ async finalize(
36
+ orderId: TableIdentity,
37
+ state: TypePaymentAttemptFinalState,
38
+ ): Promise<EntityPaymentAttempt | undefined> {
32
39
  const attempt = await this.scope.model.paymentAttempt.getForUpdate({ orderId });
33
- if (!attempt || attempt.state === 'cancelled') return attempt;
34
- const cancelledAt = new Date();
40
+ if (!attempt || attempt.state === state) return attempt;
41
+ if (attempt.state !== 'created') this.app.throw(409, 'payment attempt is already finalized');
42
+ const finalizedAt = new Date();
43
+ const cancelledAt = state === 'cancelled' ? finalizedAt : undefined;
35
44
  await this.scope.model.paymentAttempt.updateById(attempt.id, {
36
- state: 'cancelled',
45
+ state,
46
+ finalizedAt,
37
47
  cancelledAt,
38
48
  });
39
- return { ...attempt, state: 'cancelled', cancelledAt };
49
+ return { ...attempt, state, finalizedAt, cancelledAt };
50
+ }
51
+
52
+ @Core.transaction({ isolationLevel: 'SERIALIZABLE' })
53
+ async cancel(orderId: TableIdentity): Promise<EntityPaymentAttempt | undefined> {
54
+ return await this.finalize(orderId, 'cancelled');
40
55
  }
41
56
  }
@@ -14,7 +14,7 @@ export class DtoCouponIssue {
14
14
  @Api.field(v.required(), v.tableIdentity())
15
15
  userId: TableIdentity;
16
16
 
17
- @Api.field(v.required(), v.min(1), v.max(100))
17
+ @Api.field(v.required(), v.min(1), v.max(80))
18
18
  correlationId: string;
19
19
 
20
20
  @Api.field(v.required(), v.min(1), v.max(255))
@@ -42,7 +42,7 @@ const serializationRetryOptions = {
42
42
  minTimeout: 0,
43
43
  maxTimeout: 0,
44
44
  randomize: false,
45
- errorCodes: ['40001'],
45
+ errorCodes: ['40001', 'ER_LOCK_DEADLOCK', 'ER_LOCK_WAIT_TIMEOUT'],
46
46
  ownerOnly: true,
47
47
  };
48
48
 
@@ -52,9 +52,14 @@ export class ServiceCoupon extends BeanBase {
52
52
  @Core.retryable(serializationRetryOptions)
53
53
  async issue(command: ICouponIssueCommand): Promise<EntityCouponGrant> {
54
54
  this._assertCommand(command);
55
+ if (command.correlationId.length > 80) {
56
+ this.app.throw(400, 'coupon issuance correlationId is too long');
57
+ }
55
58
  const template = await this.scope.model.couponTemplate.getByIdForUpdate(command.templateId);
56
59
  if (!template) this.app.throw(404, 'coupon template not found');
57
60
  this._assertTemplateIssuable(template);
61
+ const user = await this.bean.user.findOneById(command.userId);
62
+ if (!user) this.app.throw(404, 'coupon recipient not found');
58
63
  const existing = await this.scope.model.couponGrant.get({
59
64
  couponCode: command.correlationId,
60
65
  });