cabloy 5.1.127 → 5.1.128
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/CHANGELOG.md +16 -0
- package/cabloy-docs/backend/i18n-guide.md +86 -7
- package/e2e/specs/a-commerce/commerce.spec.ts +93 -8
- package/package.json +1 -1
- package/vona/env/.env +2 -0
- package/vona/env/.env.prod +6 -2
- package/vona/packages-cli/cabloy-cli/package.json +1 -1
- package/vona/packages-cli/cli/package.json +1 -1
- package/vona/packages-cli/cli-set-api/package.json +1 -1
- package/vona/packages-utils/module-glob/package.json +1 -1
- package/vona/packages-utils/utils/package.json +1 -1
- package/vona/packages-utils/utils/src/vona.ts +8 -1
- package/vona/packages-vona/vona/package.json +1 -1
- package/vona/packages-vona/vona-core/package.json +1 -1
- package/vona/packages-vona/vona-mock/package.json +1 -1
- package/vona/pnpm-lock.yaml +10 -39
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/.metadata/index.ts +1 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productSelectResItem.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/dto/productView.tsx +3 -1
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/entity/product.tsx +23 -3
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/model/product.ts +1 -0
- package/vona/src/suite/a-commerce/modules/commerce-catalog/src/service/product.ts +7 -2
- package/vona/src/suite/a-commerce/modules/commerce-catalog/test/productPresentation.test.ts +214 -0
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/bean/payScene.commerceOrder.ts +39 -3
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/commercePayScene.ts +14 -1
- package/vona/src/suite/a-commerce/modules/commerce-payment/src/service/paymentAttempt.ts +5 -1
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/.metadata/index.ts +17 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/controller/checkout.ts +18 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/checkoutCreate.tsx +3 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/checkoutPaymentMethod.tsx +19 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/dto/checkoutPaymentMethods.tsx +17 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/src/service/order.ts +51 -0
- package/vona/src/suite/a-commerce/modules/commerce-trade/test/paymentOutcome.test.ts +2 -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 +94 -55
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/bean.payScene.ts +65 -1
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/bean/meta.redlock.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/controller/paymentCallback.ts +32 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/controller/paymentSession.ts +26 -8
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentCallback.ts +99 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/paymentSession.ts +26 -3
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/providerOperation.ts +214 -82
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/service/refundOperation.ts +27 -2
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payScene.ts +9 -0
- package/vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payment.ts +5 -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 +7 -0
- 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 +395 -84
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/index.ts +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/lib/paypalGateway.ts +129 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-paypal/src/types/index.ts +2 -0
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/package.json +1 -1
- package/vona/src/suite-vendor/a-pay/modules/pay-stripe/src/bean/payProvider.stripe.ts +7 -0
- package/vona/src/suite-vendor/a-pay/package.json +5 -5
- package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +1 -1
- package/vona/src/suite-vendor/a-vona/package.json +1 -1
- package/zova/packages-cli/cli/package.json +3 -3
- package/zova/packages-cli/cli-set-front/package.json +4 -4
- package/zova/packages-utils/zova-jsx/package.json +3 -3
- package/zova/packages-utils/zova-vite/package.json +2 -2
- package/zova/packages-zova/zova/package.json +3 -3
- package/zova/packages-zova/zova-core/package.json +2 -2
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/schemas.ts +8 -0
- package/zova/src/suite/a-commerce/modules/commerce-member/src/api/openapi/types.ts +175 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/cli/openapi.config.ts +1 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/api/commerceTradeCheckout.ts +16 -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 +177 -2
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/apiSchema/commerceTradeCheckout.ts +12 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/model/cart.ts +11 -0
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/checkout/controller.tsx +25 -1
- package/zova/src/suite/a-commerce/modules/commerce-trade/src/page/payment/controller.tsx +27 -4
- package/zova/src/suite-vendor/a-pay/modules/a-pay/cli/openapi.config.ts +1 -1
- 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/api/openapi/schemas.ts +20 -8
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/openapi/types.ts +292 -32
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/api/paymentSession.ts +26 -4
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/apiSchema/paymentSession.ts +5 -0
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/component/paymentNextAction/controller.tsx +2 -1
- package/zova/src/suite-vendor/a-pay/modules/a-pay/src/model/paymentSession.ts +12 -0
- package/zova/src/suite-vendor/a-pay/package.json +2 -2
- package/zova/src/suite-vendor/a-zova/modules/a-zova/package.json +4 -4
- package/zova/src/suite-vendor/a-zova/package.json +2 -2
package/.cabloy-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.1.
|
|
1
|
+
5.1.128
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.1.128
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Add payment session support.
|
|
8
|
+
- Combine resource name components.
|
|
9
|
+
- Add a PayPal Commerce runbook.
|
|
10
|
+
- Implement the product semantic presentation contract.
|
|
11
|
+
- Complete the PayPal Commerce payment flow.
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
- Preserve changes when resolving main branch conflicts.
|
|
16
|
+
- Enforce payment provider availability.
|
|
17
|
+
- Harden PayPal Commerce reconciliation.
|
|
18
|
+
|
|
3
19
|
## 5.1.127
|
|
4
20
|
|
|
5
21
|
### Features
|
|
@@ -127,17 +127,96 @@ declare module 'vona' {
|
|
|
127
127
|
|
|
128
128
|
In the VSCode workflow, the `recordlocale` snippet can generate the augmentation skeleton.
|
|
129
129
|
|
|
130
|
-
##
|
|
130
|
+
## Formatting locale text
|
|
131
131
|
|
|
132
|
-
Locale
|
|
132
|
+
Locale values use printf-style placeholders. Pass formatting values after the locale key:
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
|
|
134
|
+
```typescript
|
|
135
|
+
// en-us.ts
|
|
136
|
+
export default {
|
|
137
|
+
Apples_: '%d apples',
|
|
138
|
+
Greeting: '%s has %d apples',
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
this.scope.locale.Apples_.locale('en-us', 2);
|
|
144
|
+
// 2 apples
|
|
145
|
+
|
|
146
|
+
this.scope.locale.Greeting.locale('en-us', 'Mike', 2);
|
|
147
|
+
// Mike has 2 apples
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Common placeholders include:
|
|
151
|
+
|
|
152
|
+
- `%s`: string
|
|
153
|
+
- `%d`: number
|
|
154
|
+
- `%i`: integer
|
|
155
|
+
- `%f`: floating-point number
|
|
156
|
+
- `%j`: JSON
|
|
157
|
+
- `%%`: literal percent sign
|
|
158
|
+
|
|
159
|
+
## Plural and value-specific support
|
|
160
|
+
|
|
161
|
+
Locale resources can express special messages for exact numeric values through key suffixes:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
export default {
|
|
165
|
+
Apples_: '%d apples',
|
|
166
|
+
Apples_0: 'no apples',
|
|
167
|
+
Apples_1: 'one apple',
|
|
168
|
+
};
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The suffix selects a special message based on the first formatting argument:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
this.scope.locale.Apples_.locale('en-us', 0);
|
|
175
|
+
// no apples
|
|
176
|
+
|
|
177
|
+
this.scope.locale.Apples_.locale('en-us', 1);
|
|
178
|
+
// one apple
|
|
137
179
|
|
|
138
|
-
|
|
180
|
+
this.scope.locale.Apples_.locale('en-us', 2);
|
|
181
|
+
// 2 apples
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The base key is used when no value-specific key matches. Therefore, it is not necessary to define a special key for every possible number.
|
|
185
|
+
|
|
186
|
+
For a numeric value that is not the first formatting argument, use this naming convention:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
<baseKey>_<matchedValue>_<argumentIndex>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The argument index is zero-based. For example:
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
export default {
|
|
196
|
+
NameApples_: '%s has %d apples',
|
|
197
|
+
NameApples_0_1: '%s has no apples',
|
|
198
|
+
NameApples_1_1: '%s has one apple',
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Here:
|
|
203
|
+
|
|
204
|
+
- `NameApples_0_1` matches `args[1] === 0`, the second formatting argument;
|
|
205
|
+
- `NameApples_1_1` matches `args[1] === 1`, the second formatting argument;
|
|
206
|
+
- `NameApples_` is used for other values.
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
this.scope.locale.NameApples_.locale('en-us', 'Mike', 0);
|
|
210
|
+
// Mike has no apples
|
|
211
|
+
|
|
212
|
+
this.scope.locale.NameApples_.locale('en-us', 'Mike', 1);
|
|
213
|
+
// Mike has one apple
|
|
214
|
+
|
|
215
|
+
this.scope.locale.NameApples_.locale('en-us', 'Mike', 2);
|
|
216
|
+
// Mike has 2 apples
|
|
217
|
+
```
|
|
139
218
|
|
|
140
|
-
This makes plural handling part of the localization model
|
|
219
|
+
This is exact numeric-value selection, not automatic `Intl.PluralRules` or CLDR plural-category resolution. It makes common plural handling part of the localization model while allowing each locale to define its own wording.
|
|
141
220
|
|
|
142
221
|
## Timezone support
|
|
143
222
|
|
|
@@ -415,7 +415,7 @@ test(
|
|
|
415
415
|
const startResponse = waitForApiResponse(
|
|
416
416
|
page,
|
|
417
417
|
'POST',
|
|
418
|
-
new RegExp(`/api/payment-session/${checkout.paymentSessionId}/start$`),
|
|
418
|
+
new RegExp(`/api/pay/payment-session/${checkout.paymentSessionId}/start$`),
|
|
419
419
|
);
|
|
420
420
|
await page.getByRole('button', { name: 'Start payment', exact: true }).click();
|
|
421
421
|
expect((await startResponse).ok()).toBeTruthy();
|
|
@@ -535,9 +535,7 @@ test(
|
|
|
535
535
|
await orderCard.getByRole('button', { name: 'View', exact: true }).click();
|
|
536
536
|
await expect(page).toHaveURL(new RegExp(`/commerce/order/${checkout.orderId}(?:/|$)`));
|
|
537
537
|
await historyDetailResponse;
|
|
538
|
-
await expect(
|
|
539
|
-
page.getByRole('heading', { name: `Order #${checkout.orderId}`, level: 1 }),
|
|
540
|
-
).toBeVisible();
|
|
538
|
+
await expect(page.getByRole('heading', { name: `Order #${checkout.orderId}` })).toBeVisible();
|
|
541
539
|
await expect(page.getByText('1 × $45.99 = $45.99')).toBeVisible();
|
|
542
540
|
await expect(page.getByRole('alert')).toHaveCount(0);
|
|
543
541
|
expect(pageErrors).toEqual([]);
|
|
@@ -586,7 +584,7 @@ test(
|
|
|
586
584
|
const startResponse = waitForApiResponse(
|
|
587
585
|
page,
|
|
588
586
|
'POST',
|
|
589
|
-
new RegExp(`/api/payment-session/${checkout.paymentSessionId}/start$`),
|
|
587
|
+
new RegExp(`/api/pay/payment-session/${checkout.paymentSessionId}/start$`),
|
|
590
588
|
);
|
|
591
589
|
await page.getByRole('button', { name: 'Start payment', exact: true }).click();
|
|
592
590
|
expect((await startResponse).ok()).toBeTruthy();
|
|
@@ -654,7 +652,7 @@ test(
|
|
|
654
652
|
const startResponse = waitForApiResponse(
|
|
655
653
|
page,
|
|
656
654
|
'POST',
|
|
657
|
-
new RegExp(`/api/payment-session/${checkout.paymentSessionId}/start$`),
|
|
655
|
+
new RegExp(`/api/pay/payment-session/${checkout.paymentSessionId}/start$`),
|
|
658
656
|
);
|
|
659
657
|
await page.getByRole('button', { name: 'Start payment', exact: true }).click();
|
|
660
658
|
expect((await startResponse).ok()).toBeTruthy();
|
|
@@ -738,8 +736,7 @@ test(
|
|
|
738
736
|
{ timeout: 40_000 },
|
|
739
737
|
)
|
|
740
738
|
.toContain('refunded');
|
|
741
|
-
|
|
742
|
-
await expect(refundedOrderRow).toContainText('refunded');
|
|
739
|
+
await expect(await getAdminOrderRow(adminPage, checkout.orderId)).toContainText('refunded');
|
|
743
740
|
expect(adminPageErrors).toEqual([]);
|
|
744
741
|
} finally {
|
|
745
742
|
await adminContext.close().catch(() => {});
|
|
@@ -1016,6 +1013,94 @@ test(
|
|
|
1016
1013
|
},
|
|
1017
1014
|
);
|
|
1018
1015
|
|
|
1016
|
+
test(
|
|
1017
|
+
'ATP-SPC-02: Product renders semantic Admin relation and publication controls',
|
|
1018
|
+
{ tag: ['@admin', '@flow', '@product'] },
|
|
1019
|
+
async ({ browser }, testInfo) => {
|
|
1020
|
+
test.setTimeout(60_000);
|
|
1021
|
+
const suffix = `${testInfo.workerIndex}-${testInfo.parallelIndex ?? testInfo.retry}-${Date.now()}`;
|
|
1022
|
+
const categoryName = `E2E Product Category ${suffix}`;
|
|
1023
|
+
const productTitle = `E2E Product ${suffix}`;
|
|
1024
|
+
const adminContext = await browser.newContext();
|
|
1025
|
+
const adminPage = await adminContext.newPage();
|
|
1026
|
+
const adminPageErrors = collectPageErrors(adminPage);
|
|
1027
|
+
const productCreatePath = '/commerce-admin/rest/resource/commerce-catalog%3Aproduct/create';
|
|
1028
|
+
const productListPath = '/commerce-admin/rest/resource/commerce-catalog%3Aproduct';
|
|
1029
|
+
const categoryActionPath = '/api/commerce/catalog/category';
|
|
1030
|
+
const productActionPath = '/api/commerce/catalog/product';
|
|
1031
|
+
let categoryId: number | string | undefined;
|
|
1032
|
+
let productId: number | string | undefined;
|
|
1033
|
+
let headers: { Authorization: string } | undefined;
|
|
1034
|
+
try {
|
|
1035
|
+
await adminPage.setViewportSize({ width: 1440, height: 900 });
|
|
1036
|
+
await login(adminPage, '/commerce-admin/', 'admin', '123456', 'commerceAdmin');
|
|
1037
|
+
const accessToken = (await adminContext.cookies()).find(
|
|
1038
|
+
cookie => cookie.name === 'token',
|
|
1039
|
+
)?.value;
|
|
1040
|
+
expect(accessToken).toBeTruthy();
|
|
1041
|
+
headers = { Authorization: `Bearer ${accessToken}` };
|
|
1042
|
+
|
|
1043
|
+
const categoryResponse = await adminPage.request.post(categoryActionPath, {
|
|
1044
|
+
data: { name: categoryName, published: true },
|
|
1045
|
+
headers,
|
|
1046
|
+
});
|
|
1047
|
+
expect(categoryResponse.ok()).toBeTruthy();
|
|
1048
|
+
categoryId = (await categoryResponse.json()).data;
|
|
1049
|
+
expectTableIdentity(categoryId);
|
|
1050
|
+
|
|
1051
|
+
await adminPage.goto(productCreatePath, { waitUntil: 'load' });
|
|
1052
|
+
const categoryPicker = adminPage
|
|
1053
|
+
.getByRole('group', { name: 'Category' })
|
|
1054
|
+
.getByRole('combobox');
|
|
1055
|
+
await expect(categoryPicker).toBeVisible();
|
|
1056
|
+
await categoryPicker.selectOption({ label: categoryName });
|
|
1057
|
+
await expect(categoryPicker).toHaveValue(String(categoryId));
|
|
1058
|
+
const publication = adminPage.getByRole('group', { name: 'Published' }).getByRole('combobox');
|
|
1059
|
+
await expect(publication).toBeVisible();
|
|
1060
|
+
await publication.selectOption({ label: 'Unpublished' });
|
|
1061
|
+
await expect(publication).toHaveValue('false');
|
|
1062
|
+
|
|
1063
|
+
const productResponse = await adminPage.request.post(productActionPath, {
|
|
1064
|
+
data: { categoryId, title: productTitle, published: false },
|
|
1065
|
+
headers,
|
|
1066
|
+
});
|
|
1067
|
+
expect(productResponse.ok()).toBeTruthy();
|
|
1068
|
+
productId = (await productResponse.json()).data;
|
|
1069
|
+
expectTableIdentity(productId);
|
|
1070
|
+
|
|
1071
|
+
await adminPage.goto(productListPath, { waitUntil: 'load' });
|
|
1072
|
+
const productRow = adminPage.getByRole('row', { name: new RegExp(productTitle) });
|
|
1073
|
+
await expect(productRow).toBeVisible();
|
|
1074
|
+
await expect(productRow.getByText(categoryName, { exact: true })).toBeVisible();
|
|
1075
|
+
await expect(productRow.getByText('Unpublished', { exact: true })).toBeVisible();
|
|
1076
|
+
|
|
1077
|
+
await adminPage.goto(`${productListPath}/${productId}`, { waitUntil: 'load' });
|
|
1078
|
+
await expect(
|
|
1079
|
+
adminPage.getByRole('group', { name: 'Category' }).getByRole('textbox'),
|
|
1080
|
+
).toHaveValue(categoryName);
|
|
1081
|
+
await expect(
|
|
1082
|
+
adminPage.getByRole('group', { name: 'Published' }).getByRole('textbox'),
|
|
1083
|
+
).toHaveValue('Unpublished');
|
|
1084
|
+
await expect(adminPage.getByRole('button', { name: 'Submit', exact: true })).toHaveCount(0);
|
|
1085
|
+
expect(adminPageErrors).toEqual([]);
|
|
1086
|
+
} finally {
|
|
1087
|
+
if (productId && headers) {
|
|
1088
|
+
const response = await adminPage.request.delete(`${productActionPath}/${productId}`, {
|
|
1089
|
+
headers,
|
|
1090
|
+
});
|
|
1091
|
+
expect(response.ok()).toBeTruthy();
|
|
1092
|
+
}
|
|
1093
|
+
if (categoryId && headers) {
|
|
1094
|
+
const response = await adminPage.request.delete(`${categoryActionPath}/${categoryId}`, {
|
|
1095
|
+
headers,
|
|
1096
|
+
});
|
|
1097
|
+
expect(response.ok()).toBeTruthy();
|
|
1098
|
+
}
|
|
1099
|
+
await adminContext.close().catch(() => {});
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
1102
|
+
);
|
|
1103
|
+
|
|
1019
1104
|
test(
|
|
1020
1105
|
'Commerce Cart: anonymous browser is redirected to login',
|
|
1021
1106
|
{ tag: ['@web', '@cart'] },
|
package/package.json
CHANGED
package/vona/env/.env
CHANGED
package/vona/env/.env.prod
CHANGED
|
@@ -17,7 +17,14 @@ export function combineResourceNameParts(
|
|
|
17
17
|
// path
|
|
18
18
|
const res: string[] = [];
|
|
19
19
|
if (!simplifyProviderId || parts[0] !== 'a') res.push(parts[0]);
|
|
20
|
-
if (
|
|
20
|
+
if (
|
|
21
|
+
!simplify ||
|
|
22
|
+
(resourceName !== parts[1] &&
|
|
23
|
+
!resourceName.startsWith(`${parts[1]}-`) &&
|
|
24
|
+
!resourceName.startsWith(`${parts[1]}/`))
|
|
25
|
+
) {
|
|
26
|
+
res.push(parts[1]);
|
|
27
|
+
}
|
|
21
28
|
if (resourceName) res.push(resourceName);
|
|
22
29
|
return res;
|
|
23
30
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vona",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.85",
|
|
4
4
|
"gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
|
|
5
5
|
"description": "Vona is an intuitive, elegant and powerful Node.js framework for rapidly developing enterprise applications of any size",
|
|
6
6
|
"keywords": [
|
package/vona/pnpm-lock.yaml
CHANGED
|
@@ -24,7 +24,7 @@ importers:
|
|
|
24
24
|
dependencies:
|
|
25
25
|
'@babel/core':
|
|
26
26
|
specifier: ^7.29.0
|
|
27
|
-
version: 7.29.7
|
|
27
|
+
version: 7.29.7
|
|
28
28
|
'@babel/traverse':
|
|
29
29
|
specifier: ^7.29.0
|
|
30
30
|
version: 7.29.7
|
|
@@ -69,7 +69,7 @@ importers:
|
|
|
69
69
|
version: 8.0.1
|
|
70
70
|
bullmq:
|
|
71
71
|
specifier: ^5.74.1
|
|
72
|
-
version: 5.79.1
|
|
72
|
+
version: 5.79.1
|
|
73
73
|
chalk:
|
|
74
74
|
specifier: ^5.6.2
|
|
75
75
|
version: 5.6.2
|
|
@@ -81,7 +81,7 @@ importers:
|
|
|
81
81
|
version: 11.3.5
|
|
82
82
|
ioredis:
|
|
83
83
|
specifier: ^5.10.1
|
|
84
|
-
version: 5.11.1
|
|
84
|
+
version: 5.11.1
|
|
85
85
|
knex:
|
|
86
86
|
specifier: ^3.3.0
|
|
87
87
|
version: 3.3.0(better-sqlite3@12.11.1)
|
|
@@ -2756,7 +2756,7 @@ importers:
|
|
|
2756
2756
|
dependencies:
|
|
2757
2757
|
bullmq:
|
|
2758
2758
|
specifier: ^5.74.1
|
|
2759
|
-
version: 5.79.1
|
|
2759
|
+
version: 5.79.1
|
|
2760
2760
|
devDependencies:
|
|
2761
2761
|
clean-package:
|
|
2762
2762
|
specifier: ^2.2.0
|
|
@@ -2778,7 +2778,7 @@ importers:
|
|
|
2778
2778
|
dependencies:
|
|
2779
2779
|
ioredis:
|
|
2780
2780
|
specifier: ^5.10.1
|
|
2781
|
-
version: 5.11.1
|
|
2781
|
+
version: 5.11.1
|
|
2782
2782
|
devDependencies:
|
|
2783
2783
|
clean-package:
|
|
2784
2784
|
specifier: ^2.2.0
|
|
@@ -8962,26 +8962,6 @@ snapshots:
|
|
|
8962
8962
|
transitivePeerDependencies:
|
|
8963
8963
|
- supports-color
|
|
8964
8964
|
|
|
8965
|
-
'@babel/core@7.29.7(supports-color@5.5.0)':
|
|
8966
|
-
dependencies:
|
|
8967
|
-
'@babel/code-frame': 7.29.7
|
|
8968
|
-
'@babel/generator': 7.29.7
|
|
8969
|
-
'@babel/helper-compilation-targets': 7.29.7
|
|
8970
|
-
'@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@5.5.0))
|
|
8971
|
-
'@babel/helpers': 7.29.7
|
|
8972
|
-
'@babel/parser': 7.29.7
|
|
8973
|
-
'@babel/template': 7.29.7
|
|
8974
|
-
'@babel/traverse': 7.29.7
|
|
8975
|
-
'@babel/types': 7.29.7
|
|
8976
|
-
'@jridgewell/remapping': 2.3.5
|
|
8977
|
-
convert-source-map: 2.0.0
|
|
8978
|
-
debug: 4.4.3(supports-color@5.5.0)
|
|
8979
|
-
gensync: 1.0.0-beta.2
|
|
8980
|
-
json5: 2.2.3
|
|
8981
|
-
semver: 6.3.1
|
|
8982
|
-
transitivePeerDependencies:
|
|
8983
|
-
- supports-color
|
|
8984
|
-
|
|
8985
8965
|
'@babel/generator@7.29.7':
|
|
8986
8966
|
dependencies:
|
|
8987
8967
|
'@babel/parser': 7.29.7
|
|
@@ -9031,15 +9011,6 @@ snapshots:
|
|
|
9031
9011
|
transitivePeerDependencies:
|
|
9032
9012
|
- supports-color
|
|
9033
9013
|
|
|
9034
|
-
'@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@5.5.0))':
|
|
9035
|
-
dependencies:
|
|
9036
|
-
'@babel/core': 7.29.7(supports-color@5.5.0)
|
|
9037
|
-
'@babel/helper-module-imports': 7.29.7
|
|
9038
|
-
'@babel/helper-validator-identifier': 7.29.7
|
|
9039
|
-
'@babel/traverse': 7.29.7
|
|
9040
|
-
transitivePeerDependencies:
|
|
9041
|
-
- supports-color
|
|
9042
|
-
|
|
9043
9014
|
'@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
|
|
9044
9015
|
dependencies:
|
|
9045
9016
|
'@babel/core': 7.29.7
|
|
@@ -10006,7 +9977,7 @@ snapshots:
|
|
|
10006
9977
|
|
|
10007
9978
|
'@sesamecare-oss/redlock@1.4.0(ioredis@5.11.1)':
|
|
10008
9979
|
dependencies:
|
|
10009
|
-
ioredis: 5.11.1
|
|
9980
|
+
ioredis: 5.11.1
|
|
10010
9981
|
|
|
10011
9982
|
'@sindresorhus/merge-streams@2.3.0': {}
|
|
10012
9983
|
|
|
@@ -10912,10 +10883,10 @@ snapshots:
|
|
|
10912
10883
|
base64-js: 1.5.1
|
|
10913
10884
|
ieee754: 1.2.1
|
|
10914
10885
|
|
|
10915
|
-
bullmq@5.79.1
|
|
10886
|
+
bullmq@5.79.1:
|
|
10916
10887
|
dependencies:
|
|
10917
10888
|
cron-parser: 4.9.0
|
|
10918
|
-
ioredis: 5.10.1
|
|
10889
|
+
ioredis: 5.10.1
|
|
10919
10890
|
msgpackr: 2.0.2
|
|
10920
10891
|
node-abort-controller: 3.1.1
|
|
10921
10892
|
semver: 7.8.1
|
|
@@ -12061,7 +12032,7 @@ snapshots:
|
|
|
12061
12032
|
|
|
12062
12033
|
interpret@2.2.0: {}
|
|
12063
12034
|
|
|
12064
|
-
ioredis@5.10.1
|
|
12035
|
+
ioredis@5.10.1:
|
|
12065
12036
|
dependencies:
|
|
12066
12037
|
'@ioredis/commands': 1.5.1
|
|
12067
12038
|
cluster-key-slot: 1.1.2
|
|
@@ -12075,7 +12046,7 @@ snapshots:
|
|
|
12075
12046
|
transitivePeerDependencies:
|
|
12076
12047
|
- supports-color
|
|
12077
12048
|
|
|
12078
|
-
ioredis@5.11.1
|
|
12049
|
+
ioredis@5.11.1:
|
|
12079
12050
|
dependencies:
|
|
12080
12051
|
'@ioredis/commands': 1.10.0
|
|
12081
12052
|
cluster-key-slot: 1.1.1
|
|
@@ -149,7 +149,7 @@ declare module 'vona-module-commerce-catalog' {
|
|
|
149
149
|
}
|
|
150
150
|
export interface IModelOptionsProduct {
|
|
151
151
|
relations: {
|
|
152
|
-
category: IModelRelationBelongsTo<'commerce-catalog:product', 'commerce-catalog:category', false, '
|
|
152
|
+
category: IModelRelationBelongsTo<'commerce-catalog:product', 'commerce-catalog:category', false, 'id'|'name'|'published'>;
|
|
153
153
|
skus: IModelRelationHasMany<'commerce-catalog:sku', 'productId', false, '*', undefined, undefined, undefined>;
|
|
154
154
|
skuAvailables: IModelRelationHasMany<'commerce-catalog:sku', 'productId', false, 'id'|'code'|'productId'|'priceCents', ['commerce-trade:stockBalance'], undefined, undefined>;
|
|
155
155
|
};
|
|
@@ -46,7 +46,9 @@ export interface IDtoOptionsProductSelectResItem extends IDecoratorDtoOptions {}
|
|
|
46
46
|
}),
|
|
47
47
|
],
|
|
48
48
|
})
|
|
49
|
-
export class DtoProductSelectResItem extends $Dto.get(() => ModelProduct
|
|
49
|
+
export class DtoProductSelectResItem extends $Dto.get(() => ModelProduct, {
|
|
50
|
+
include: { category: true },
|
|
51
|
+
}) {
|
|
50
52
|
@Api.field(
|
|
51
53
|
v.title($locale('Operations')),
|
|
52
54
|
ZovaRender.order(1, 'max'),
|
|
@@ -22,4 +22,6 @@ export interface IDtoOptionsProductView extends IDecoratorDtoOptions {}
|
|
|
22
22
|
}),
|
|
23
23
|
],
|
|
24
24
|
})
|
|
25
|
-
export class DtoProductView extends $Dto.get(() => ModelProduct
|
|
25
|
+
export class DtoProductView extends $Dto.get(() => ModelProduct, {
|
|
26
|
+
include: { category: true },
|
|
27
|
+
}) {}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { TableIdentity } from 'table-identity';
|
|
2
2
|
import type { IDecoratorEntityOptions } from 'vona-module-a-orm';
|
|
3
3
|
|
|
4
|
-
import { $makeMetadata, Api, v } from 'vona-module-a-openapiutils';
|
|
4
|
+
import { $makeMetadata, $resourceName, Api, v } from 'vona-module-a-openapiutils';
|
|
5
5
|
import { Entity, EntityBase } from 'vona-module-a-orm';
|
|
6
6
|
import { ZovaRender } from 'zova-rest-cabloy-basic-admin';
|
|
7
7
|
|
|
8
8
|
import { $locale } from '../.metadata/locales.ts';
|
|
9
|
+
import { categoryPublicationItems } from './category.tsx';
|
|
9
10
|
|
|
10
11
|
export interface IEntityOptionsProduct extends IDecoratorEntityOptions {}
|
|
11
12
|
|
|
@@ -37,10 +38,29 @@ export class EntityProduct extends EntityBase {
|
|
|
37
38
|
)
|
|
38
39
|
title: string;
|
|
39
40
|
|
|
40
|
-
@Api.field(
|
|
41
|
+
@Api.field(
|
|
42
|
+
v.title($locale('Category')),
|
|
43
|
+
v.required(),
|
|
44
|
+
ZovaRender.order(2),
|
|
45
|
+
ZovaRender.field('basic-resource:formFieldResourcePicker', {
|
|
46
|
+
resource: $resourceName('commerce-catalog:category'),
|
|
47
|
+
relationName: 'category',
|
|
48
|
+
}),
|
|
49
|
+
ZovaRender.cell('basic-resource:resourcePicker', {
|
|
50
|
+
resource: $resourceName('commerce-catalog:category'),
|
|
51
|
+
relationName: 'category',
|
|
52
|
+
}),
|
|
53
|
+
v.tableIdentity(),
|
|
54
|
+
)
|
|
41
55
|
categoryId: TableIdentity;
|
|
42
56
|
|
|
43
|
-
@Api.field(
|
|
57
|
+
@Api.field(
|
|
58
|
+
v.title($locale('Published')),
|
|
59
|
+
v.default(false),
|
|
60
|
+
ZovaRender.order(3),
|
|
61
|
+
ZovaRender.field('basic-select:formFieldSelect', { items: categoryPublicationItems }),
|
|
62
|
+
ZovaRender.cell('basic-select:select', { items: categoryPublicationItems }),
|
|
63
|
+
)
|
|
44
64
|
published: boolean;
|
|
45
65
|
|
|
46
66
|
@Api.field(v.title($locale('Description')), v.optional(), ZovaRender.order(4))
|
|
@@ -13,6 +13,7 @@ export interface IModelOptionsProduct extends IDecoratorModelOptions<EntityProdu
|
|
|
13
13
|
'commerce-catalog:product',
|
|
14
14
|
'commerce-catalog:category',
|
|
15
15
|
'categoryId',
|
|
16
|
+
{ columns: ['id', 'name', 'published'] },
|
|
16
17
|
),
|
|
17
18
|
skus: $relation.hasMany('commerce-catalog:sku', 'productId'),
|
|
18
19
|
skuAvailables: $relation.hasMany(
|
|
@@ -22,7 +22,10 @@ export class ServiceProduct extends BeanBase {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async select(params?: IQueryParams<ModelProduct>): Promise<DtoProductSelectRes> {
|
|
25
|
-
return await this.scope.model.product.selectAndCount(
|
|
25
|
+
return await this.scope.model.product.selectAndCount({
|
|
26
|
+
...params,
|
|
27
|
+
include: { ...params?.include, category: true },
|
|
28
|
+
});
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
async selectPublic(params: IQueryParams<ModelProduct>): Promise<DtoProductPublicSelectRes> {
|
|
@@ -50,7 +53,9 @@ export class ServiceProduct extends BeanBase {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
async view(id: TableIdentity): Promise<DtoProductView | undefined> {
|
|
53
|
-
return await this.scope.model.product.getById(id
|
|
56
|
+
return await this.scope.model.product.getById(id, {
|
|
57
|
+
include: { category: true },
|
|
58
|
+
});
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
async viewPublic(id: TableIdentity): Promise<DtoProductPublic | undefined> {
|