cabloy 5.1.117 → 5.1.119

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 (119) hide show
  1. package/.cabloy-version +1 -1
  2. package/.github/workflows/vona-test-pg.yml +2 -2
  3. package/.github/workflows/vona-test-sqlite3.yml +2 -2
  4. package/CHANGELOG.md +19 -0
  5. package/cabloy-docs/backend/metrics-guide.md +75 -0
  6. package/e2e/specs/a-commerce/commerce.spec.ts +111 -0
  7. package/observability/README.md +18 -0
  8. package/observability/collector/otel-collector.yaml +34 -0
  9. package/observability/docker-compose.metrics.yml +25 -0
  10. package/observability/grafana/provisioning/datasources/prometheus.yaml +8 -0
  11. package/observability/prometheus/prometheus.yaml +7 -0
  12. package/package.json +1 -1
  13. package/scripts/upgrade.ts +1 -0
  14. package/vona/env/.env +6 -0
  15. package/vona/packages-cli/cli/package.json +1 -1
  16. package/vona/packages-cli/cli-set-api/package.json +1 -1
  17. package/vona/packages-vona/vona/package.json +1 -1
  18. package/vona/packages-vona/vona-core/package.json +1 -1
  19. package/vona/packages-vona/vona-core/src/lib/framework/processWorker.ts +1 -1
  20. package/vona/packages-vona/vona-mock/package.json +1 -1
  21. package/vona/packages-vona/vona-mock/src/index.ts +2 -0
  22. package/vona/packages-vona/vona-mock/src/lib/testLock.ts +21 -0
  23. package/vona/pnpm-lock.yaml +167 -64
  24. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/catalog.test.ts +13 -3
  25. package/vona/src/suite/a-commerce/modules/commerce-catalog/test/product.test.ts +124 -70
  26. package/vona/src/suite/a-commerce/modules/commerce-payment/src/.metadata/index.ts +221 -0
  27. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.index.ts +12 -0
  28. package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/meta.version.ts +91 -0
  29. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/refundAttempt.tsx +37 -0
  30. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/refundAudit.tsx +47 -0
  31. package/vona/src/suite/a-commerce/modules/commerce-payment/src/entity/refundRequest.tsx +43 -0
  32. package/vona/src/suite/a-commerce/modules/commerce-payment/src/model/refundAttempt.ts +10 -0
  33. package/vona/src/suite/a-commerce/modules/commerce-payment/src/model/refundAudit.ts +10 -0
  34. package/vona/src/suite/a-commerce/modules/commerce-payment/src/model/refundRequest.ts +10 -0
  35. package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +36 -0
  36. package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +43 -0
  37. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderDetail.tsx +23 -2
  38. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectResItem.tsx +3 -0
  39. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSummary.tsx +23 -2
  40. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundOutcomeCreate.tsx +16 -0
  41. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRequestCreate.tsx +15 -0
  42. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundResult.tsx +35 -0
  43. package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundReview.tsx +15 -0
  44. package/vona/src/suite/a-commerce/modules/commerce-trade/src/entity/orderAudit.tsx +55 -13
  45. package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +459 -10
  46. package/vona/src/suite/a-commerce/modules/commerce-trade/test/cartOwnership.test.ts +2 -4
  47. package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutReservation.test.ts +2 -4
  48. package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutTransaction.test.ts +2 -4
  49. package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +2 -4
  50. package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +2 -4
  51. package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +337 -0
  52. package/vona/src/suite/a-commerce/modules/commerce-trade/test/reservationExpiry.test.ts +2 -3
  53. package/vona/src/suite/a-commerce/modules/commerce-trade/test/shipment.test.ts +2 -4
  54. package/vona/src/suite/a-commerce/modules/commerce-trade/test/shipmentRefundRace.test.ts +143 -0
  55. package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockBalance.test.ts +2 -4
  56. package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockReservation.test.ts +2 -4
  57. package/vona/src/suite/cabloy-basic/modules/basic-metrics/package.json +54 -0
  58. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/.metadata/index.ts +189 -0
  59. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/.metadata/this.ts +1 -0
  60. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/bean/ssrMenu.metrics.ts +23 -0
  61. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/controller/metrics.ts +21 -0
  62. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/dto/metricsQueue.ts +25 -0
  63. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/dto/metricsRuntime.ts +36 -0
  64. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/dto/metricsSnapshot.ts +21 -0
  65. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/index.ts +1 -0
  66. package/vona/src/suite/cabloy-basic/modules/basic-metrics/src/service/metrics.ts +11 -0
  67. package/vona/src/suite/cabloy-basic/modules/basic-metrics/tsconfig.build.json +11 -0
  68. package/vona/src/suite/cabloy-basic/modules/basic-metrics/tsconfig.json +5 -0
  69. package/vona/src/suite/cabloy-basic/package.json +1 -0
  70. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
  71. package/vona/src/suite-vendor/a-vona/modules/a-instance/package.json +1 -1
  72. package/vona/src/suite-vendor/a-vona/modules/a-instance/src/bean/middlewareSystem.app.ts +2 -0
  73. package/vona/src/suite-vendor/a-vona/modules/a-instance/src/bean/middlewareSystem.instance.ts +2 -0
  74. package/vona/src/suite-vendor/a-vona/modules/a-metrics/package.json +62 -0
  75. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/.metadata/index.ts +178 -0
  76. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/.metadata/this.ts +1 -0
  77. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/bean/bean.metrics.ts +15 -0
  78. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/bean/middlewareSystem.health.ts +24 -0
  79. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/bean/middlewareSystem.metrics.ts +51 -0
  80. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/config/config.ts +75 -0
  81. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/index.ts +2 -0
  82. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/monkey.ts +27 -0
  83. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/service/health.ts +53 -0
  84. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/service/metrics.ts +222 -0
  85. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/service/metricsRuntime.ts +69 -0
  86. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/types/context.ts +9 -0
  87. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/types/index.ts +2 -0
  88. package/vona/src/suite-vendor/a-vona/modules/a-metrics/src/types/metrics.ts +50 -0
  89. package/vona/src/suite-vendor/a-vona/modules/a-metrics/tsconfig.build.json +11 -0
  90. package/vona/src/suite-vendor/a-vona/modules/a-metrics/tsconfig.json +7 -0
  91. package/vona/src/suite-vendor/a-vona/package.json +2 -1
  92. package/zova/pnpm-lock.yaml +104 -89
  93. package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +4 -0
  94. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/component/tableCellActionRefund.ts +31 -0
  95. package/zova/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +35 -6
  96. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +104 -0
  97. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +16 -0
  98. package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +231 -2
  99. package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +20 -0
  100. package/zova/src/suite/a-commerce/modules/commerce-trade/src/bean/tableCell.actionRefund.tsx +40 -0
  101. package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionRefund/controller.tsx +106 -0
  102. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +7 -0
  103. package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +7 -0
  104. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +45 -1
  105. package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/orderMine.ts +15 -0
  106. package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/order/controller.tsx +41 -0
  107. package/zova/src/suite/cabloy-basic/modules/basic-metrics/package.json +53 -0
  108. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/.metadata/index.ts +151 -0
  109. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/.metadata/page/dashboard.ts +9 -0
  110. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/.metadata/this.ts +1 -0
  111. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/api/basicMetricsMetrics.ts +41 -0
  112. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/index.ts +2 -0
  113. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/model/metrics.ts +16 -0
  114. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/page/dashboard/controller.tsx +95 -0
  115. package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/routes.ts +5 -0
  116. package/zova/src/suite/cabloy-basic/modules/basic-metrics/tsconfig.build.json +13 -0
  117. package/zova/src/suite/cabloy-basic/modules/basic-metrics/tsconfig.json +5 -0
  118. package/zova/src/suite/cabloy-basic/package.json +1 -0
  119. package/vona/src/suite/a-commerce/modules/commerce-trade/test/testLock.ts +0 -11
@@ -68,5 +68,96 @@ export class MetaVersion extends BeanBase implements IMetaVersionUpdate {
68
68
  .dateTime(entityPaymentAudit.processedAt)
69
69
  .comment(entityPaymentAudit.$comment.processedAt);
70
70
  });
71
+
72
+ const entityRefundRequest = this.scope.entity.refundRequest;
73
+ await this.bean.model.createTable(entityRefundRequest.$table, table => {
74
+ table.comment(entityRefundRequest.$comment.$table);
75
+ table.basicFields();
76
+ table
77
+ .tableIdentity(entityRefundRequest.orderId)
78
+ .comment(entityRefundRequest.$comment.orderId);
79
+ table.userId(entityRefundRequest.userId).comment(entityRefundRequest.$comment.userId);
80
+ table.string(entityRefundRequest.state, 20).comment(entityRefundRequest.$comment.state);
81
+ table.string(entityRefundRequest.currency, 3).comment(entityRefundRequest.$comment.currency);
82
+ table
83
+ .integer(entityRefundRequest.amountCents)
84
+ .comment(entityRefundRequest.$comment.amountCents);
85
+ table
86
+ .string(entityRefundRequest.correlationId, 100)
87
+ .comment(entityRefundRequest.$comment.correlationId);
88
+ table.string(entityRefundRequest.reason, 255).comment(entityRefundRequest.$comment.reason);
89
+ table
90
+ .userId(entityRefundRequest.reviewedBy)
91
+ .nullable()
92
+ .comment(entityRefundRequest.$comment.reviewedBy);
93
+ table
94
+ .dateTime(entityRefundRequest.reviewedAt)
95
+ .nullable()
96
+ .comment(entityRefundRequest.$comment.reviewedAt);
97
+ table
98
+ .dateTime(entityRefundRequest.finalizedAt)
99
+ .nullable()
100
+ .comment(entityRefundRequest.$comment.finalizedAt);
101
+ });
102
+
103
+ const entityRefundAttempt = this.scope.entity.refundAttempt;
104
+ await this.bean.model.createTable(entityRefundAttempt.$table, table => {
105
+ table.comment(entityRefundAttempt.$comment.$table);
106
+ table.basicFields();
107
+ table
108
+ .tableIdentity(entityRefundAttempt.refundRequestId)
109
+ .comment(entityRefundAttempt.$comment.refundRequestId);
110
+ table
111
+ .tableIdentity(entityRefundAttempt.orderId)
112
+ .comment(entityRefundAttempt.$comment.orderId);
113
+ table.userId(entityRefundAttempt.userId).comment(entityRefundAttempt.$comment.userId);
114
+ table.string(entityRefundAttempt.state, 20).comment(entityRefundAttempt.$comment.state);
115
+ table.string(entityRefundAttempt.currency, 3).comment(entityRefundAttempt.$comment.currency);
116
+ table
117
+ .integer(entityRefundAttempt.amountCents)
118
+ .comment(entityRefundAttempt.$comment.amountCents);
119
+ table
120
+ .string(entityRefundAttempt.correlationId, 100)
121
+ .comment(entityRefundAttempt.$comment.correlationId);
122
+ table
123
+ .dateTime(entityRefundAttempt.finalizedAt)
124
+ .nullable()
125
+ .comment(entityRefundAttempt.$comment.finalizedAt);
126
+ });
127
+
128
+ const entityRefundAudit = this.scope.entity.refundAudit;
129
+ await this.bean.model.createTable(entityRefundAudit.$table, table => {
130
+ table.comment(entityRefundAudit.$comment.$table);
131
+ table.basicFields();
132
+ table
133
+ .tableIdentity(entityRefundAudit.refundRequestId)
134
+ .comment(entityRefundAudit.$comment.refundRequestId);
135
+ table
136
+ .tableIdentity(entityRefundAudit.refundAttemptId)
137
+ .nullable()
138
+ .comment(entityRefundAudit.$comment.refundAttemptId);
139
+ table.tableIdentity(entityRefundAudit.orderId).comment(entityRefundAudit.$comment.orderId);
140
+ table.userId(entityRefundAudit.userId).comment(entityRefundAudit.$comment.userId);
141
+ table
142
+ .string(entityRefundAudit.toRefundState, 20)
143
+ .comment(entityRefundAudit.$comment.toRefundState);
144
+ table
145
+ .string(entityRefundAudit.attemptState, 20)
146
+ .nullable()
147
+ .comment(entityRefundAudit.$comment.attemptState);
148
+ table
149
+ .string(entityRefundAudit.idempotencyKey, 100)
150
+ .nullable()
151
+ .comment(entityRefundAudit.$comment.idempotencyKey);
152
+ table
153
+ .string(entityRefundAudit.correlationId, 100)
154
+ .comment(entityRefundAudit.$comment.correlationId);
155
+ table.string(entityRefundAudit.reason, 255).comment(entityRefundAudit.$comment.reason);
156
+ table
157
+ .userId(entityRefundAudit.actorId)
158
+ .nullable()
159
+ .comment(entityRefundAudit.$comment.actorId);
160
+ table.dateTime(entityRefundAudit.processedAt).comment(entityRefundAudit.$comment.processedAt);
161
+ });
71
162
  }
72
163
  }
@@ -0,0 +1,37 @@
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
+ export type TypeRefundAttemptState = 'created' | 'succeeded' | 'failed';
9
+
10
+ export interface IEntityOptionsRefundAttempt extends IDecoratorEntityOptions {}
11
+
12
+ @Entity<IEntityOptionsRefundAttempt>('commercePaymentRefundAttempt')
13
+ export class EntityRefundAttempt extends EntityBase {
14
+ @Api.field(v.tableIdentity())
15
+ refundRequestId: TableIdentity;
16
+
17
+ @Api.field(v.tableIdentity())
18
+ orderId: TableIdentity;
19
+
20
+ @Api.field(v.tableIdentity())
21
+ userId: TableIdentity;
22
+
23
+ @Api.field(z.enum(['created', 'succeeded', 'failed']))
24
+ state: TypeRefundAttemptState;
25
+
26
+ @Api.field(z.literal('USD'))
27
+ currency: 'USD';
28
+
29
+ @Api.field(z.number().int().nonnegative())
30
+ amountCents: number;
31
+
32
+ @Api.field(v.required(), v.min(1), v.max(100))
33
+ correlationId: string;
34
+
35
+ @Api.field(v.optional())
36
+ finalizedAt?: Date;
37
+ }
@@ -0,0 +1,47 @@
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 { TypeRefundAttemptState } from './refundAttempt.tsx';
9
+ import type { TypeRefundRequestState } from './refundRequest.tsx';
10
+
11
+ export interface IEntityOptionsRefundAudit extends IDecoratorEntityOptions {}
12
+
13
+ @Entity<IEntityOptionsRefundAudit>('commercePaymentRefundAudit')
14
+ export class EntityRefundAudit extends EntityBase {
15
+ @Api.field(v.tableIdentity())
16
+ refundRequestId: TableIdentity;
17
+
18
+ @Api.field(v.optional(), v.tableIdentity())
19
+ refundAttemptId?: TableIdentity;
20
+
21
+ @Api.field(v.tableIdentity())
22
+ orderId: TableIdentity;
23
+
24
+ @Api.field(v.tableIdentity())
25
+ userId: TableIdentity;
26
+
27
+ @Api.field(z.enum(['requested', 'approved', 'rejected', 'refunded', 'failed']))
28
+ toRefundState: TypeRefundRequestState;
29
+
30
+ @Api.field(v.optional(), z.enum(['created', 'succeeded', 'failed']))
31
+ attemptState?: TypeRefundAttemptState;
32
+
33
+ @Api.field(v.optional(), v.min(1), v.max(100))
34
+ idempotencyKey?: string;
35
+
36
+ @Api.field(v.required(), v.min(1), v.max(100))
37
+ correlationId: string;
38
+
39
+ @Api.field(v.required(), v.min(1), v.max(255))
40
+ reason: string;
41
+
42
+ @Api.field(v.optional(), v.tableIdentity())
43
+ actorId?: TableIdentity;
44
+
45
+ @Api.field(v.required())
46
+ processedAt: Date;
47
+ }
@@ -0,0 +1,43 @@
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
+ export type TypeRefundRequestState = 'requested' | 'approved' | 'rejected' | 'refunded' | 'failed';
9
+
10
+ export interface IEntityOptionsRefundRequest extends IDecoratorEntityOptions {}
11
+
12
+ @Entity<IEntityOptionsRefundRequest>('commercePaymentRefundRequest')
13
+ export class EntityRefundRequest extends EntityBase {
14
+ @Api.field(v.tableIdentity())
15
+ orderId: TableIdentity;
16
+
17
+ @Api.field(v.tableIdentity())
18
+ userId: TableIdentity;
19
+
20
+ @Api.field(z.enum(['requested', 'approved', 'rejected', 'refunded', 'failed']))
21
+ state: TypeRefundRequestState;
22
+
23
+ @Api.field(z.literal('USD'))
24
+ currency: 'USD';
25
+
26
+ @Api.field(z.number().int().nonnegative())
27
+ amountCents: number;
28
+
29
+ @Api.field(v.required(), v.min(1), v.max(100))
30
+ correlationId: string;
31
+
32
+ @Api.field(v.required(), v.min(1), v.max(255))
33
+ reason: string;
34
+
35
+ @Api.field(v.optional(), v.tableIdentity())
36
+ reviewedBy?: TableIdentity;
37
+
38
+ @Api.field(v.optional())
39
+ reviewedAt?: Date;
40
+
41
+ @Api.field(v.optional())
42
+ finalizedAt?: Date;
43
+ }
@@ -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 { EntityRefundAttempt } from '../entity/refundAttempt.tsx';
6
+
7
+ export interface IModelOptionsRefundAttempt extends IDecoratorModelOptions<EntityRefundAttempt> {}
8
+
9
+ @Model<IModelOptionsRefundAttempt>({ entity: EntityRefundAttempt })
10
+ export class ModelRefundAttempt extends BeanModelBase<EntityRefundAttempt> {}
@@ -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 { EntityRefundAudit } from '../entity/refundAudit.tsx';
6
+
7
+ export interface IModelOptionsRefundAudit extends IDecoratorModelOptions<EntityRefundAudit> {}
8
+
9
+ @Model<IModelOptionsRefundAudit>({ entity: EntityRefundAudit })
10
+ export class ModelRefundAudit extends BeanModelBase<EntityRefundAudit> {}
@@ -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 { EntityRefundRequest } from '../entity/refundRequest.tsx';
6
+
7
+ export interface IModelOptionsRefundRequest extends IDecoratorModelOptions<EntityRefundRequest> {}
8
+
9
+ @Model<IModelOptionsRefundRequest>({ entity: EntityRefundRequest })
10
+ export class ModelRefundRequest extends BeanModelBase<EntityRefundRequest> {}
@@ -849,6 +849,10 @@ export * from '../dto/orderSummary.tsx';
849
849
  export * from '../dto/orderView.tsx';
850
850
  export * from '../dto/paymentOutcomeCreate.tsx';
851
851
  export * from '../dto/paymentOutcomeResult.tsx';
852
+ export * from '../dto/refundOutcomeCreate.tsx';
853
+ export * from '../dto/refundRequestCreate.tsx';
854
+ export * from '../dto/refundResult.tsx';
855
+ export * from '../dto/refundReview.tsx';
852
856
  export * from '../dto/shipmentView.tsx';
853
857
  export * from '../dto/stockAdjust.tsx';
854
858
  export * from '../dto/stockAuditCreate.tsx';
@@ -883,6 +887,10 @@ import type { IDtoOptionsOrderSummary } from '../dto/orderSummary.tsx';
883
887
  import type { IDtoOptionsOrderView } from '../dto/orderView.tsx';
884
888
  import type { IDtoOptionsPaymentOutcomeCreate } from '../dto/paymentOutcomeCreate.tsx';
885
889
  import type { IDtoOptionsPaymentOutcomeResult } from '../dto/paymentOutcomeResult.tsx';
890
+ import type { IDtoOptionsRefundOutcomeCreate } from '../dto/refundOutcomeCreate.tsx';
891
+ import type { IDtoOptionsRefundRequestCreate } from '../dto/refundRequestCreate.tsx';
892
+ import type { IDtoOptionsRefundResult } from '../dto/refundResult.tsx';
893
+ import type { IDtoOptionsRefundReview } from '../dto/refundReview.tsx';
886
894
  import type { IDtoOptionsShipmentView } from '../dto/shipmentView.tsx';
887
895
  import type { IDtoOptionsStockAdjust } from '../dto/stockAdjust.tsx';
888
896
  import type { IDtoOptionsStockAuditCreate } from '../dto/stockAuditCreate.tsx';
@@ -921,6 +929,10 @@ declare module 'vona-module-a-web' {
921
929
  'commerce-trade:orderView': IDtoOptionsOrderView;
922
930
  'commerce-trade:paymentOutcomeCreate': IDtoOptionsPaymentOutcomeCreate;
923
931
  'commerce-trade:paymentOutcomeResult': IDtoOptionsPaymentOutcomeResult;
932
+ 'commerce-trade:refundOutcomeCreate': IDtoOptionsRefundOutcomeCreate;
933
+ 'commerce-trade:refundRequestCreate': IDtoOptionsRefundRequestCreate;
934
+ 'commerce-trade:refundResult': IDtoOptionsRefundResult;
935
+ 'commerce-trade:refundReview': IDtoOptionsRefundReview;
924
936
  'commerce-trade:shipmentView': IDtoOptionsShipmentView;
925
937
  'commerce-trade:stockAdjust': IDtoOptionsStockAdjust;
926
938
  'commerce-trade:stockAuditCreate': IDtoOptionsStockAuditCreate;
@@ -964,6 +976,10 @@ import type { DtoOrderSummary } from '../dto/orderSummary.tsx';
964
976
  import type { DtoOrderView } from '../dto/orderView.tsx';
965
977
  import type { DtoPaymentOutcomeCreate } from '../dto/paymentOutcomeCreate.tsx';
966
978
  import type { DtoPaymentOutcomeResult } from '../dto/paymentOutcomeResult.tsx';
979
+ import type { DtoRefundOutcomeCreate } from '../dto/refundOutcomeCreate.tsx';
980
+ import type { DtoRefundRequestCreate } from '../dto/refundRequestCreate.tsx';
981
+ import type { DtoRefundResult } from '../dto/refundResult.tsx';
982
+ import type { DtoRefundReview } from '../dto/refundReview.tsx';
967
983
  import type { DtoShipmentView } from '../dto/shipmentView.tsx';
968
984
  import type { DtoStockAdjust } from '../dto/stockAdjust.tsx';
969
985
  import type { DtoStockAuditCreate } from '../dto/stockAuditCreate.tsx';
@@ -1060,6 +1076,22 @@ declare module 'vona-module-commerce-trade' {
1060
1076
  fields?: TypeEntityOptionsFields<DtoPaymentOutcomeResult, IDtoOptionsPaymentOutcomeResult[TypeSymbolKeyFieldsMore]>;
1061
1077
  }
1062
1078
 
1079
+ export interface IDtoOptionsRefundOutcomeCreate {
1080
+ fields?: TypeEntityOptionsFields<DtoRefundOutcomeCreate, IDtoOptionsRefundOutcomeCreate[TypeSymbolKeyFieldsMore]>;
1081
+ }
1082
+
1083
+ export interface IDtoOptionsRefundRequestCreate {
1084
+ fields?: TypeEntityOptionsFields<DtoRefundRequestCreate, IDtoOptionsRefundRequestCreate[TypeSymbolKeyFieldsMore]>;
1085
+ }
1086
+
1087
+ export interface IDtoOptionsRefundResult {
1088
+ fields?: TypeEntityOptionsFields<DtoRefundResult, IDtoOptionsRefundResult[TypeSymbolKeyFieldsMore]>;
1089
+ }
1090
+
1091
+ export interface IDtoOptionsRefundReview {
1092
+ fields?: TypeEntityOptionsFields<DtoRefundReview, IDtoOptionsRefundReview[TypeSymbolKeyFieldsMore]>;
1093
+ }
1094
+
1063
1095
  export interface IDtoOptionsShipmentView {
1064
1096
  fields?: TypeEntityOptionsFields<DtoShipmentView, IDtoOptionsShipmentView[TypeSymbolKeyFieldsMore]>;
1065
1097
  }
@@ -1267,6 +1299,10 @@ declare module 'vona-module-a-web' {
1267
1299
  export interface IApiPathPostRecord{
1268
1300
  '/commerce/trade/cart/items': undefined;
1269
1301
  '/commerce/trade/checkout': undefined;
1302
+ '/commerce/trade/order/:id/requestRefund': undefined;
1303
+ '/commerce/trade/order/:id/approveRefund': undefined;
1304
+ '/commerce/trade/order/:id/rejectRefund': undefined;
1305
+ '/commerce/trade/order/:id/refundOutcome': undefined;
1270
1306
  '/commerce/trade/order/:id/ship': undefined;
1271
1307
  '/commerce/trade/payment/:attemptId/outcome': undefined;
1272
1308
  '/commerce/trade/stockBalance/adjustStock': undefined;
@@ -16,6 +16,10 @@ import { DtoOrderSelectReq } from '../dto/orderSelectReq.tsx';
16
16
  import { DtoOrderSelectRes } from '../dto/orderSelectRes.tsx';
17
17
  import { DtoOrderShip } from '../dto/orderShip.tsx';
18
18
  import { DtoOrderView } from '../dto/orderView.tsx';
19
+ import { DtoRefundOutcomeCreate } from '../dto/refundOutcomeCreate.tsx';
20
+ import { DtoRefundRequestCreate } from '../dto/refundRequestCreate.tsx';
21
+ import { DtoRefundResult } from '../dto/refundResult.tsx';
22
+ import { DtoRefundReview } from '../dto/refundReview.tsx';
19
23
  import { DtoShipmentView } from '../dto/shipmentView.tsx';
20
24
 
21
25
  export interface IControllerOptionsOrder extends IDecoratorControllerOptions {}
@@ -39,6 +43,45 @@ export class ControllerOrder extends BeanBase {
39
43
  return await this.scope.service.order.viewMine(id);
40
44
  }
41
45
 
46
+ @Web.post(':id/requestRefund')
47
+ @Api.body(DtoRefundResult)
48
+ async requestRefund(
49
+ @Arg.param('id', v.tableIdentity()) id: TableIdentity,
50
+ @Arg.body() command: DtoRefundRequestCreate,
51
+ ): Promise<DtoRefundResult> {
52
+ return await this.scope.service.order.requestRefund(id, command);
53
+ }
54
+
55
+ @Web.post(':id/approveRefund')
56
+ @Api.body(DtoRefundResult)
57
+ @Passport.systemAdmin()
58
+ async approveRefund(
59
+ @Arg.param('id', v.tableIdentity()) id: TableIdentity,
60
+ @Arg.body() command: DtoRefundReview,
61
+ ): Promise<DtoRefundResult> {
62
+ return await this.scope.service.order.approveRefund(id, command);
63
+ }
64
+
65
+ @Web.post(':id/rejectRefund')
66
+ @Api.body(DtoRefundResult)
67
+ @Passport.systemAdmin()
68
+ async rejectRefund(
69
+ @Arg.param('id', v.tableIdentity()) id: TableIdentity,
70
+ @Arg.body() command: DtoRefundReview,
71
+ ): Promise<DtoRefundResult> {
72
+ return await this.scope.service.order.rejectRefund(id, command);
73
+ }
74
+
75
+ @Web.post(':id/refundOutcome')
76
+ @Api.body(DtoRefundResult)
77
+ @Passport.systemAdmin()
78
+ async refundOutcome(
79
+ @Arg.param('id', v.tableIdentity()) id: TableIdentity,
80
+ @Arg.body() command: DtoRefundOutcomeCreate,
81
+ ): Promise<DtoRefundResult> {
82
+ return await this.scope.service.order.applyRefundOutcome(id, command);
83
+ }
84
+
42
85
  @Web.post(':id/ship')
43
86
  @Api.body(DtoShipmentView)
44
87
  @Passport.systemAdmin()
@@ -40,8 +40,29 @@ export class DtoOrderDetail {
40
40
  @Api.field(v.tableIdentity())
41
41
  id: TableIdentity;
42
42
 
43
- @Api.field(z.enum(['awaiting_payment', 'paid', 'shipped', 'cancelled', 'expired']))
44
- state: 'awaiting_payment' | 'paid' | 'shipped' | 'cancelled' | 'expired';
43
+ @Api.field(
44
+ z.enum([
45
+ 'awaiting_payment',
46
+ 'paid',
47
+ 'refund_requested',
48
+ 'refund_approved',
49
+ 'refund_rejected',
50
+ 'shipped',
51
+ 'refunded',
52
+ 'cancelled',
53
+ 'expired',
54
+ ]),
55
+ )
56
+ state:
57
+ | 'awaiting_payment'
58
+ | 'paid'
59
+ | 'refund_requested'
60
+ | 'refund_approved'
61
+ | 'refund_rejected'
62
+ | 'shipped'
63
+ | 'refunded'
64
+ | 'cancelled'
65
+ | 'expired';
45
66
 
46
67
  @Api.field(z.literal('USD'))
47
68
  currency: 'USD';
@@ -30,6 +30,9 @@ export class DtoOrderSelectResItem extends $Dto.get(() => ModelOrder) {
30
30
  ZovaRender.tableActionRow('commerce-trade:actionShip', {
31
31
  permission: { public: true },
32
32
  }),
33
+ ZovaRender.tableActionRow('commerce-trade:actionRefund', {
34
+ permission: { public: true },
35
+ }),
33
36
  ZovaRender.tableActionRow('basic-table:actionView'),
34
37
  ],
35
38
  }),
@@ -12,8 +12,29 @@ export class DtoOrderSummary {
12
12
  @Api.field(v.tableIdentity())
13
13
  id: TableIdentity;
14
14
 
15
- @Api.field(z.enum(['awaiting_payment', 'paid', 'shipped', 'cancelled', 'expired']))
16
- state: 'awaiting_payment' | 'paid' | 'shipped' | 'cancelled' | 'expired';
15
+ @Api.field(
16
+ z.enum([
17
+ 'awaiting_payment',
18
+ 'paid',
19
+ 'refund_requested',
20
+ 'refund_approved',
21
+ 'refund_rejected',
22
+ 'shipped',
23
+ 'refunded',
24
+ 'cancelled',
25
+ 'expired',
26
+ ]),
27
+ )
28
+ state:
29
+ | 'awaiting_payment'
30
+ | 'paid'
31
+ | 'refund_requested'
32
+ | 'refund_approved'
33
+ | 'refund_rejected'
34
+ | 'shipped'
35
+ | 'refunded'
36
+ | 'cancelled'
37
+ | 'expired';
17
38
 
18
39
  @Api.field(z.literal('USD'))
19
40
  currency: 'USD';
@@ -0,0 +1,16 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+
3
+ import { Api, v } from 'vona-module-a-openapiutils';
4
+ import { Dto } from 'vona-module-a-web';
5
+ import { z } from 'zod';
6
+
7
+ export interface IDtoOptionsRefundOutcomeCreate extends IDecoratorDtoOptions {}
8
+
9
+ @Dto<IDtoOptionsRefundOutcomeCreate>()
10
+ export class DtoRefundOutcomeCreate {
11
+ @Api.field(z.enum(['succeeded', 'failed']))
12
+ outcome: 'succeeded' | 'failed';
13
+
14
+ @Api.field(v.required(), v.min(1), v.max(100))
15
+ idempotencyKey: string;
16
+ }
@@ -0,0 +1,15 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+
3
+ import { Api, v } from 'vona-module-a-openapiutils';
4
+ import { Dto } from 'vona-module-a-web';
5
+
6
+ export interface IDtoOptionsRefundRequestCreate extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsRefundRequestCreate>()
9
+ export class DtoRefundRequestCreate {
10
+ @Api.field(v.required(), v.min(1), v.max(255))
11
+ reason: string;
12
+
13
+ @Api.field(v.required(), v.min(1), v.max(100))
14
+ idempotencyKey: string;
15
+ }
@@ -0,0 +1,35 @@
1
+ import type { TableIdentity } from 'table-identity';
2
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
3
+
4
+ import { Api, v } from 'vona-module-a-openapiutils';
5
+ import { Dto } from 'vona-module-a-web';
6
+ import { z } from 'zod';
7
+
8
+ export interface IDtoOptionsRefundResult extends IDecoratorDtoOptions {}
9
+
10
+ @Dto<IDtoOptionsRefundResult>()
11
+ export class DtoRefundResult {
12
+ @Api.field(v.tableIdentity())
13
+ orderId: TableIdentity;
14
+
15
+ @Api.field(v.tableIdentity())
16
+ refundRequestId: TableIdentity;
17
+
18
+ @Api.field(v.optional(), v.tableIdentity())
19
+ refundAttemptId?: TableIdentity;
20
+
21
+ @Api.field(z.enum(['paid', 'refund_requested', 'refund_approved', 'refund_rejected', 'refunded']))
22
+ orderState: 'paid' | 'refund_requested' | 'refund_approved' | 'refund_rejected' | 'refunded';
23
+
24
+ @Api.field(z.enum(['requested', 'approved', 'rejected', 'refunded', 'failed']))
25
+ refundState: 'requested' | 'approved' | 'rejected' | 'refunded' | 'failed';
26
+
27
+ @Api.field(v.optional(), z.enum(['created', 'succeeded', 'failed']))
28
+ refundAttemptState?: 'created' | 'succeeded' | 'failed';
29
+
30
+ @Api.field(z.literal('USD'))
31
+ currency: 'USD';
32
+
33
+ @Api.field(z.number().int().nonnegative())
34
+ amountCents: number;
35
+ }
@@ -0,0 +1,15 @@
1
+ import type { IDecoratorDtoOptions } from 'vona-module-a-web';
2
+
3
+ import { Api, v } from 'vona-module-a-openapiutils';
4
+ import { Dto } from 'vona-module-a-web';
5
+
6
+ export interface IDtoOptionsRefundReview extends IDecoratorDtoOptions {}
7
+
8
+ @Dto<IDtoOptionsRefundReview>()
9
+ export class DtoRefundReview {
10
+ @Api.field(v.required(), v.min(1), v.max(255))
11
+ reason: string;
12
+
13
+ @Api.field(v.required(), v.min(1), v.max(100))
14
+ idempotencyKey: string;
15
+ }
@@ -7,7 +7,17 @@ import { z } from 'zod';
7
7
 
8
8
  import type { TypeOrderState } from './order.tsx';
9
9
 
10
- export type TypeOrderAuditOperation = 'created' | 'paid' | 'cancelled' | 'expired' | 'shipped';
10
+ export type TypeOrderAuditOperation =
11
+ | 'created'
12
+ | 'paid'
13
+ | 'cancelled'
14
+ | 'expired'
15
+ | 'shipped'
16
+ | 'refund_requested'
17
+ | 'refund_approved'
18
+ | 'refund_rejected'
19
+ | 'refund_failed'
20
+ | 'refunded';
11
21
 
12
22
  export interface IEntityOptionsOrderAudit extends IDecoratorEntityOptions {}
13
23
 
@@ -16,20 +26,52 @@ export class EntityOrderAudit extends EntityBase {
16
26
  @Api.field(v.tableIdentity())
17
27
  orderId: TableIdentity;
18
28
 
19
- @Api.field(z.enum(['created', 'paid', 'cancelled', 'expired', 'shipped']))
29
+ @Api.field(
30
+ z.enum([
31
+ 'created',
32
+ 'paid',
33
+ 'cancelled',
34
+ 'expired',
35
+ 'shipped',
36
+ 'refund_requested',
37
+ 'refund_approved',
38
+ 'refund_rejected',
39
+ 'refund_failed',
40
+ 'refunded',
41
+ ]),
42
+ )
20
43
  operation: TypeOrderAuditOperation;
21
44
 
22
- @Api.field(v.optional(), z.enum(['awaiting_payment', 'paid', 'cancelled', 'expired', 'shipped']))
23
- fromState?: Extract<
24
- TypeOrderState,
25
- 'awaiting_payment' | 'paid' | 'cancelled' | 'expired' | 'shipped'
26
- >;
27
-
28
- @Api.field(z.enum(['awaiting_payment', 'paid', 'cancelled', 'expired', 'shipped']))
29
- toState: Extract<
30
- TypeOrderState,
31
- 'awaiting_payment' | 'paid' | 'cancelled' | 'expired' | 'shipped'
32
- >;
45
+ @Api.field(
46
+ v.optional(),
47
+ z.enum([
48
+ 'awaiting_payment',
49
+ 'paid',
50
+ 'refund_requested',
51
+ 'refund_approved',
52
+ 'refund_rejected',
53
+ 'shipped',
54
+ 'refunded',
55
+ 'cancelled',
56
+ 'expired',
57
+ ]),
58
+ )
59
+ fromState?: TypeOrderState;
60
+
61
+ @Api.field(
62
+ z.enum([
63
+ 'awaiting_payment',
64
+ 'paid',
65
+ 'refund_requested',
66
+ 'refund_approved',
67
+ 'refund_rejected',
68
+ 'shipped',
69
+ 'refunded',
70
+ 'cancelled',
71
+ 'expired',
72
+ ]),
73
+ )
74
+ toState: TypeOrderState;
33
75
 
34
76
  @Api.field(v.optional(), v.tableIdentity())
35
77
  actorId?: TableIdentity;