@faststore/api 1.9.14 → 1.10.6
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/CHANGELOG.md +30 -0
- package/dist/__generated__/schema.d.ts +5 -1
- package/dist/api.cjs.development.js +66 -3
- package/dist/api.cjs.development.js.map +1 -1
- package/dist/api.cjs.production.min.js +1 -1
- package/dist/api.cjs.production.min.js.map +1 -1
- package/dist/api.esm.js +66 -3
- package/dist/api.esm.js.map +1 -1
- package/dist/platforms/vtex/clients/commerce/index.d.ts +11 -0
- package/dist/platforms/vtex/clients/commerce/types/Product.d.ts +174 -0
- package/dist/platforms/vtex/clients/index.d.ts +7 -0
- package/dist/platforms/vtex/resolvers/query.d.ts +3 -3
- package/dist/platforms/vtex/utils/facets.d.ts +14 -0
- package/package.json +3 -3
- package/src/__generated__/schema.ts +5 -1
- package/src/platforms/vtex/clients/commerce/index.ts +24 -2
- package/src/platforms/vtex/clients/commerce/types/Product.ts +199 -0
- package/src/platforms/vtex/resolvers/query.ts +39 -14
- package/src/platforms/vtex/utils/facets.ts +41 -0
- package/src/typeDefs/facet.graphql +13 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { FACET_CROSS_SELLING_MAP } from "../../utils/facets";
|
|
2
|
+
import type { PortalProduct } from "./types/Product";
|
|
1
3
|
import type { Context, Options } from '../../index';
|
|
2
4
|
import type { Brand } from './types/Brand';
|
|
3
5
|
import type { CategoryTree } from './types/CategoryTree';
|
|
@@ -7,6 +9,7 @@ import type { Region, RegionInput } from './types/Region';
|
|
|
7
9
|
import type { Simulation, SimulationArgs, SimulationOptions } from './types/Simulation';
|
|
8
10
|
import type { Session } from './types/Session';
|
|
9
11
|
import type { Channel } from '../../utils/channel';
|
|
12
|
+
declare type ValueOf<T> = T extends Record<string, infer K> ? K : never;
|
|
10
13
|
export declare const VtexCommerce: ({ account, environment }: Options, ctx: Context) => {
|
|
11
14
|
catalog: {
|
|
12
15
|
brand: {
|
|
@@ -18,6 +21,13 @@ export declare const VtexCommerce: ({ account, environment }: Options, ctx: Cont
|
|
|
18
21
|
portal: {
|
|
19
22
|
pagetype: (slug: string) => Promise<PortalPagetype>;
|
|
20
23
|
};
|
|
24
|
+
products: {
|
|
25
|
+
crossselling: ({ type, productId, groupByProduct }: {
|
|
26
|
+
type: ValueOf<typeof FACET_CROSS_SELLING_MAP>;
|
|
27
|
+
productId: string;
|
|
28
|
+
groupByProduct?: boolean | undefined;
|
|
29
|
+
}) => Promise<PortalProduct[]>;
|
|
30
|
+
};
|
|
21
31
|
};
|
|
22
32
|
checkout: {
|
|
23
33
|
simulation: (args: SimulationArgs, { salesChannel }?: SimulationOptions) => Promise<Simulation>;
|
|
@@ -42,3 +52,4 @@ export declare const VtexCommerce: ({ account, environment }: Options, ctx: Cont
|
|
|
42
52
|
};
|
|
43
53
|
session: (search: string) => Promise<Session>;
|
|
44
54
|
};
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export interface PortalProduct {
|
|
2
|
+
productId: string;
|
|
3
|
+
productName: string;
|
|
4
|
+
brand: string;
|
|
5
|
+
brandId: number;
|
|
6
|
+
brandImageUrl: null | string;
|
|
7
|
+
linkText: string;
|
|
8
|
+
productReference: string;
|
|
9
|
+
productReferenceCode: string;
|
|
10
|
+
categoryId: string;
|
|
11
|
+
productTitle: string;
|
|
12
|
+
metaTagDescription: string;
|
|
13
|
+
releaseDate: Date;
|
|
14
|
+
clusterHighlights: unknown;
|
|
15
|
+
productClusters: unknown;
|
|
16
|
+
searchableClusters: unknown;
|
|
17
|
+
categories: Category[];
|
|
18
|
+
categoriesIds: CategoriesId[];
|
|
19
|
+
link: string;
|
|
20
|
+
description: string;
|
|
21
|
+
items: Item[];
|
|
22
|
+
}
|
|
23
|
+
declare enum Category {
|
|
24
|
+
Office = "/Office/",
|
|
25
|
+
OfficeChairs = "/Office/Chairs/"
|
|
26
|
+
}
|
|
27
|
+
declare enum CategoriesId {
|
|
28
|
+
The9282 = "/9282/",
|
|
29
|
+
The92829296 = "/9282/9296/"
|
|
30
|
+
}
|
|
31
|
+
interface Item {
|
|
32
|
+
itemId: string;
|
|
33
|
+
name: string;
|
|
34
|
+
nameComplete: string;
|
|
35
|
+
complementName: string;
|
|
36
|
+
ean: string;
|
|
37
|
+
referenceId: ReferenceId[];
|
|
38
|
+
measurementUnit: MeasurementUnit;
|
|
39
|
+
unitMultiplier: number;
|
|
40
|
+
modalType: null;
|
|
41
|
+
isKit: boolean;
|
|
42
|
+
images: Image[];
|
|
43
|
+
sellers: Seller[];
|
|
44
|
+
videos: unknown[];
|
|
45
|
+
estimatedDateArrival: null;
|
|
46
|
+
}
|
|
47
|
+
interface Image {
|
|
48
|
+
imageId: string;
|
|
49
|
+
imageLabel: string;
|
|
50
|
+
imageTag: string;
|
|
51
|
+
imageUrl: string;
|
|
52
|
+
imageText: string;
|
|
53
|
+
imageLastModified: Date;
|
|
54
|
+
}
|
|
55
|
+
declare enum MeasurementUnit {
|
|
56
|
+
Un = "un"
|
|
57
|
+
}
|
|
58
|
+
interface ReferenceId {
|
|
59
|
+
key: Key;
|
|
60
|
+
value: string;
|
|
61
|
+
}
|
|
62
|
+
declare enum Key {
|
|
63
|
+
RefId = "RefId"
|
|
64
|
+
}
|
|
65
|
+
interface Seller {
|
|
66
|
+
sellerId: string;
|
|
67
|
+
sellerName: SellerName;
|
|
68
|
+
addToCartLink: string;
|
|
69
|
+
sellerDefault: boolean;
|
|
70
|
+
commertialOffer: CommertialOffer;
|
|
71
|
+
}
|
|
72
|
+
interface CommertialOffer {
|
|
73
|
+
deliverySlaSamplesPerRegion: DeliverySlaSamplesPerRegion;
|
|
74
|
+
installments: Installment[];
|
|
75
|
+
discountHighLight: unknown[];
|
|
76
|
+
giftSkuIds: unknown[];
|
|
77
|
+
teasers: unknown[];
|
|
78
|
+
buyTogether: unknown[];
|
|
79
|
+
itemMetadataAttachment: unknown[];
|
|
80
|
+
price: number;
|
|
81
|
+
listPrice: number;
|
|
82
|
+
priceWithoutDiscount: number;
|
|
83
|
+
rewardValue: number;
|
|
84
|
+
priceValidUntil: Date;
|
|
85
|
+
availableQuantity: number;
|
|
86
|
+
isAvailable: boolean;
|
|
87
|
+
tax: number;
|
|
88
|
+
deliverySlaSamples: DeliverySlaSample[];
|
|
89
|
+
getInfoErrorMessage: null;
|
|
90
|
+
cacheVersionUsedToCallCheckout: string;
|
|
91
|
+
paymentOptions: PaymentOptions;
|
|
92
|
+
}
|
|
93
|
+
interface DeliverySlaSample {
|
|
94
|
+
deliverySlaPerTypes: unknown[];
|
|
95
|
+
region: null;
|
|
96
|
+
}
|
|
97
|
+
interface DeliverySlaSamplesPerRegion {
|
|
98
|
+
the0: DeliverySlaSample;
|
|
99
|
+
}
|
|
100
|
+
interface Installment {
|
|
101
|
+
value: number;
|
|
102
|
+
interestRate: number;
|
|
103
|
+
totalValuePlusInterestRate: number;
|
|
104
|
+
numberOfInstallments: number;
|
|
105
|
+
paymentSystemName: PaymentSystemNameEnum;
|
|
106
|
+
paymentSystemGroupName: GroupName;
|
|
107
|
+
name: Name;
|
|
108
|
+
}
|
|
109
|
+
declare enum Name {
|
|
110
|
+
BoletoBancárioÀVista = "Boleto Banc\u00E1rio \u00E0 vista",
|
|
111
|
+
FreeÀVista = "Free \u00E0 vista"
|
|
112
|
+
}
|
|
113
|
+
declare enum GroupName {
|
|
114
|
+
BankInvoicePaymentGroup = "bankInvoicePaymentGroup",
|
|
115
|
+
Custom201PaymentGroupPaymentGroup = "custom201PaymentGroupPaymentGroup"
|
|
116
|
+
}
|
|
117
|
+
declare enum PaymentSystemNameEnum {
|
|
118
|
+
BoletoBancário = "Boleto Banc\u00E1rio",
|
|
119
|
+
Free = "Free"
|
|
120
|
+
}
|
|
121
|
+
interface PaymentOptions {
|
|
122
|
+
installmentOptions: InstallmentOption[];
|
|
123
|
+
paymentSystems: PaymentSystem[];
|
|
124
|
+
payments: unknown[];
|
|
125
|
+
giftCards: unknown[];
|
|
126
|
+
giftCardMessages: unknown[];
|
|
127
|
+
availableAccounts: unknown[];
|
|
128
|
+
availableTokens: unknown[];
|
|
129
|
+
}
|
|
130
|
+
interface InstallmentOption {
|
|
131
|
+
paymentSystem: string;
|
|
132
|
+
bin: null;
|
|
133
|
+
paymentName: PaymentSystemNameEnum;
|
|
134
|
+
paymentGroupName: GroupName;
|
|
135
|
+
value: number;
|
|
136
|
+
installments: InstallmentElement[];
|
|
137
|
+
}
|
|
138
|
+
interface InstallmentElement {
|
|
139
|
+
count: number;
|
|
140
|
+
hasInterestRate: boolean;
|
|
141
|
+
interestRate: number;
|
|
142
|
+
value: number;
|
|
143
|
+
total: number;
|
|
144
|
+
sellerMerchantInstallments?: InstallmentElement[];
|
|
145
|
+
id?: Id;
|
|
146
|
+
}
|
|
147
|
+
declare enum Id {
|
|
148
|
+
Storeframework = "STOREFRAMEWORK"
|
|
149
|
+
}
|
|
150
|
+
interface PaymentSystem {
|
|
151
|
+
id: number;
|
|
152
|
+
name: PaymentSystemNameEnum;
|
|
153
|
+
groupName: GroupName;
|
|
154
|
+
validator: null;
|
|
155
|
+
stringId: string;
|
|
156
|
+
template: Template;
|
|
157
|
+
requiresDocument: boolean;
|
|
158
|
+
isCustom: boolean;
|
|
159
|
+
description: Description | null;
|
|
160
|
+
requiresAuthentication: boolean;
|
|
161
|
+
dueDate: Date;
|
|
162
|
+
availablePayments: null;
|
|
163
|
+
}
|
|
164
|
+
declare enum Description {
|
|
165
|
+
FreePayToTestCheckoutPayments = "Free pay to test checkout payments"
|
|
166
|
+
}
|
|
167
|
+
declare enum Template {
|
|
168
|
+
BankInvoicePaymentGroupTemplate = "bankInvoicePaymentGroup-template",
|
|
169
|
+
Custom201PaymentGroupPaymentGroupTemplate = "custom201PaymentGroupPaymentGroup-template"
|
|
170
|
+
}
|
|
171
|
+
declare enum SellerName {
|
|
172
|
+
Vtex = "VTEX"
|
|
173
|
+
}
|
|
174
|
+
export {};
|
|
@@ -18,6 +18,13 @@ export declare const getClients: (options: Options, ctx: Context) => {
|
|
|
18
18
|
portal: {
|
|
19
19
|
pagetype: (slug: string) => Promise<import("./commerce/types/Portal").PortalPagetype>;
|
|
20
20
|
};
|
|
21
|
+
products: {
|
|
22
|
+
crossselling: ({ type, productId, groupByProduct }: {
|
|
23
|
+
type: "whoboughtalsobought" | "whosawalsosaw" | "similars" | "whosawalsobought" | "accessories" | "suggestions";
|
|
24
|
+
productId: string;
|
|
25
|
+
groupByProduct?: boolean | undefined;
|
|
26
|
+
}) => Promise<import("./commerce/types/Product").PortalProduct[]>;
|
|
27
|
+
};
|
|
21
28
|
};
|
|
22
29
|
checkout: {
|
|
23
30
|
simulation: (args: import("./commerce/types/Simulation").SimulationArgs, { salesChannel }?: import("./commerce/types/Simulation").SimulationOptions) => Promise<import("./commerce/types/Simulation").Simulation>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { CategoryTree } from
|
|
3
|
-
import type { Context } from
|
|
1
|
+
import type { QueryAllCollectionsArgs, QueryAllProductsArgs, QueryCollectionArgs, QueryProductArgs, QuerySearchArgs } from "../../../__generated__/schema";
|
|
2
|
+
import type { CategoryTree } from "../clients/commerce/types/CategoryTree";
|
|
3
|
+
import type { Context } from "../index";
|
|
4
4
|
export declare const Query: {
|
|
5
5
|
product: (_: unknown, { locator }: QueryProductArgs, ctx: Context) => Promise<import("../utils/enhanceSku").EnhancedSku>;
|
|
6
6
|
collection: (_: unknown, { slug }: QueryCollectionArgs, ctx: Context) => Promise<import("../clients/commerce/types/Portal").CollectionPageType>;
|
|
@@ -2,6 +2,18 @@ export interface SelectedFacet {
|
|
|
2
2
|
key: string;
|
|
3
3
|
value: string;
|
|
4
4
|
}
|
|
5
|
+
export interface CrossSellingFacet {
|
|
6
|
+
key: keyof typeof FACET_CROSS_SELLING_MAP;
|
|
7
|
+
value: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const FACET_CROSS_SELLING_MAP: {
|
|
10
|
+
readonly buy: "whoboughtalsobought";
|
|
11
|
+
readonly view: "whosawalsosaw";
|
|
12
|
+
readonly similars: "similars";
|
|
13
|
+
readonly viewAndBought: "whosawalsobought";
|
|
14
|
+
readonly accessories: "accessories";
|
|
15
|
+
readonly suggestions: "suggestions";
|
|
16
|
+
};
|
|
5
17
|
/**
|
|
6
18
|
* Transform facets from the store to VTEX platform facets.
|
|
7
19
|
* For instance, the channel in Store becomes trade-policy and regionId in VTEX's realm
|
|
@@ -14,6 +26,8 @@ export declare const transformSelectedFacet: ({ key, value }: SelectedFacet) =>
|
|
|
14
26
|
value: string;
|
|
15
27
|
};
|
|
16
28
|
export declare const parseRange: (range: string) => [number, number] | null;
|
|
29
|
+
export declare const isCrossSelling: (x: string) => x is "similars" | "accessories" | "suggestions" | "buy" | "view" | "viewAndBought";
|
|
30
|
+
export declare const findCrossSelling: (facets?: SelectedFacet[] | null | undefined) => CrossSellingFacet | null;
|
|
17
31
|
export declare const findSlug: (facets?: SelectedFacet[] | null | undefined) => string | null;
|
|
18
32
|
export declare const findSkuId: (facets?: SelectedFacet[] | null | undefined) => string | null;
|
|
19
33
|
export declare const findLocale: (facets?: SelectedFacet[] | null | undefined) => string | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faststore/api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"express-graphql": "^0.12.0",
|
|
38
38
|
"graphql": "^15.6.0",
|
|
39
39
|
"jest-transform-graphql": "^2.1.0",
|
|
40
|
-
"shared": "^1.
|
|
40
|
+
"shared": "^1.10.6",
|
|
41
41
|
"ts-jest": "25.5.1",
|
|
42
42
|
"tsdx": "^0.14.1",
|
|
43
43
|
"tslib": "^2.3.1",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"graphql": "^15.6.0"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "654744a6c3b29afacbd83c4d9ebefe4270d1ae2a"
|
|
50
50
|
}
|
|
@@ -341,8 +341,9 @@ export type StoreFacetRange = {
|
|
|
341
341
|
key: Scalars['String'];
|
|
342
342
|
/** Facet label. */
|
|
343
343
|
label: Scalars['String'];
|
|
344
|
+
/** Maximum facet range value. */
|
|
344
345
|
max: StoreFacetValueRange;
|
|
345
|
-
/**
|
|
346
|
+
/** Minimum facet range value. */
|
|
346
347
|
min: StoreFacetValueRange;
|
|
347
348
|
};
|
|
348
349
|
|
|
@@ -367,9 +368,12 @@ export type StoreFacetValueBoolean = {
|
|
|
367
368
|
value: Scalars['String'];
|
|
368
369
|
};
|
|
369
370
|
|
|
371
|
+
/** Search facet range value information. Used for minimum and maximum range values. */
|
|
370
372
|
export type StoreFacetValueRange = {
|
|
371
373
|
__typename?: 'StoreFacetValueRange';
|
|
374
|
+
/** Search facet range absolute value. */
|
|
372
375
|
absolute: Scalars['Float'];
|
|
376
|
+
/** Search facet range selected value. */
|
|
373
377
|
selected: Scalars['Float'];
|
|
374
378
|
};
|
|
375
379
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FACET_CROSS_SELLING_MAP } from "../../utils/facets"
|
|
2
|
+
import { fetchAPI } from "../fetch"
|
|
3
|
+
import type { PortalProduct } from "./types/Product"
|
|
2
4
|
import type { Context, Options } from '../../index'
|
|
3
5
|
import type { Brand } from './types/Brand'
|
|
4
6
|
import type { CategoryTree } from './types/CategoryTree'
|
|
@@ -13,6 +15,8 @@ import type {
|
|
|
13
15
|
import type { Session } from './types/Session'
|
|
14
16
|
import type { Channel } from '../../utils/channel'
|
|
15
17
|
|
|
18
|
+
type ValueOf<T> = T extends Record<string, infer K> ? K : never;
|
|
19
|
+
|
|
16
20
|
const BASE_INIT = {
|
|
17
21
|
method: 'POST',
|
|
18
22
|
headers: {
|
|
@@ -40,6 +44,24 @@ export const VtexCommerce = (
|
|
|
40
44
|
pagetype: (slug: string): Promise<PortalPagetype> =>
|
|
41
45
|
fetchAPI(`${base}/api/catalog_system/pub/portal/pagetype/${slug}`),
|
|
42
46
|
},
|
|
47
|
+
products: {
|
|
48
|
+
crossselling: (
|
|
49
|
+
{ type, productId, groupByProduct = true }: {
|
|
50
|
+
type: ValueOf<typeof FACET_CROSS_SELLING_MAP>;
|
|
51
|
+
productId: string;
|
|
52
|
+
groupByProduct?: boolean;
|
|
53
|
+
},
|
|
54
|
+
): Promise<PortalProduct[]> => {
|
|
55
|
+
const params = new URLSearchParams({
|
|
56
|
+
sc: ctx.storage.channel.salesChannel,
|
|
57
|
+
groupByProduct: groupByProduct.toString(),
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
return fetchAPI(
|
|
61
|
+
`${base}/api/catalog_system/pub/products/crossselling/${type}/${productId}?${params}`,
|
|
62
|
+
)
|
|
63
|
+
},
|
|
64
|
+
},
|
|
43
65
|
},
|
|
44
66
|
checkout: {
|
|
45
67
|
simulation: (
|
|
@@ -120,7 +142,7 @@ export const VtexCommerce = (
|
|
|
120
142
|
...BASE_INIT,
|
|
121
143
|
body: JSON.stringify({ value }),
|
|
122
144
|
method: 'PUT',
|
|
123
|
-
}
|
|
145
|
+
},
|
|
124
146
|
)
|
|
125
147
|
},
|
|
126
148
|
region: async ({
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
export interface PortalProduct {
|
|
2
|
+
productId: string;
|
|
3
|
+
productName: string;
|
|
4
|
+
brand: string;
|
|
5
|
+
brandId: number;
|
|
6
|
+
brandImageUrl: null | string;
|
|
7
|
+
linkText: string;
|
|
8
|
+
productReference: string;
|
|
9
|
+
productReferenceCode: string;
|
|
10
|
+
categoryId: string;
|
|
11
|
+
productTitle: string;
|
|
12
|
+
metaTagDescription: string;
|
|
13
|
+
releaseDate: Date;
|
|
14
|
+
clusterHighlights: unknown;
|
|
15
|
+
productClusters: unknown;
|
|
16
|
+
searchableClusters: unknown;
|
|
17
|
+
categories: Category[];
|
|
18
|
+
categoriesIds: CategoriesId[];
|
|
19
|
+
link: string;
|
|
20
|
+
description: string;
|
|
21
|
+
items: Item[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
enum Category {
|
|
25
|
+
Office = "/Office/",
|
|
26
|
+
OfficeChairs = "/Office/Chairs/",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
enum CategoriesId {
|
|
30
|
+
The9282 = "/9282/",
|
|
31
|
+
The92829296 = "/9282/9296/",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
interface Item {
|
|
37
|
+
itemId: string;
|
|
38
|
+
name: string;
|
|
39
|
+
nameComplete: string;
|
|
40
|
+
complementName: string;
|
|
41
|
+
ean: string;
|
|
42
|
+
referenceId: ReferenceId[];
|
|
43
|
+
measurementUnit: MeasurementUnit;
|
|
44
|
+
unitMultiplier: number;
|
|
45
|
+
modalType: null;
|
|
46
|
+
isKit: boolean;
|
|
47
|
+
images: Image[];
|
|
48
|
+
sellers: Seller[];
|
|
49
|
+
videos: unknown[];
|
|
50
|
+
estimatedDateArrival: null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface Image {
|
|
54
|
+
imageId: string;
|
|
55
|
+
imageLabel: string;
|
|
56
|
+
imageTag: string;
|
|
57
|
+
imageUrl: string;
|
|
58
|
+
imageText: string;
|
|
59
|
+
imageLastModified: Date;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
enum MeasurementUnit {
|
|
63
|
+
Un = "un",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface ReferenceId {
|
|
67
|
+
key: Key;
|
|
68
|
+
value: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
enum Key {
|
|
72
|
+
RefId = "RefId",
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface Seller {
|
|
76
|
+
sellerId: string;
|
|
77
|
+
sellerName: SellerName;
|
|
78
|
+
addToCartLink: string;
|
|
79
|
+
sellerDefault: boolean;
|
|
80
|
+
commertialOffer: CommertialOffer;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface CommertialOffer {
|
|
84
|
+
deliverySlaSamplesPerRegion: DeliverySlaSamplesPerRegion;
|
|
85
|
+
installments: Installment[];
|
|
86
|
+
discountHighLight: unknown[];
|
|
87
|
+
giftSkuIds: unknown[];
|
|
88
|
+
teasers: unknown[];
|
|
89
|
+
buyTogether: unknown[];
|
|
90
|
+
itemMetadataAttachment: unknown[];
|
|
91
|
+
price: number;
|
|
92
|
+
listPrice: number;
|
|
93
|
+
priceWithoutDiscount: number;
|
|
94
|
+
rewardValue: number;
|
|
95
|
+
priceValidUntil: Date;
|
|
96
|
+
availableQuantity: number;
|
|
97
|
+
isAvailable: boolean;
|
|
98
|
+
tax: number;
|
|
99
|
+
deliverySlaSamples: DeliverySlaSample[];
|
|
100
|
+
getInfoErrorMessage: null;
|
|
101
|
+
cacheVersionUsedToCallCheckout: string;
|
|
102
|
+
paymentOptions: PaymentOptions;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface DeliverySlaSample {
|
|
106
|
+
deliverySlaPerTypes: unknown[];
|
|
107
|
+
region: null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface DeliverySlaSamplesPerRegion {
|
|
111
|
+
the0: DeliverySlaSample;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
interface Installment {
|
|
115
|
+
value: number;
|
|
116
|
+
interestRate: number;
|
|
117
|
+
totalValuePlusInterestRate: number;
|
|
118
|
+
numberOfInstallments: number;
|
|
119
|
+
paymentSystemName: PaymentSystemNameEnum;
|
|
120
|
+
paymentSystemGroupName: GroupName;
|
|
121
|
+
name: Name;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
enum Name {
|
|
125
|
+
BoletoBancárioÀVista = "Boleto Bancário à vista",
|
|
126
|
+
FreeÀVista = "Free à vista",
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
enum GroupName {
|
|
130
|
+
BankInvoicePaymentGroup = "bankInvoicePaymentGroup",
|
|
131
|
+
Custom201PaymentGroupPaymentGroup = "custom201PaymentGroupPaymentGroup",
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
enum PaymentSystemNameEnum {
|
|
135
|
+
BoletoBancário = "Boleto Bancário",
|
|
136
|
+
Free = "Free",
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
interface PaymentOptions {
|
|
140
|
+
installmentOptions: InstallmentOption[];
|
|
141
|
+
paymentSystems: PaymentSystem[];
|
|
142
|
+
payments: unknown[];
|
|
143
|
+
giftCards: unknown[];
|
|
144
|
+
giftCardMessages: unknown[];
|
|
145
|
+
availableAccounts: unknown[];
|
|
146
|
+
availableTokens: unknown[];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
interface InstallmentOption {
|
|
150
|
+
paymentSystem: string;
|
|
151
|
+
bin: null;
|
|
152
|
+
paymentName: PaymentSystemNameEnum;
|
|
153
|
+
paymentGroupName: GroupName;
|
|
154
|
+
value: number;
|
|
155
|
+
installments: InstallmentElement[];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
interface InstallmentElement {
|
|
159
|
+
count: number;
|
|
160
|
+
hasInterestRate: boolean;
|
|
161
|
+
interestRate: number;
|
|
162
|
+
value: number;
|
|
163
|
+
total: number;
|
|
164
|
+
sellerMerchantInstallments?: InstallmentElement[];
|
|
165
|
+
id?: Id;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
enum Id {
|
|
169
|
+
Storeframework = "STOREFRAMEWORK",
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
interface PaymentSystem {
|
|
173
|
+
id: number;
|
|
174
|
+
name: PaymentSystemNameEnum;
|
|
175
|
+
groupName: GroupName;
|
|
176
|
+
validator: null;
|
|
177
|
+
stringId: string;
|
|
178
|
+
template: Template;
|
|
179
|
+
requiresDocument: boolean;
|
|
180
|
+
isCustom: boolean;
|
|
181
|
+
description: Description | null;
|
|
182
|
+
requiresAuthentication: boolean;
|
|
183
|
+
dueDate: Date;
|
|
184
|
+
availablePayments: null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
enum Description {
|
|
188
|
+
FreePayToTestCheckoutPayments = "Free pay to test checkout payments",
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
enum Template {
|
|
192
|
+
BankInvoicePaymentGroupTemplate = "bankInvoicePaymentGroup-template",
|
|
193
|
+
Custom201PaymentGroupPaymentGroupTemplate =
|
|
194
|
+
"custom201PaymentGroupPaymentGroup-template",
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
enum SellerName {
|
|
198
|
+
Vtex = "VTEX",
|
|
199
|
+
}
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { FACET_CROSS_SELLING_MAP } from "./../utils/facets"
|
|
2
|
+
import { BadRequestError, NotFoundError } from "../../errors"
|
|
3
|
+
import { mutateChannelContext, mutateLocaleContext } from "../utils/contex"
|
|
4
|
+
import { enhanceSku } from "../utils/enhanceSku"
|
|
4
5
|
import {
|
|
5
6
|
findChannel,
|
|
7
|
+
findCrossSelling,
|
|
6
8
|
findLocale,
|
|
7
9
|
findSkuId,
|
|
8
10
|
findSlug,
|
|
9
11
|
transformSelectedFacet,
|
|
10
|
-
} from
|
|
11
|
-
import { SORT_MAP } from
|
|
12
|
-
import { StoreCollection } from
|
|
12
|
+
} from "../utils/facets"
|
|
13
|
+
import { SORT_MAP } from "../utils/sort"
|
|
14
|
+
import { StoreCollection } from "./collection"
|
|
13
15
|
import type {
|
|
14
|
-
QueryProductArgs,
|
|
15
16
|
QueryAllCollectionsArgs,
|
|
16
17
|
QueryAllProductsArgs,
|
|
17
|
-
QuerySearchArgs,
|
|
18
18
|
QueryCollectionArgs,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import {
|
|
19
|
+
QueryProductArgs,
|
|
20
|
+
QuerySearchArgs,
|
|
21
|
+
} from "../../../__generated__/schema"
|
|
22
|
+
import type { CategoryTree } from "../clients/commerce/types/CategoryTree"
|
|
23
|
+
import type { Context } from "../index"
|
|
24
|
+
import { isValidSkuId, pickBestSku } from "../utils/sku"
|
|
23
25
|
|
|
24
26
|
export const Query = {
|
|
25
27
|
product: async (_: unknown, { locator }: QueryProductArgs, ctx: Context) => {
|
|
@@ -95,6 +97,7 @@ export const Query = {
|
|
|
95
97
|
// Insert channel in context for later usage
|
|
96
98
|
const channel = findChannel(selectedFacets)
|
|
97
99
|
const locale = findLocale(selectedFacets)
|
|
100
|
+
const crossSelling = findCrossSelling(selectedFacets)
|
|
98
101
|
|
|
99
102
|
if (channel) {
|
|
100
103
|
mutateChannelContext(ctx, channel)
|
|
@@ -104,11 +107,33 @@ export const Query = {
|
|
|
104
107
|
mutateLocaleContext(ctx, locale)
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
let query = term
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* In case we are using crossSelling, we need to modify the search
|
|
114
|
+
* we will be performing on our search engine. The idea in here
|
|
115
|
+
* is to use the cross selling API for fetching the productIds our
|
|
116
|
+
* search will return for us.
|
|
117
|
+
* Doing this two request workflow makes it possible to have cross
|
|
118
|
+
* selling with Search features, like pagination, internationalization
|
|
119
|
+
* etc
|
|
120
|
+
*/
|
|
121
|
+
if (crossSelling) {
|
|
122
|
+
const products = await ctx.clients.commerce.catalog.products.crossselling({
|
|
123
|
+
type: FACET_CROSS_SELLING_MAP[crossSelling.key],
|
|
124
|
+
productId: crossSelling.value,
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
query = `product:${
|
|
128
|
+
products.map((x) => x.productId).slice(0, first).join(";")
|
|
129
|
+
}`
|
|
130
|
+
}
|
|
131
|
+
|
|
107
132
|
const after = maybeAfter ? Number(maybeAfter) : 0
|
|
108
133
|
const searchArgs = {
|
|
109
|
-
page: Math.ceil(after / first
|
|
134
|
+
page: Math.ceil(after / first),
|
|
110
135
|
count: first,
|
|
111
|
-
query
|
|
136
|
+
query,
|
|
112
137
|
sort: SORT_MAP[sort ?? 'score_desc'],
|
|
113
138
|
selectedFacets: selectedFacets?.flatMap(transformSelectedFacet) ?? [],
|
|
114
139
|
}
|