cabloy 5.1.131 → 5.1.133
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cabloy-version +1 -1
- package/.claude/skills/cabloy-worktree-environment/SKILL.md +6 -6
- package/.claude/skills/cabloy-worktree-environment/evals/evals.json +2 -2
- package/.github/workflows/vona-test-pg.yml +1 -1
- package/.github/workflows/vona-test-sqlite3.yml +1 -1
- package/CHANGELOG.md +28 -0
- package/cabloy-docs/backend/dto-guide.md +39 -4
- package/cabloy-docs/backend/dto-infer-generation.md +29 -0
- package/cabloy-docs/backend/openapi-guide.md +16 -0
- package/cabloy-docs/backend/validation-guide.md +45 -0
- package/cabloy-docs/frontend/environment-config-guide.md +8 -15
- package/cabloy-docs/frontend/navigation-guards-guide.md +3 -3
- package/cabloy-docs/frontend/page-route-guide.md +4 -4
- package/cabloy-docs/frontend/ssr-env.md +22 -29
- package/cabloy-docs/frontend/theme-guide.md +4 -4
- package/cabloy-docs/frontend/zova-router-under-the-hood.md +1 -1
- package/cabloy-docs/fullstack/deploy-cloudflare-docker.md +6 -6
- package/cabloy-docs/fullstack/parallel-worktree-environment.md +2 -2
- package/e2e/specs/a-commerce/commerce.spec.ts +479 -17
- package/e2e/specs/cabloy-basic/basic.spec.ts +30 -5
- package/package.json +7 -7
- package/vona/.claude/skills/detect-ssr-leak/SKILL.md +1 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/pnpm-lock.yaml +120 -10
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuCreate.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuSelectResItem.tsx +13 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuUpdate.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/skuView.tsx +13 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/entity/sku.tsx +6 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/test/skuPresentation.test.ts +227 -0
- package/vona/src/suite/a-commerce/modules/commerce-member/src/.metadata/index.ts +46 -36
- package/vona/src/suite/a-commerce/modules/commerce-member/src/dto/addressSelectResItem.tsx +5 -13
- package/vona/src/suite/a-commerce/modules/commerce-member/src/service/address.ts +16 -1
- package/vona/src/suite/a-commerce/modules/commerce-member/test/addressPresentation.test.ts +210 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +13 -2
- package/vona/src/suite/a-commerce/modules/commerce-payment/test/paymentAttempt.test.ts +12 -0
- package/vona/src/suite/a-commerce/modules/commerce-promotion/src/service/coupon.ts +7 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +45 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +23 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +23 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/order.ts +31 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineBase.tsx +56 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineResItem.tsx +17 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderAdminLineView.tsx +13 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderSelectResItem.tsx +26 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/orderView.tsx +197 -3
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryAction.tsx +19 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/refundRecoveryView.tsx +70 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditSelectResItem.tsx +7 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditView.tsx +21 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceSelectResItem.tsx +7 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceView.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/entity/order.tsx +12 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +15 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +215 -3
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockAudit.ts +25 -2
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/stockBalance.ts +14 -3
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/checkoutReservation.test.ts +4 -4
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderPresentation.test.ts +358 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/orderSnapshot.test.ts +8 -8
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +5 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/refundLifecycle.test.ts +50 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/stockPresentation.test.ts +324 -0
- package/vona/src/suite/a-home/modules/home-base/package.json +3 -2
- package/vona/src/suite/a-home/modules/home-base/src/.metadata/index.ts +93 -16
- package/vona/src/suite/a-home/modules/home-base/src/controller/siteCatalog.ts +21 -0
- package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectRes.ts +11 -0
- package/vona/src/suite/a-home/modules/home-base/src/dto/siteCatalogSelectResItem.ts +15 -0
- package/vona/src/suite/a-home/modules/home-base/src/service/siteCatalog.ts +29 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/bean/ssrSite.admin.ts +3 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteadmin/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/bean/ssrSite.web.ts +3 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/en-us.ts +1 -0
- package/vona/src/suite/cabloy-basic/modules/basic-siteweb/src/config/locale/zh-cn.ts +1 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/cli/ssrSite/boilerplate/{{sceneName}}.{{beanName}}.ts_ +1 -0
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/package.json +1 -1
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/env.ts +1 -3
- package/vona/src/suite-vendor/a-cabloy/modules/a-ssr/src/types/ssrSite.ts +2 -1
- package/vona/src/suite-vendor/a-cabloy/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/.metadata/index.ts +67 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payProvider.ts +1 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payScene.ts +5 -4
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.index.ts +8 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.version.ts +22 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/schedule.providerOperationDispatch.ts +1 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/paymentSession.tsx +6 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperation.tsx +3 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/providerOperationRecoveryAudit.tsx +53 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/entity/refundOperation.tsx +6 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/model/providerOperationRecoveryAudit.ts +12 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +6 -2
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +236 -30
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/refundOperation.ts +8 -5
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/webhook.ts +34 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts +4 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +6 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/bean/payProvider.mock.ts +15 -7
- package/vona/src/suite-vendor/a-pay/modules/pay-mock/src/service/payMock.ts +9 -5
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/bean/payProvider.paypal.ts +289 -86
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/paypalGateway.ts +9 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/package.json +5 -5
- package/vona/src/suite-vendor/a-vona/modules/a-openapi/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapi/src/types/rest.ts +1 -0
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-openapiutils/src/lib/utils.ts +12 -0
- package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoCreate.ts +5 -1
- package/vona/src/suite-vendor/a-vona/modules/a-orm/src/lib/dto/dtoUpdate.ts +5 -1
- package/vona/src/suite-vendor/a-vona/modules/a-validation/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-validation/src/bean/bean.validator.ts +60 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/modules/a-web/src/lib/decorator/bean.ts +7 -4
- package/vona/src/suite-vendor/a-vona/modules/a-web/src/types/dto.ts +2 -1
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/env/.env +3 -5
- package/zova/env/.env.cabloyBasicAdmin +1 -4
- package/zova/env/.env.cabloyBasicWeb +1 -5
- package/zova/env/.env.cabloyCommerce +1 -5
- package/zova/env/.env.cabloyCommerceAdmin +1 -4
- package/zova/env/.env.ssr.admin +1 -4
- package/zova/env/.env.ssr.web +1 -5
- package/zova/package.original.json +1 -1
- package/zova/packages-utils/zova-jsx/package.json +2 -2
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +2 -1
- package/zova/packages-zova/zova-core/src/core/component/locale.ts +10 -4
- package/zova/packages-zova/zova-core/src/core/sys/config.ts +14 -6
- package/zova/packages-zova/zova-core/src/types/utils/env.ts +4 -2
- package/zova/pnpm-lock.yaml +24 -21
- package/zova/src/front/config/config/config.ts +22 -7
- package/zova/src/suite/a-commerce/modules/commerce-catalog/src/routes.ts +2 -2
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +16 -8
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +150 -216
- package/zova/src/suite/a-commerce/modules/commerce-member/src/model/addressMine.ts +1 -2
- package/zova/src/suite/a-commerce/modules/commerce-member/src/page/address/controller.tsx +5 -8
- package/zova/src/suite/a-commerce/modules/commerce-member/src/routes.ts +1 -1
- package/zova/src/suite/a-commerce/modules/commerce-promotion/src/model/coupon.ts +1 -2
- package/zova/src/suite/a-commerce/modules/commerce-siteadmin/src/routes.ts +3 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +3 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeOrder.ts +72 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/schemas.ts +8 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/openapi/types.ts +226 -16
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeOrder.ts +15 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/component/tableCellActionRefund/controller.tsx +155 -36
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/en-us.ts +7 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/config/locale/zh-cn.ts +7 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/cart.ts +3 -4
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/order.ts +42 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/orderMine.ts +2 -4
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/cart/controller.tsx +5 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +14 -10
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/order/controller.tsx +5 -8
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/orders/controller.tsx +5 -8
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +151 -24
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/routes.ts +5 -5
- package/zova/src/suite/a-demo/modules/demo-basic/src/routes.ts +26 -7
- package/zova/src/suite/a-demo/modules/demo-todo/src/routes.ts +2 -2
- package/zova/src/suite/a-devui/modules/devui-adapter/src/bean/meta.themeHandler.ts +1 -1
- package/zova/src/suite/a-home/modules/home-base/package.json +1 -0
- package/zova/src/suite/a-home/modules/home-base/src/routes.ts +5 -0
- package/zova/src/suite/a-home/modules/home-base/src/service/routerGuards.ts +1 -1
- package/zova/src/suite/a-home/modules/home-base/src/service/ssrLayout.ts +18 -14
- package/zova/src/suite/a-home/modules/home-indexadmin/src/routes.ts +1 -1
- package/zova/src/suite/a-home/modules/home-indexweb/src/routes.ts +1 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/component/layoutAdmin/controller.tsx +12 -4
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/config/config.ts +8 -0
- package/zova/src/suite/a-home/modules/home-layoutadmin/src/model/layout.ts +5 -8
- package/zova/src/suite/a-home/modules/home-layoutempty/src/.metadata/index.ts +10 -3
- package/zova/src/suite/a-home/modules/home-layoutempty/src/component/layoutEmpty/controller.tsx +9 -3
- package/zova/src/suite/a-home/modules/home-layoutempty/src/config/config.ts +12 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/controller.tsx +13 -8
- package/zova/src/suite/a-home/modules/home-layoutweb/src/component/layoutWeb/render.header.tsx +1 -1
- package/zova/src/suite/a-home/modules/home-layoutweb/src/config/config.ts +4 -0
- package/zova/src/suite/a-home/modules/home-layoutweb/src/model/layout.ts +5 -8
- package/zova/src/suite/a-home/modules/home-login/src/routes.ts +1 -0
- package/zova/src/suite/a-home/modules/home-passport/src/model/passport.ts +2 -3
- package/zova/src/suite/cabloy-basic/modules/basic-metrics/src/routes.ts +3 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/package.json +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/model/resource.ts +1 -1
- package/zova/src/suite-vendor/a-cabloy/modules/rest-resource/src/routes.ts +3 -0
- package/zova/src/suite-vendor/a-cabloy/package.json +2 -2
- package/zova/src/suite-vendor/a-pay/modules/a-pay/package.json +1 -1
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +2 -2
- package/zova/src/suite-vendor/a-pay/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-interceptor/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-interceptor/src/bean/interceptor.jwt.ts +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/model/sdk.ts +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-openapi/src/types/rest.ts +1 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/config/config.ts +1 -17
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/bodyReadyObserver.ts +27 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/index.ts +2 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssr.ts +33 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrMetaStore.ts +3 -35
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/lib/ssrProfile.ts +38 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/monkey.ts +10 -0
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/config.ts +3 -10
- package/zova/src/suite-vendor/a-zova/modules/a-ssr/src/types/ssr.ts +17 -8
- package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-ssrserver/src/service/ssrHandler.ts +33 -18
- package/zova/src/suite-vendor/a-zova/modules/a-style/package.json +1 -1
- package/zova/src/suite-vendor/a-zova/modules/a-style/src/bean/bean.theme.ts +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/package.json +7 -7
|
@@ -0,0 +1,70 @@
|
|
|
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 IDtoOptionsRefundRecoveryView extends IDecoratorDtoOptions {}
|
|
9
|
+
|
|
10
|
+
@Dto<IDtoOptionsRefundRecoveryView>()
|
|
11
|
+
export class DtoRefundRecoveryView {
|
|
12
|
+
@Api.field(v.tableIdentity())
|
|
13
|
+
orderId: TableIdentity;
|
|
14
|
+
|
|
15
|
+
@Api.field(v.tableIdentity())
|
|
16
|
+
refundRequestId: TableIdentity;
|
|
17
|
+
|
|
18
|
+
@Api.field(v.tableIdentity())
|
|
19
|
+
refundAttemptId: TableIdentity;
|
|
20
|
+
|
|
21
|
+
@Api.field(v.tableIdentity())
|
|
22
|
+
refundOperationId: TableIdentity;
|
|
23
|
+
|
|
24
|
+
@Api.field(v.tableIdentity())
|
|
25
|
+
providerOperationId: TableIdentity;
|
|
26
|
+
|
|
27
|
+
@Api.field(v.required(), v.min(1), v.max(100))
|
|
28
|
+
providerName: string;
|
|
29
|
+
|
|
30
|
+
@Api.field(z.enum(['sandbox', 'live']))
|
|
31
|
+
environment: 'sandbox' | 'live';
|
|
32
|
+
|
|
33
|
+
@Api.field(z.enum(['created', 'submitting', 'pending', 'succeeded', 'failed', 'cancelled']))
|
|
34
|
+
refundOperationState: 'created' | 'submitting' | 'pending' | 'succeeded' | 'failed' | 'cancelled';
|
|
35
|
+
|
|
36
|
+
@Api.field(
|
|
37
|
+
z.enum(['created', 'claimed', 'submitted', 'succeeded', 'failed', 'reconciliation_required']),
|
|
38
|
+
)
|
|
39
|
+
providerOperationState:
|
|
40
|
+
| 'created'
|
|
41
|
+
| 'claimed'
|
|
42
|
+
| 'submitted'
|
|
43
|
+
| 'succeeded'
|
|
44
|
+
| 'failed'
|
|
45
|
+
| 'reconciliation_required';
|
|
46
|
+
|
|
47
|
+
@Api.field(z.number().int().nonnegative())
|
|
48
|
+
attemptCount: number;
|
|
49
|
+
|
|
50
|
+
@Api.field(v.optional(), v.max(255))
|
|
51
|
+
providerRefundId?: string;
|
|
52
|
+
|
|
53
|
+
@Api.field(v.optional(), v.max(100))
|
|
54
|
+
errorCode?: string;
|
|
55
|
+
|
|
56
|
+
@Api.field(v.optional(), v.max(255))
|
|
57
|
+
errorSummary?: string;
|
|
58
|
+
|
|
59
|
+
@Api.field(v.optional())
|
|
60
|
+
submittedAt?: Date;
|
|
61
|
+
|
|
62
|
+
@Api.field(v.optional())
|
|
63
|
+
finalizedAt?: Date;
|
|
64
|
+
|
|
65
|
+
@Api.field(z.enum(['none', 'reconcile_only', 'query_only', 'retry_same_key']))
|
|
66
|
+
recoveryDisposition: 'none' | 'reconcile_only' | 'query_only' | 'retry_same_key';
|
|
67
|
+
|
|
68
|
+
@Api.field(v.required())
|
|
69
|
+
recoveryMessage: string;
|
|
70
|
+
}
|
package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockAuditSelectResItem.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { Dto } from 'vona-module-a-web';
|
|
|
6
6
|
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
7
7
|
|
|
8
8
|
import { $locale } from '../.metadata/locales.ts';
|
|
9
|
+
import { EntityStockAudit } from '../entity/stockAudit.tsx';
|
|
9
10
|
import { ModelStockAudit } from '../model/stockAudit.ts';
|
|
10
11
|
|
|
11
12
|
export interface IDtoOptionsStockAuditSelectResItem extends IDecoratorDtoOptions {}
|
|
@@ -43,7 +44,12 @@ export interface IDtoOptionsStockAuditSelectResItem extends IDecoratorDtoOptions
|
|
|
43
44
|
}),
|
|
44
45
|
],
|
|
45
46
|
})
|
|
46
|
-
export class DtoStockAuditSelectResItem extends $Dto.get(() => ModelStockAudit
|
|
47
|
+
export class DtoStockAuditSelectResItem extends $Dto.get(() => ModelStockAudit, {
|
|
48
|
+
columns: ['id', 'skuId', 'operation', 'delta', 'createdAt'],
|
|
49
|
+
}) {
|
|
50
|
+
@Api.field(ZovaRender.order(1, 'core'), ZovaRender.cell('basic-table:actionView'))
|
|
51
|
+
declare id: EntityStockAudit['id'];
|
|
52
|
+
|
|
47
53
|
@Api.field(
|
|
48
54
|
v.title($locale('Operations')),
|
|
49
55
|
ZovaRender.order(1, 'max'),
|
|
@@ -22,4 +22,24 @@ export interface IDtoOptionsStockAuditView extends IDecoratorDtoOptions {}
|
|
|
22
22
|
}),
|
|
23
23
|
],
|
|
24
24
|
})
|
|
25
|
-
export class DtoStockAuditView extends $Dto.get(() => ModelStockAudit
|
|
25
|
+
export class DtoStockAuditView extends $Dto.get(() => ModelStockAudit, {
|
|
26
|
+
columns: [
|
|
27
|
+
'id',
|
|
28
|
+
'stockBalanceId',
|
|
29
|
+
'skuId',
|
|
30
|
+
'stockReservationId',
|
|
31
|
+
'actorId',
|
|
32
|
+
'operation',
|
|
33
|
+
'delta',
|
|
34
|
+
'reason',
|
|
35
|
+
'correlationId',
|
|
36
|
+
'priorOnHand',
|
|
37
|
+
'priorReserved',
|
|
38
|
+
'priorAvailable',
|
|
39
|
+
'onHand',
|
|
40
|
+
'reserved',
|
|
41
|
+
'available',
|
|
42
|
+
'createdAt',
|
|
43
|
+
'updatedAt',
|
|
44
|
+
],
|
|
45
|
+
}) {}
|
package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/stockBalanceSelectResItem.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { Dto } from 'vona-module-a-web';
|
|
|
6
6
|
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
7
7
|
|
|
8
8
|
import { $locale } from '../.metadata/locales.ts';
|
|
9
|
+
import { EntityStockBalance } from '../entity/stockBalance.tsx';
|
|
9
10
|
import { ModelStockBalance } from '../model/stockBalance.ts';
|
|
10
11
|
|
|
11
12
|
export interface IDtoOptionsStockBalanceSelectResItem extends IDecoratorDtoOptions {}
|
|
@@ -43,7 +44,12 @@ export interface IDtoOptionsStockBalanceSelectResItem extends IDecoratorDtoOptio
|
|
|
43
44
|
}),
|
|
44
45
|
],
|
|
45
46
|
})
|
|
46
|
-
export class DtoStockBalanceSelectResItem extends $Dto.get(() => ModelStockBalance
|
|
47
|
+
export class DtoStockBalanceSelectResItem extends $Dto.get(() => ModelStockBalance, {
|
|
48
|
+
columns: ['id', 'skuId', 'onHand', 'reserved', 'available'],
|
|
49
|
+
}) {
|
|
50
|
+
@Api.field(ZovaRender.order(1, 'core'), ZovaRender.cell('basic-table:actionView'))
|
|
51
|
+
declare id: EntityStockBalance['id'];
|
|
52
|
+
|
|
47
53
|
@Api.field(
|
|
48
54
|
v.title($locale('Operations')),
|
|
49
55
|
ZovaRender.order(1, 'max'),
|
|
@@ -22,4 +22,6 @@ export interface IDtoOptionsStockBalanceView extends IDecoratorDtoOptions {}
|
|
|
22
22
|
}),
|
|
23
23
|
],
|
|
24
24
|
})
|
|
25
|
-
export class DtoStockBalanceView extends $Dto.get(() => ModelStockBalance
|
|
25
|
+
export class DtoStockBalanceView extends $Dto.get(() => ModelStockBalance, {
|
|
26
|
+
columns: ['id', 'skuId', 'onHand', 'reserved', 'available', 'createdAt', 'updatedAt'],
|
|
27
|
+
}) {}
|
|
@@ -10,6 +10,18 @@ import { $locale } from '../.metadata/locales.ts';
|
|
|
10
10
|
import { DtoOrderAddressSnapshot } from '../dto/orderAddressSnapshot.tsx';
|
|
11
11
|
import { DtoOrderCouponSnapshot } from '../dto/orderCouponSnapshot.tsx';
|
|
12
12
|
|
|
13
|
+
export const orderStateItems = [
|
|
14
|
+
{ value: 'awaiting_payment', title: $locale('OrderStateAwaitingPayment') },
|
|
15
|
+
{ value: 'paid', title: $locale('OrderStatePaid') },
|
|
16
|
+
{ value: 'refund_requested', title: $locale('OrderStateRefundRequested') },
|
|
17
|
+
{ value: 'refund_approved', title: $locale('OrderStateRefundApproved') },
|
|
18
|
+
{ value: 'refund_rejected', title: $locale('OrderStateRefundRejected') },
|
|
19
|
+
{ value: 'shipped', title: $locale('OrderStateShipped') },
|
|
20
|
+
{ value: 'refunded', title: $locale('OrderStateRefunded') },
|
|
21
|
+
{ value: 'cancelled', title: $locale('OrderStateCancelled') },
|
|
22
|
+
{ value: 'expired', title: $locale('OrderStateExpired') },
|
|
23
|
+
];
|
|
24
|
+
|
|
13
25
|
export type TypeOrderState =
|
|
14
26
|
| 'awaiting_payment'
|
|
15
27
|
| 'paid'
|
|
@@ -9,8 +9,21 @@ export interface IModelOptionsOrder extends IDecoratorModelOptions<EntityOrder>
|
|
|
9
9
|
@Model<IModelOptionsOrder>({
|
|
10
10
|
entity: EntityOrder,
|
|
11
11
|
relations: {
|
|
12
|
-
lines: $relation.hasMany('commerce-trade:orderLine', 'orderId'
|
|
13
|
-
|
|
12
|
+
lines: $relation.hasMany('commerce-trade:orderLine', 'orderId', {
|
|
13
|
+
columns: [
|
|
14
|
+
'id',
|
|
15
|
+
'skuCodeSnapshot',
|
|
16
|
+
'titleSnapshot',
|
|
17
|
+
'skuAttributesSnapshot',
|
|
18
|
+
'unitPriceCents',
|
|
19
|
+
'quantity',
|
|
20
|
+
'eligibleSubtotalCents',
|
|
21
|
+
'lineTotalCents',
|
|
22
|
+
],
|
|
23
|
+
}),
|
|
24
|
+
shipment: $relation.hasOne('commerce-trade:shipment', 'orderId', {
|
|
25
|
+
columns: ['id', 'carrier', 'trackingNumber', 'shippedAt'],
|
|
26
|
+
}),
|
|
14
27
|
},
|
|
15
28
|
})
|
|
16
29
|
export class ModelOrder extends BeanModelBase<EntityOrder> {}
|
|
@@ -15,6 +15,7 @@ import { Core } from 'vona-module-a-core';
|
|
|
15
15
|
import type { DtoCheckoutCreate } from '../dto/checkoutCreate.tsx';
|
|
16
16
|
import type { DtoCheckoutResult } from '../dto/checkoutResult.tsx';
|
|
17
17
|
import type { DtoOrderAddressSnapshot } from '../dto/orderAddressSnapshot.tsx';
|
|
18
|
+
import type { DtoOrderAdminLineResItem } from '../dto/orderAdminLineResItem.tsx';
|
|
18
19
|
import type { DtoOrderCouponSnapshot } from '../dto/orderCouponSnapshot.tsx';
|
|
19
20
|
import type { DtoOrderDetail } from '../dto/orderDetail.tsx';
|
|
20
21
|
import type { DtoOrderLineSkuAttributeSnapshot } from '../dto/orderLineSkuAttributeSnapshot.tsx';
|
|
@@ -25,6 +26,8 @@ import type { DtoOrderView } from '../dto/orderView.tsx';
|
|
|
25
26
|
import type { DtoPaymentOutcomeCreate } from '../dto/paymentOutcomeCreate.tsx';
|
|
26
27
|
import type { DtoPaymentOutcomeResult } from '../dto/paymentOutcomeResult.tsx';
|
|
27
28
|
import type { DtoRefundOutcomeCreate } from '../dto/refundOutcomeCreate.tsx';
|
|
29
|
+
import type { DtoRefundRecoveryAction } from '../dto/refundRecoveryAction.tsx';
|
|
30
|
+
import type { DtoRefundRecoveryView } from '../dto/refundRecoveryView.tsx';
|
|
28
31
|
import type { DtoRefundRequestCreate } from '../dto/refundRequestCreate.tsx';
|
|
29
32
|
import type { DtoRefundResult } from '../dto/refundResult.tsx';
|
|
30
33
|
import type { DtoRefundReview } from '../dto/refundReview.tsx';
|
|
@@ -55,7 +58,13 @@ const serializationRetryOptions = {
|
|
|
55
58
|
minTimeout: 0,
|
|
56
59
|
maxTimeout: 0,
|
|
57
60
|
randomize: false,
|
|
58
|
-
errorCodes: [
|
|
61
|
+
errorCodes: [
|
|
62
|
+
'40001',
|
|
63
|
+
'ER_LOCK_DEADLOCK',
|
|
64
|
+
'ER_LOCK_WAIT_TIMEOUT',
|
|
65
|
+
'SQLITE_BUSY',
|
|
66
|
+
'SQLITE_BUSY_SNAPSHOT',
|
|
67
|
+
],
|
|
59
68
|
};
|
|
60
69
|
|
|
61
70
|
const checkoutSerializationRetryOptions = {
|
|
@@ -726,6 +735,43 @@ export class ServiceOrder extends BeanBase {
|
|
|
726
735
|
return await this._reviewRefund(orderId, command, decision, onStage);
|
|
727
736
|
}
|
|
728
737
|
|
|
738
|
+
@Core.transaction({ isolationLevel: 'SERIALIZABLE' })
|
|
739
|
+
@Core.retryable(serializationRetryOptions)
|
|
740
|
+
async refundRecovery(orderId: TableIdentity): Promise<DtoRefundRecoveryView> {
|
|
741
|
+
const linked = await this.refundRecoveryLinkage(orderId);
|
|
742
|
+
return this._refundRecoveryView(linked);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
@Core.transaction({ isolationLevel: 'SERIALIZABLE' })
|
|
746
|
+
@Core.retryable(serializationRetryOptions)
|
|
747
|
+
async reconcileRefund(
|
|
748
|
+
orderId: TableIdentity,
|
|
749
|
+
command: DtoRefundRecoveryAction,
|
|
750
|
+
): Promise<DtoRefundRecoveryView> {
|
|
751
|
+
const linked = await this.refundRecoveryLinkage(orderId);
|
|
752
|
+
await this.$scope.pay.service.providerOperation.reconcileRefund(linked.providerOperation.id, {
|
|
753
|
+
...command,
|
|
754
|
+
actorId: this.bean.passport.currentUser!.id,
|
|
755
|
+
});
|
|
756
|
+
return await this.refundRecovery(orderId);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
@Core.transaction({ isolationLevel: 'SERIALIZABLE' })
|
|
760
|
+
@Core.retryable(serializationRetryOptions)
|
|
761
|
+
async retryRefund(
|
|
762
|
+
orderId: TableIdentity,
|
|
763
|
+
command: DtoRefundRecoveryAction,
|
|
764
|
+
): Promise<DtoRefundRecoveryView> {
|
|
765
|
+
const linked = await this.refundRecoveryLinkage(orderId);
|
|
766
|
+
await this.$scope.pay.service.providerOperation.retryRefund(linked.providerOperation.id, {
|
|
767
|
+
...command,
|
|
768
|
+
actorId: this.bean.passport.currentUser!.id,
|
|
769
|
+
});
|
|
770
|
+
return await this.refundRecovery(orderId);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
@Core.transaction({ isolationLevel: 'SERIALIZABLE' })
|
|
774
|
+
@Core.retryable(serializationRetryOptions)
|
|
729
775
|
async executeRefund(orderId: TableIdentity): Promise<DtoRefundResult> {
|
|
730
776
|
const prepared = await this._prepareRefundExecution(orderId);
|
|
731
777
|
await this.$scope.commercePayment.service.commercePayScene.createRefundOperation(prepared.id);
|
|
@@ -743,6 +789,140 @@ export class ServiceOrder extends BeanBase {
|
|
|
743
789
|
|
|
744
790
|
@Core.transaction({ isolationLevel: 'SERIALIZABLE' })
|
|
745
791
|
@Core.retryable(serializationRetryOptions)
|
|
792
|
+
async refundRecoveryLinkage(orderId: TableIdentity) {
|
|
793
|
+
const order = await this.scope.model.order.getByIdForUpdate(orderId);
|
|
794
|
+
if (!order) this.app.throw(404, 'order not found');
|
|
795
|
+
const refundRequest = await this.$scope.commercePayment.model.refundRequest.getForUpdate({
|
|
796
|
+
orderId: order.id,
|
|
797
|
+
state: 'approved',
|
|
798
|
+
});
|
|
799
|
+
if (!refundRequest) this.app.throw(404, 'approved refund request not found');
|
|
800
|
+
const refundAttempt = await this.$scope.commercePayment.model.refundAttempt.getForUpdate({
|
|
801
|
+
refundRequestId: refundRequest.id,
|
|
802
|
+
});
|
|
803
|
+
if (!refundAttempt?.refundOperationId) this.app.throw(404, 'refund recovery is not available');
|
|
804
|
+
const paymentAttempt = await this.$scope.commercePayment.model.paymentAttempt.getForUpdate({
|
|
805
|
+
orderId: order.id,
|
|
806
|
+
});
|
|
807
|
+
if (!paymentAttempt?.paymentSessionId)
|
|
808
|
+
this.app.throw(404, 'commerce payment session not found');
|
|
809
|
+
const refundOperation = await this.$scope.pay.model.refundOperation.getByIdForUpdate(
|
|
810
|
+
refundAttempt.refundOperationId,
|
|
811
|
+
);
|
|
812
|
+
if (!refundOperation) this.app.throw(404, 'refund operation not found');
|
|
813
|
+
const paymentSession = await this.$scope.pay.model.paymentSession.getByIdForUpdate(
|
|
814
|
+
paymentAttempt.paymentSessionId,
|
|
815
|
+
);
|
|
816
|
+
if (!paymentSession) this.app.throw(404, 'payment session not found');
|
|
817
|
+
const providerOperation = await this.$scope.pay.model.providerOperation.getForUpdate({
|
|
818
|
+
refundOperationId: refundOperation.id,
|
|
819
|
+
kind: 'refund',
|
|
820
|
+
});
|
|
821
|
+
if (!providerOperation) this.app.throw(404, 'refund provider operation not found');
|
|
822
|
+
const unresolvedReconciliations =
|
|
823
|
+
await this.$scope.pay.model.providerOperationRecoveryAudit.select({
|
|
824
|
+
where: {
|
|
825
|
+
providerOperationId: providerOperation.id,
|
|
826
|
+
action: 'reconcile',
|
|
827
|
+
resolution: 'unresolved',
|
|
828
|
+
},
|
|
829
|
+
limit: 1,
|
|
830
|
+
});
|
|
831
|
+
if (
|
|
832
|
+
order.state !== 'refund_approved' ||
|
|
833
|
+
refundRequest.state !== 'approved' ||
|
|
834
|
+
refundAttempt.state !== 'created' ||
|
|
835
|
+
String(refundAttempt.orderId) !== String(order.id) ||
|
|
836
|
+
String(refundAttempt.refundRequestId) !== String(refundRequest.id) ||
|
|
837
|
+
String(refundOperation.paymentSessionId) !== String(paymentSession.id) ||
|
|
838
|
+
String(providerOperation.paymentSessionId) !== String(paymentSession.id) ||
|
|
839
|
+
refundOperation.businessReference !== String(refundAttempt.id) ||
|
|
840
|
+
refundAttempt.amountCents !== refundRequest.amountCents ||
|
|
841
|
+
refundAttempt.currency !== refundRequest.currency ||
|
|
842
|
+
refundOperation.amountMinor !== refundAttempt.amountCents ||
|
|
843
|
+
refundOperation.currency !== refundAttempt.currency ||
|
|
844
|
+
paymentSession.currency !== refundOperation.currency ||
|
|
845
|
+
!paymentSession.providerCaptureId
|
|
846
|
+
) {
|
|
847
|
+
this.app.throw(409, 'refund recovery linkage conflicts with immutable payment facts');
|
|
848
|
+
}
|
|
849
|
+
return {
|
|
850
|
+
order,
|
|
851
|
+
refundRequest,
|
|
852
|
+
refundAttempt,
|
|
853
|
+
paymentAttempt,
|
|
854
|
+
paymentSession,
|
|
855
|
+
refundOperation,
|
|
856
|
+
providerOperation,
|
|
857
|
+
hasUnresolvedReconciliation: unresolvedReconciliations.length > 0,
|
|
858
|
+
};
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
private _refundRecoveryView(
|
|
862
|
+
linked: Awaited<ReturnType<typeof this.refundRecoveryLinkage>>,
|
|
863
|
+
): DtoRefundRecoveryView {
|
|
864
|
+
const {
|
|
865
|
+
order,
|
|
866
|
+
refundRequest,
|
|
867
|
+
refundAttempt,
|
|
868
|
+
paymentSession,
|
|
869
|
+
refundOperation,
|
|
870
|
+
providerOperation,
|
|
871
|
+
hasUnresolvedReconciliation,
|
|
872
|
+
} = linked;
|
|
873
|
+
const canQuery = Boolean(
|
|
874
|
+
refundOperation.providerRefundId && providerOperation.state !== 'succeeded',
|
|
875
|
+
);
|
|
876
|
+
const canRetry =
|
|
877
|
+
!refundOperation.providerRefundId &&
|
|
878
|
+
providerOperation.state === 'reconciliation_required' &&
|
|
879
|
+
providerOperation.errorCode === 'refund_submission_outcome_unknown' &&
|
|
880
|
+
Boolean(providerOperation.submittedAt) &&
|
|
881
|
+
!providerOperation.recoveryRetryGrantedAt &&
|
|
882
|
+
hasUnresolvedReconciliation &&
|
|
883
|
+
providerOperation.submittedAt!.getTime() + 45 * 24 * 60 * 60 * 1_000 >= Date.now();
|
|
884
|
+
const canReconcile =
|
|
885
|
+
!refundOperation.providerRefundId &&
|
|
886
|
+
providerOperation.state === 'reconciliation_required' &&
|
|
887
|
+
providerOperation.errorCode === 'refund_submission_outcome_unknown' &&
|
|
888
|
+
Boolean(providerOperation.submittedAt) &&
|
|
889
|
+
!hasUnresolvedReconciliation;
|
|
890
|
+
const recoveryDisposition = canQuery
|
|
891
|
+
? 'query_only'
|
|
892
|
+
: canRetry
|
|
893
|
+
? 'retry_same_key'
|
|
894
|
+
: canReconcile
|
|
895
|
+
? 'reconcile_only'
|
|
896
|
+
: 'none';
|
|
897
|
+
const recoveryMessage =
|
|
898
|
+
recoveryDisposition === 'query_only'
|
|
899
|
+
? 'A verified provider refund identifier is available. Reconcile without resubmitting.'
|
|
900
|
+
: recoveryDisposition === 'reconcile_only'
|
|
901
|
+
? 'Provider refund outcome is unknown. Record reconciliation before considering a retry.'
|
|
902
|
+
: recoveryDisposition === 'retry_same_key'
|
|
903
|
+
? 'Reconciliation was unresolved. A single acknowledged retry may reuse the original provider request.'
|
|
904
|
+
: 'No provider refund submission is available. Do not create or manually declare a replacement refund.';
|
|
905
|
+
return {
|
|
906
|
+
orderId: order.id,
|
|
907
|
+
refundRequestId: refundRequest.id,
|
|
908
|
+
refundAttemptId: refundAttempt.id,
|
|
909
|
+
refundOperationId: refundOperation.id,
|
|
910
|
+
providerOperationId: providerOperation.id,
|
|
911
|
+
providerName: paymentSession.providerName,
|
|
912
|
+
environment: paymentSession.environment,
|
|
913
|
+
refundOperationState: refundOperation.state,
|
|
914
|
+
providerOperationState: providerOperation.state,
|
|
915
|
+
attemptCount: providerOperation.attemptCount,
|
|
916
|
+
providerRefundId: refundOperation.providerRefundId,
|
|
917
|
+
errorCode: providerOperation.errorCode,
|
|
918
|
+
errorSummary: providerOperation.errorSummary,
|
|
919
|
+
submittedAt: providerOperation.submittedAt,
|
|
920
|
+
finalizedAt: refundOperation.finalizedAt ?? providerOperation.finalizedAt,
|
|
921
|
+
recoveryDisposition,
|
|
922
|
+
recoveryMessage,
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
|
|
746
926
|
private async _prepareRefundExecution(orderId: TableIdentity) {
|
|
747
927
|
const order = await this.scope.model.order.getByIdForUpdate(orderId);
|
|
748
928
|
if (!order) this.app.throw(404, 'order not found');
|
|
@@ -758,6 +938,9 @@ export class ServiceOrder extends BeanBase {
|
|
|
758
938
|
if (order.state !== 'refund_approved' || attempt.state !== 'created') {
|
|
759
939
|
this.app.throw(409, 'refund is not available for execution');
|
|
760
940
|
}
|
|
941
|
+
if (attempt.refundOperationId) {
|
|
942
|
+
this.app.throw(409, 'refund submission requires recovery inspection');
|
|
943
|
+
}
|
|
761
944
|
return attempt;
|
|
762
945
|
}
|
|
763
946
|
|
|
@@ -939,14 +1122,43 @@ export class ServiceOrder extends BeanBase {
|
|
|
939
1122
|
}
|
|
940
1123
|
|
|
941
1124
|
async select(params?: IQueryParams<ModelOrder>): Promise<DtoOrderSelectRes> {
|
|
942
|
-
|
|
1125
|
+
const result = await this.scope.model.order.selectAndCount({
|
|
943
1126
|
...params,
|
|
1127
|
+
columns: ['id', 'state', 'payableTotalCents', 'reservationExpiresAt', 'createdAt'],
|
|
944
1128
|
orders: params?.orders ?? [['id', 'desc']],
|
|
945
1129
|
});
|
|
1130
|
+
return result as DtoOrderSelectRes;
|
|
946
1131
|
}
|
|
947
1132
|
|
|
948
1133
|
async view(id: TableIdentity): Promise<DtoOrderView | undefined> {
|
|
949
|
-
|
|
1134
|
+
const order = await this.scope.model.order.getById(id, {
|
|
1135
|
+
columns: [
|
|
1136
|
+
'id',
|
|
1137
|
+
'state',
|
|
1138
|
+
'currency',
|
|
1139
|
+
'eligibleSubtotalCents',
|
|
1140
|
+
'discountCents',
|
|
1141
|
+
'payableTotalCents',
|
|
1142
|
+
'reservationExpiresAt',
|
|
1143
|
+
'addressSnapshot',
|
|
1144
|
+
'couponSnapshot',
|
|
1145
|
+
'createdAt',
|
|
1146
|
+
'updatedAt',
|
|
1147
|
+
],
|
|
1148
|
+
include: { shipment: true, lines: true },
|
|
1149
|
+
});
|
|
1150
|
+
if (!order) return;
|
|
1151
|
+
const lines: DtoOrderAdminLineResItem[] = order.lines.map(line => ({
|
|
1152
|
+
id: line.id,
|
|
1153
|
+
skuCodeSnapshot: line.skuCodeSnapshot,
|
|
1154
|
+
titleSnapshot: line.titleSnapshot,
|
|
1155
|
+
skuAttributesSnapshot: line.skuAttributesSnapshot,
|
|
1156
|
+
unitPriceCents: line.unitPriceCents,
|
|
1157
|
+
quantity: line.quantity,
|
|
1158
|
+
eligibleSubtotalCents: line.eligibleSubtotalCents,
|
|
1159
|
+
lineTotalCents: line.lineTotalCents,
|
|
1160
|
+
}));
|
|
1161
|
+
return { ...order, lines } as DtoOrderView;
|
|
950
1162
|
}
|
|
951
1163
|
|
|
952
1164
|
async mine(params?: IQueryParams<ModelOrder>): Promise<DtoOrderMineRes> {
|
|
@@ -11,10 +11,33 @@ import type { ModelStockAudit } from '../model/stockAudit.ts';
|
|
|
11
11
|
@Service()
|
|
12
12
|
export class ServiceStockAudit extends BeanBase {
|
|
13
13
|
async select(params?: IQueryParams<ModelStockAudit>): Promise<DtoStockAuditSelectRes> {
|
|
14
|
-
return await this.scope.model.stockAudit.selectAndCount(
|
|
14
|
+
return await this.scope.model.stockAudit.selectAndCount({
|
|
15
|
+
...params,
|
|
16
|
+
columns: ['id', 'skuId', 'operation', 'delta', 'createdAt'],
|
|
17
|
+
});
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
async view(id: TableIdentity): Promise<DtoStockAuditView | undefined> {
|
|
18
|
-
return await this.scope.model.stockAudit.getById(id
|
|
21
|
+
return await this.scope.model.stockAudit.getById(id, {
|
|
22
|
+
columns: [
|
|
23
|
+
'id',
|
|
24
|
+
'stockBalanceId',
|
|
25
|
+
'skuId',
|
|
26
|
+
'stockReservationId',
|
|
27
|
+
'actorId',
|
|
28
|
+
'operation',
|
|
29
|
+
'delta',
|
|
30
|
+
'reason',
|
|
31
|
+
'correlationId',
|
|
32
|
+
'priorOnHand',
|
|
33
|
+
'priorReserved',
|
|
34
|
+
'priorAvailable',
|
|
35
|
+
'onHand',
|
|
36
|
+
'reserved',
|
|
37
|
+
'available',
|
|
38
|
+
'createdAt',
|
|
39
|
+
'updatedAt',
|
|
40
|
+
],
|
|
41
|
+
});
|
|
19
42
|
}
|
|
20
43
|
}
|
|
@@ -34,18 +34,29 @@ const serializationRetryOptions = {
|
|
|
34
34
|
minTimeout: 0,
|
|
35
35
|
maxTimeout: 0,
|
|
36
36
|
randomize: false,
|
|
37
|
-
errorCodes: [
|
|
37
|
+
errorCodes: [
|
|
38
|
+
'40001',
|
|
39
|
+
'ER_LOCK_DEADLOCK',
|
|
40
|
+
'ER_LOCK_WAIT_TIMEOUT',
|
|
41
|
+
'SQLITE_BUSY',
|
|
42
|
+
'SQLITE_BUSY_SNAPSHOT',
|
|
43
|
+
],
|
|
38
44
|
ownerOnly: true,
|
|
39
45
|
};
|
|
40
46
|
|
|
41
47
|
@Service()
|
|
42
48
|
export class ServiceStockBalance extends BeanBase {
|
|
43
49
|
async select(params?: IQueryParams<ModelStockBalance>): Promise<DtoStockBalanceSelectRes> {
|
|
44
|
-
return await this.scope.model.stockBalance.selectAndCount(
|
|
50
|
+
return await this.scope.model.stockBalance.selectAndCount({
|
|
51
|
+
...params,
|
|
52
|
+
columns: ['id', 'skuId', 'onHand', 'reserved', 'available'],
|
|
53
|
+
});
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
async view(id: TableIdentity): Promise<DtoStockBalanceView | undefined> {
|
|
48
|
-
return await this.scope.model.stockBalance.getById(id
|
|
57
|
+
return await this.scope.model.stockBalance.getById(id, {
|
|
58
|
+
columns: ['id', 'skuId', 'onHand', 'reserved', 'available', 'createdAt', 'updatedAt'],
|
|
59
|
+
});
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
@Core.transaction({ isolationLevel: 'SERIALIZABLE' })
|
|
@@ -426,15 +426,15 @@ describe('checkoutReservation.test.ts', { concurrency: false }, () => {
|
|
|
426
426
|
},
|
|
427
427
|
},
|
|
428
428
|
);
|
|
429
|
-
fixture.skuId =
|
|
430
|
-
|
|
429
|
+
fixture.skuId = (
|
|
430
|
+
await app.scope('commerce-catalog').model.sku.insert({
|
|
431
431
|
productId: fixture.productId,
|
|
432
432
|
code: `checkout-snapshot-sku-${suffix}`,
|
|
433
433
|
priceCents: 1299,
|
|
434
434
|
attributes: [{ name: 'Color', value: 'Black' }],
|
|
435
435
|
lifecycle: 'active',
|
|
436
|
-
}
|
|
437
|
-
|
|
436
|
+
})
|
|
437
|
+
).id as number;
|
|
438
438
|
fixture.balanceId = (
|
|
439
439
|
await app.scope('commerce-trade').service.stockBalance.adjustStock({
|
|
440
440
|
skuId: fixture.skuId,
|