@nuskin/ns-product-lib 2.11.0 → 2.13.0-cx24-5107.1

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ # [2.13.0-cx24-5107.1](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.12.0...v2.13.0-cx24-5107.1) (2023-09-28)
2
+
3
+
4
+ ### Fix
5
+
6
+ * directory issue on jest ([41f8afa](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/41f8afa725923b472e33da741874e7ae9feeea73))
7
+ * file directory issue ([568d935](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/568d935f7575dfe18a33cd430d01e17ed3020080))
8
+ * kit and bundle ([5a4f13d](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/5a4f13d10ab87fa5ebfbe549ecb3df0c803f2296))
9
+ * linter ([1bf15af](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/1bf15afee64c0db411e794c5c3181ecbcbf64893))
10
+ * linter error (#CX24-5107) ([03f5abc](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/03f5abcd4940a91c2c04665b24e460813894eeba)), closes [#CX24-5107](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-5107)
11
+ * multi variants ([33ccfdd](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/33ccfdd979e4c229e82814e8b3a0aa93c7a1e14a))
12
+ * odd space in require ([f242b4d](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/f242b4dc696de968607b3c14340c60c3e7baa898))
13
+ * remove old code ([461e70e](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/461e70e1a4d5b1507c940a32bd6c645d5e3f8fef))
14
+ * sonar qube issue ([461a4b9](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/461a4b9007390608ba99b182ef698cc0cd1922cc))
15
+ * unit testing ([cda18ce](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/cda18ce61a0e411df889a2d2939898c54aba6c36))
16
+ * unitest issue in pipeline ([48b99f3](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/48b99f375d1f357f6c5e906a00a09f3ad31042e4))
17
+
18
+ ### Update
19
+
20
+ * use graphql for product data (#CX24-5092) ([9e13973](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/9e139736e08eea59707164dec78ee4dc9542d4ec)), closes [#CX24-5092](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-5092)
21
+
22
+ # [2.12.0](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.11.0...v2.12.0) (2023-09-22)
23
+
24
+
25
+ ### Update
26
+
27
+ * added subscription price flag to product (CX16-10044) ([341cb81](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/341cb81a15a70121f2370eb59913d0c77f0066b9))
28
+
1
29
  # [2.11.0](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.10.1...v2.11.0) (2023-09-18)
2
30
 
3
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/ns-product-lib",
3
- "version": "2.11.0",
3
+ "version": "2.13.0-cx24-5107.1",
4
4
  "description": "This project contains shared Product models and code between the backend and frontend.",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ const CustomerTypes = {
4
+ BrandAffiliate: "BrandAffiliate",
5
+ Preferred: "Preferred",
6
+ PreferredCustomer: "Preferred Customer",
7
+ Retail: "Retail",
8
+ properties: {
9
+ BRAND_AFFILIATE: { stringKey: "DIST", code: 10 },
10
+ RETAIL: { stringKey: "CUST", code: 20 },
11
+ PREFERRED: { stringKey: "preferred", code: 30 },
12
+ PREFERRED_CUSTOMER: { stringKey: "PREF", code: 30 }
13
+ }
14
+ };
15
+
16
+ module.exports = CustomerTypes;
@@ -0,0 +1,32 @@
1
+ const { getEnvironmentFromUrl } = require('@nuskin/ns-common-lib');
2
+
3
+ const config = {
4
+ dev: {
5
+ url: 'https://test.nuskin.com/product-api/graphql',
6
+ env: 'dev'
7
+ },
8
+ test: {
9
+ url: 'https://test.nuskin.com/product-api/graphql',
10
+ env: 'test'
11
+ },
12
+ prod: {
13
+ url: 'https://nuskin.com/product-api/graphql',
14
+ env: 'public'
15
+ }
16
+ };
17
+
18
+ /**
19
+ * Get product-api graphQL base URL based on web URL
20
+ * @returns {string} baseUrl (default: prod env url )
21
+ */
22
+ function graphQlUrl () {
23
+ const env = getEnvironmentFromUrl(window.location.host);
24
+
25
+ if (!config[env]) {
26
+ return config['prod'].url;
27
+ }
28
+
29
+ return config[env].url;
30
+ }
31
+
32
+ module.exports = graphQlUrl;
@@ -0,0 +1,7 @@
1
+ const getProduct = require('./product');
2
+ const graphQlUrl = require('./graphQlUrl');
3
+
4
+ module.exports = {
5
+ getProduct,
6
+ getGraphQlUrl: graphQlUrl
7
+ }
@@ -0,0 +1,415 @@
1
+ const axios = require('axios');
2
+ const { getProductByIdQuery } = require('./query');
3
+ const getGraphQlUrl = require('./graphQlUrl')
4
+ const ProductStatus = require("../models/productStatus");
5
+ const CustomerTypes = require('./customerTypes');
6
+
7
+ const defaultPayload = {
8
+ operationName: "getProduct",
9
+ useContentSource: "CS"
10
+ };
11
+
12
+ /**
13
+ * graphQl Http request
14
+ * @param {obj} payload
15
+ * @returns {Promise}
16
+ */
17
+ const graphQlHttpRequest = (payload) => {
18
+ const url = getGraphQlUrl();
19
+ return axios.request({
20
+ method: 'post',
21
+ url: url,
22
+ data: payload,
23
+ responseType: 'json'
24
+ });
25
+
26
+ }
27
+
28
+ /**
29
+ * Get product by ID
30
+ * @todo map promotions coming from promotions API
31
+ * @param {string} id
32
+ * @param {string} market
33
+ * @param {string} locale
34
+ * @param {obj} config
35
+ */
36
+ async function getProduct(id, market, locale, config) {
37
+
38
+ const productData = {
39
+ products: [],
40
+ count: 0
41
+ };
42
+
43
+ const payload = {
44
+ ...defaultPayload,
45
+ query: getProductByIdQuery,
46
+ variables: { id, market, locale }
47
+ }
48
+
49
+ try {
50
+ const { data } = await graphQlHttpRequest(payload);
51
+ const product = mapProduct(data.productById, market, locale, config);
52
+ productData.products.push(product);
53
+ } catch (e) {
54
+ console.log(e);
55
+ }
56
+
57
+ return {
58
+ data: {
59
+ "status": 200,
60
+ "messages": [],
61
+ "data": productData
62
+ }
63
+ };
64
+ }
65
+
66
+ /**
67
+ *
68
+ * Map product data to be product card consumable structure *
69
+ * @param {object} product
70
+ * @param {string} market
71
+ * @param {string} locale
72
+ * @param {object} config
73
+ * @returns {object} Product
74
+ */
75
+ function mapProduct(product, market, locale, config) {
76
+ const kitBundleProducts = product.bundle;
77
+ let variants = product.variants || [];
78
+
79
+ const promotions = getPromotions(config);
80
+
81
+ if (kitBundleProducts) {
82
+
83
+ //merge kitBundleProducts and bundle attribute level
84
+ //since bundle level has totalPrice,availableChannels, etc
85
+ variants.push({
86
+ ...product,
87
+ ...kitBundleProducts,
88
+ productDetails: {
89
+ description: product.description
90
+ }
91
+ });
92
+ }
93
+
94
+ //serves as parent
95
+ const defaultVariant = variants[0];
96
+ const productDetail = {
97
+ "sku": defaultVariant.sku || product.id,
98
+ "globalProductID":product.id,
99
+ "title": defaultVariant.title,
100
+ "country": market,
101
+ "language": locale,
102
+ "shortDescr": defaultVariant.description,
103
+ "longDescr": defaultVariant.productDetails.description,
104
+ "fullImage": defaultVariant.productImages[0].url,
105
+ "imageAltText": defaultVariant.productImages[0].alt,
106
+ "thumbnail": defaultVariant.productImages[0].thumbnail,
107
+ "ingredients": defaultVariant.ingredients,
108
+ "benefits": defaultVariant.benefits,
109
+ "usage": defaultVariant.usage,
110
+ "resources": defaultVariant.resoruces,
111
+ "availableQuantity": defaultVariant.availableQuantity,
112
+ "maxQuantity": defaultVariant.maxQuantity,
113
+ "points": "",
114
+ "cv": (defaultVariant.points) ? defaultVariant.points.wholesale.cv : 0,
115
+ "pv": (defaultVariant.points) ? defaultVariant.points.wholesale.pv : 0,
116
+ "priceType": "WRTL",
117
+ "price": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.retail : defaultVariant.price.retail,
118
+ "priceMap": {
119
+ "WRTL": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.retail : defaultVariant.price.retail,
120
+ "WADW-WRTL": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.retailSubscription : defaultVariant.price.retail,
121
+ "WADR": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.retailSubscription : defaultVariant.price.retailSubscription, //retail ADR (subscription) price
122
+ "RTL": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.retail : defaultVariant.price.retail,
123
+ "WWHL": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.wholesale : defaultVariant.price.wholesale,
124
+ "WADW": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.wholesaleSubscription : defaultVariant.price.wholesaleSubscription,//wholesale ADR (subscription price)
125
+ "WHL": (defaultVariant.totalPrice) ? defaultVariant.totalPrice.wholesale : defaultVariant.price.wholesale
126
+ },
127
+ "cvMap": {
128
+ "WWHL": (defaultVariant.points) ? defaultVariant.points.wholesale.cv : 0,
129
+ "WADW": (defaultVariant.points) ? defaultVariant.points.subscription.cv : 0,
130
+ "WHL": (defaultVariant.points) ? defaultVariant.points.wholesale.cv : 0
131
+ },
132
+ "pvMap": {
133
+ "WWHL": (defaultVariant.points) ? defaultVariant.points.wholesale.pv : 0,
134
+ "WADW": (defaultVariant.points) ? defaultVariant.points.subscription.pv : 0,
135
+ "WHL": (defaultVariant.points) ? defaultVariant.points.wholesale.pv : 0
136
+ },
137
+ "orderTypes": mapOrderTypes(defaultVariant.availableChannels, defaultVariant.purchaseTypes),
138
+ "custTypes": mapCustomerTypes(defaultVariant.customerTypes),
139
+ "backOrderDate": defaultVariant.status.backorderedAvailableDate,
140
+ "size": defaultVariant.size,
141
+ "status": mapProductStatus(defaultVariant.status.status),
142
+ "variantType": "Other",
143
+ "variantDropdownLabel": product.variantSelectLabel || '',
144
+ "variantDropdownPlaceholder": "Select Type",
145
+ "variantsLabel": defaultVariant.variantLabel || '',
146
+ "groupOffer": false,
147
+ "personalOffer": false,
148
+ "savedEventName": '',
149
+ "salesLabel": '',
150
+ "eventName": promotions,
151
+ "sizeWeight": '',
152
+ "nettoWeight": "",
153
+ "searchScore": 0,
154
+ "isExclusive": defaultVariant.isExclusive || false,
155
+ "equinoxProductId": product.id,
156
+ "properties": {}
157
+
158
+ }
159
+
160
+ if (variants) {
161
+ productDetail.variants = mapVariants(product);
162
+ }
163
+
164
+ if (kitBundleProducts) {
165
+
166
+ //assemble childSku
167
+ //1st elememt should be parent product
168
+ productDetail.childSkus = [
169
+ {
170
+ availableChannels: kitBundleProducts.availableChannels,
171
+ productId: product.id,
172
+ skuId: product.id,
173
+ type: kitBundleProducts.type
174
+ },
175
+ ...mapChildSKU(kitBundleProducts)
176
+ ];
177
+ }
178
+
179
+ return productDetail;
180
+ }
181
+
182
+ /**
183
+ * Map product variants
184
+ * @param {*} product
185
+ * @returns {Array<object>} productVariants
186
+ */
187
+ function mapVariants(product) {
188
+
189
+ //return if it is not multi variant
190
+ if (!product.variants || (product.variants && product.variants.length === 1)) {
191
+ return [];
192
+ }
193
+
194
+ const variants = [];
195
+
196
+ product.variants.forEach(variant => {
197
+ const sku = variant.sku || variant.id;
198
+ variants[sku] = {
199
+ "sku": sku,
200
+ "globalProductID": product.id || variant.globalId,
201
+ "title": variant.title,
202
+ "shortDescr": variant.description,
203
+ "longDescr": variant.productDetails.description,
204
+ "fullImage": variant.productImages[0].url,
205
+ "imageAltText": variant.productImages[0].alt,
206
+ "thumbnail": variant.productImages[0].thumbnail,
207
+ "ingredients": variant.ingredients,
208
+ "benefits": variant.benefits,
209
+ "usage": variant.usage,
210
+ "resources": variant.resoruces,
211
+ "availableQuantity": variant.availableQuantity,
212
+ "maxQuantity": variant.maxQuantity,
213
+ "points": "",
214
+ "cv": (variant.points) ? variant.points.wholesale.cv : 0,
215
+ "pv": (variant.points) ? variant.points.wholesale.pv : 0,
216
+ "priceType": "WRTL",
217
+ "price": (variant.totalPrice) ? variant.totalPrice.retail : variant.price.retail,
218
+ "priceMap": {
219
+ "WRTL": (variant.totalPrice) ? variant.totalPrice.retail : variant.price.retail,
220
+ "WADW-WRTL": (variant.totalPrice) ? variant.totalPrice.retailSubscription : variant.price.retail,
221
+ "WADR": (variant.totalPrice) ? variant.totalPrice.retailSubscription : variant.price.retailSubscription, //retail ADR (subscription) price
222
+ "RTL": (variant.totalPrice) ? variant.totalPrice.retail : variant.price.retail,
223
+ "WWHL": (variant.totalPrice) ? variant.totalPrice.wholesale : variant.price.wholesale,
224
+ "WADW": (variant.totalPrice) ? variant.totalPrice.wholesaleSubscription : variant.price.wholesaleSubscription,//wholesale ADR (subscription price)
225
+ "WHL": (variant.totalPrice) ? variant.totalPrice.wholesale : variant.price.wholesale
226
+ },
227
+ "cvMap": {
228
+ "WWHL": (variant.points) ? variant.points.wholesale.cv : 0,
229
+ "WADW": (variant.points) ? variant.points.subscription.cv : 0,
230
+ "WHL": (variant.points) ? variant.points.wholesale.cv : 0
231
+ },
232
+ "pvMap": {
233
+ "WWHL": (variant.points) ? variant.points.wholesale.pv : 0,
234
+ "WADW": (variant.points) ? variant.points.subscription.pv : 0,
235
+ "WHL": (variant.points) ? variant.points.wholesale.pv : 0
236
+ },
237
+ "orderTypes": mapOrderTypes(variant.availableChannels, variant.purchaseTypes),
238
+ "custTypes": mapCustomerTypes(variant.customerTypes),
239
+ "backOrderDate": variant.status.backorderedAvailableDate,
240
+ "size": variant.size,
241
+ "status": mapProductStatus(variant.status.status),
242
+ "variantType": "Other",
243
+ "variantDropdownLabel": product.variantSelectLabel || '',
244
+ "variantDropdownPlaceholder": "Select Type",
245
+ "variantsLabel": variant.variantLabel || '',
246
+ "variants": [],
247
+ "groupOffer": false,
248
+ "personalOffer": false,
249
+ "savedEventName": '',
250
+ "salesLabel": '',
251
+ "eventName": '',
252
+ "sizeWeight": '',
253
+ "nettoWeight": "",
254
+ "searchScore": 0,
255
+ "isExclusive": variant.isExclusive || false,
256
+ "equinoxProductId": product.id,
257
+ "properties": {}
258
+ }
259
+ });
260
+
261
+ return variants;
262
+ }
263
+
264
+ /**
265
+ * Get promotions
266
+ * @todo use promotions API
267
+ * @param {*} config
268
+ * @returns {object} promotion
269
+ */
270
+ function getPromotions(config) {
271
+ console.log(`config `, config);
272
+ return 'event-name';
273
+ }
274
+
275
+ /**
276
+ * map product kit bundle child SKUs
277
+ * @param {*} kitBundleProducts
278
+ * @returns {array} kitBundleProducts
279
+ */
280
+ function mapChildSKU(kitBundleProducts) {
281
+ if (!kitBundleProducts || !kitBundleProducts.kitProducts) {
282
+ return [];
283
+ }
284
+
285
+ return kitBundleProducts.kitProducts.map((kitProduct) => {
286
+ const { product } = kitProduct;
287
+ const defaultVariant = product.variants[0];
288
+ return {
289
+ productId: product.id,
290
+ skuId: defaultVariant.sku,
291
+ type: 'MANDATORY',
292
+ skuQuantity: kitProduct.quantity,
293
+ availableChannels: kitBundleProducts.availableChannels,
294
+ inventory: {
295
+ atpQty: defaultVariant.availableQuantity,
296
+ backOrdered: defaultVariant.status.isBackordered,
297
+ backOrderedQty: defaultVariant.availableQuantity
298
+ }
299
+ }
300
+ });
301
+ }
302
+
303
+ /**
304
+ * map EQ customer types to supported product card customer types
305
+ * @param {Array<string>} eqCustomerTypes
306
+ * @returns{string} customer types
307
+ */
308
+ function mapCustomerTypes(eqCustomerTypes) {
309
+ if (!eqCustomerTypes) {
310
+ return "";
311
+ }
312
+
313
+ const custTypes = eqCustomerTypes;
314
+
315
+ let newCustType = [];
316
+ if (custTypes.includes(CustomerTypes.BrandAffiliate)) {
317
+ newCustType.push(CustomerTypes.properties.BRAND_AFFILIATE.code);
318
+ }
319
+
320
+ if (custTypes.includes(CustomerTypes.Retail)) {
321
+ newCustType.push(CustomerTypes.properties.RETAIL.code);
322
+ }
323
+
324
+ if (custTypes.includes(CustomerTypes.Preferred) || custTypes.includes(CustomerTypes.PreferredCustomer)) {
325
+ newCustType.push(CustomerTypes.properties.PREFERRED.code);
326
+ }
327
+
328
+ return newCustType.toString()
329
+ }
330
+
331
+ /**
332
+ * Map Order Types
333
+ * @param {Array<string>} availableChannels
334
+ * @param {object} purchaseTypes
335
+ * @returns {object} orderTypes
336
+ */
337
+ function mapOrderTypes(availableChannels, purchaseTypes) {
338
+
339
+ let orderTypes = {
340
+ "adr": false,
341
+ "order": false,
342
+ "zpfc": false,
343
+ "zadp": false,
344
+ "ars": false,
345
+ "kiosk": false,
346
+ "mobile": false,
347
+ "preferred customer": false,
348
+ "retail": false,
349
+ "web": false,
350
+ "web display": false
351
+ };
352
+
353
+ if (availableChannels) {
354
+ let availableChannelsArr = Array.isArray(availableChannels) ? availableChannels : availableChannels.split(',');
355
+
356
+ availableChannelsArr.forEach(channel => {
357
+ if (channel == 'arsPhone')
358
+ orderTypes.ars = true
359
+ if (channel == 'web') {
360
+ orderTypes.order = true
361
+ orderTypes.web = true
362
+ }
363
+ if (channel == 'kiosk')
364
+ orderTypes.kiosk = true
365
+ if (channel == 'mobile')
366
+ orderTypes.mobile = true
367
+ if (channel == 'subscription')
368
+ orderTypes.adr = true
369
+ });
370
+ }
371
+
372
+ if (purchaseTypes && purchaseTypes.buyOnce) {
373
+ orderTypes.web = true
374
+ orderTypes.order = true
375
+ }
376
+ if (purchaseTypes && purchaseTypes.subscription) {
377
+ orderTypes.adr = true
378
+ }
379
+
380
+ return orderTypes;
381
+ }
382
+
383
+ /**
384
+ * Map product status from Equinox format to Product card format
385
+ * @param {string} status
386
+ * @returns {string} status
387
+ */
388
+ function mapProductStatus (status) {
389
+ const { equinoxStatus } = ProductStatus;
390
+ let newStatus = '';
391
+ switch (status.toLowerCase()) {
392
+ case equinoxStatus.SELLABLE:
393
+ newStatus = ProductStatus.ReleasedForSale;
394
+ break;
395
+ case equinoxStatus.PREVIEW_PRODUCT:
396
+ newStatus = ProductStatus.NotReleasedForSale;
397
+ break;
398
+ case equinoxStatus.DISCONTINUED:
399
+ newStatus = ProductStatus.Discontinued;
400
+ break;
401
+ case equinoxStatus.STOPPED:
402
+ newStatus = ProductStatus.Discontinued;
403
+ break;
404
+ case equinoxStatus.REPLACEMENT:
405
+ newStatus = ProductStatus.NotReleasedForSale;
406
+ break;
407
+ default:
408
+ newStatus = ProductStatus.NotReleasedForSale;
409
+ break;
410
+ }
411
+
412
+ return newStatus;
413
+ }
414
+
415
+ module.exports = getProduct;
@@ -0,0 +1,535 @@
1
+ "use strict";
2
+
3
+ // eslint-disable-next-line max-len
4
+ const getProductByIdQuery = `query getProduct($id: String!, $market: String, $language: String, $useContentSource: String, $okta: String) {
5
+ productById(
6
+ id: $id
7
+ market: $market
8
+ language: $language
9
+ useContentSource: $useContentSource
10
+ okta: $okta
11
+ ) {
12
+ ...Product
13
+ bundle {
14
+ ...Kit
15
+ __typename
16
+ }
17
+ __typename
18
+ }
19
+ }
20
+
21
+ fragment Product on Product {
22
+ id
23
+ slug
24
+ title
25
+ secondaryTitle
26
+ productImages {
27
+ url
28
+ alt
29
+ thumbnail
30
+ __typename
31
+ }
32
+ salesLabel
33
+ salesText
34
+ description
35
+ salesDisclaimer
36
+ variantSelectLabel
37
+ variants {
38
+ ...Variant
39
+ __typename
40
+ }
41
+ features {
42
+ image {
43
+ url
44
+ alt
45
+ thumbnail
46
+ __typename
47
+ }
48
+ subtitle
49
+ features
50
+ backgroundColor
51
+ textColor
52
+ __typename
53
+ }
54
+ productDetails {
55
+ description
56
+ includedItems
57
+ highlights {
58
+ iconUrl
59
+ label
60
+ __typename
61
+ }
62
+ originCountry
63
+ importer
64
+ warnings
65
+ __typename
66
+ }
67
+ benefits {
68
+ benefits
69
+ image {
70
+ url
71
+ alt
72
+ thumbnail
73
+ __typename
74
+ }
75
+ youTubeVideoId
76
+ __typename
77
+ }
78
+ results {
79
+ summary
80
+ results {
81
+ percentage
82
+ text
83
+ __typename
84
+ }
85
+ report {
86
+ url
87
+ text
88
+ __typename
89
+ }
90
+ image {
91
+ url
92
+ alt
93
+ thumbnail
94
+ __typename
95
+ }
96
+ youTubeVideoId
97
+ __typename
98
+ }
99
+ sustainability {
100
+ youTubeVideoId
101
+ image {
102
+ url
103
+ __typename
104
+ }
105
+ description
106
+ highlights {
107
+ image {
108
+ url
109
+ __typename
110
+ }
111
+ description
112
+ __typename
113
+ }
114
+ __typename
115
+ }
116
+ usage {
117
+ steps
118
+ recommendations
119
+ warnings
120
+ additionalText
121
+ image {
122
+ url
123
+ alt
124
+ thumbnail
125
+ __typename
126
+ }
127
+ youTubeVideoId
128
+ markdown
129
+ __typename
130
+ }
131
+ resources {
132
+ title
133
+ url
134
+ image {
135
+ url
136
+ alt
137
+ thumbnail
138
+ __typename
139
+ }
140
+ __typename
141
+ }
142
+ warranty
143
+ faqs {
144
+ question
145
+ answers
146
+ __typename
147
+ }
148
+ ingredients {
149
+ productName
150
+ allIngredients
151
+ otherIngredients
152
+ activeIngredients
153
+ inactiveIngredients
154
+ ingredientDisclaimers
155
+ markdown
156
+ keyIngredients {
157
+ image {
158
+ url
159
+ alt
160
+ thumbnail
161
+ __typename
162
+ }
163
+ name
164
+ description
165
+ __typename
166
+ }
167
+ nutritionInformationImage {
168
+ url
169
+ alt
170
+ __typename
171
+ }
172
+ __typename
173
+ }
174
+ disclaimers
175
+ disclaimerWarnings {
176
+ icon {
177
+ url
178
+ alt
179
+ __typename
180
+ }
181
+ markdown
182
+ __typename
183
+ }
184
+ seoInformation {
185
+ metaDescription
186
+ metaTitle
187
+ canonicalURL
188
+ ogImage {
189
+ url
190
+ alt
191
+ __typename
192
+ }
193
+ __typename
194
+ }
195
+ thirdPartyScripts
196
+ productDataSource {
197
+ source
198
+ webBaseUrl
199
+ apiBaseUrl
200
+ storeId
201
+ __typename
202
+ }
203
+ error {
204
+ name
205
+ errors
206
+ lines
207
+ message
208
+ status
209
+ __typename
210
+ }
211
+ upSellProductIds
212
+ crossProductIds
213
+ __typename
214
+ }
215
+
216
+ fragment Variant on Variant {
217
+ sku
218
+ globalId
219
+ slug
220
+ variantLabel
221
+ variantColor
222
+ availableChannels
223
+ availableQuantity
224
+ customerTypes
225
+ maxQuantity
226
+ title
227
+ size
228
+ productImages {
229
+ url
230
+ alt
231
+ thumbnail
232
+ __typename
233
+ }
234
+ salesLabel
235
+ salesText
236
+ description
237
+ salesDisclaimer
238
+ nettoWeight
239
+ features {
240
+ image {
241
+ url
242
+ alt
243
+ thumbnail
244
+ __typename
245
+ }
246
+ subtitle
247
+ features
248
+ backgroundColor
249
+ textColor
250
+ __typename
251
+ }
252
+ productDetails {
253
+ description
254
+ includedItems
255
+ highlights {
256
+ iconUrl
257
+ label
258
+ __typename
259
+ }
260
+ originCountry
261
+ importer
262
+ warnings
263
+ __typename
264
+ }
265
+ benefits {
266
+ benefits
267
+ image {
268
+ url
269
+ alt
270
+ thumbnail
271
+ __typename
272
+ }
273
+ youTubeVideoId
274
+ __typename
275
+ }
276
+ results {
277
+ summary
278
+ results {
279
+ percentage
280
+ text
281
+ __typename
282
+ }
283
+ report {
284
+ url
285
+ text
286
+ __typename
287
+ }
288
+ image {
289
+ url
290
+ alt
291
+ thumbnail
292
+ __typename
293
+ }
294
+ youTubeVideoId
295
+ __typename
296
+ }
297
+ usage {
298
+ steps
299
+ recommendations
300
+ warnings
301
+ additionalText
302
+ image {
303
+ url
304
+ alt
305
+ thumbnail
306
+ __typename
307
+ }
308
+ youTubeVideoId
309
+ markdown
310
+ __typename
311
+ }
312
+ resources {
313
+ title
314
+ url
315
+ image {
316
+ url
317
+ alt
318
+ thumbnail
319
+ __typename
320
+ }
321
+ __typename
322
+ }
323
+ faqs {
324
+ question
325
+ answers
326
+ __typename
327
+ }
328
+ ingredients {
329
+ productName
330
+ allIngredients
331
+ otherIngredients
332
+ activeIngredients
333
+ inactiveIngredients
334
+ ingredientDisclaimers
335
+ markdown
336
+ keyIngredients {
337
+ image {
338
+ url
339
+ alt
340
+ thumbnail
341
+ __typename
342
+ }
343
+ name
344
+ description
345
+ __typename
346
+ }
347
+ nutritionInformationImage {
348
+ url
349
+ alt
350
+ __typename
351
+ }
352
+ __typename
353
+ }
354
+ isExclusive
355
+ price {
356
+ retail
357
+ wholesale
358
+ retailSales
359
+ wholesaleSales
360
+ retailSubscription
361
+ wholesaleSubscription
362
+ currencyCode
363
+ __typename
364
+ }
365
+ totalPrice {
366
+ retail
367
+ wholesale
368
+ retailSales
369
+ wholesaleSales
370
+ retailSubscription
371
+ wholesaleSubscription
372
+ currencyCode
373
+ __typename
374
+ }
375
+ points {
376
+ wholesale {
377
+ cv
378
+ pv
379
+ __typename
380
+ }
381
+ subscription {
382
+ cv
383
+ pv
384
+ __typename
385
+ }
386
+ __typename
387
+ }
388
+ totalPoints {
389
+ wholesale {
390
+ cv
391
+ pv
392
+ __typename
393
+ }
394
+ subscription {
395
+ cv
396
+ pv
397
+ __typename
398
+ }
399
+ __typename
400
+ }
401
+ pricingJson
402
+ availableQuantity
403
+ maxQuantity
404
+ status {
405
+ isBackordered
406
+ backorderedAvailableDate
407
+ status
408
+ __typename
409
+ }
410
+ purchaseTypes {
411
+ buyOnce
412
+ subscription
413
+ __typename
414
+ }
415
+ marketAttributes {
416
+ redeem
417
+ earn
418
+ __typename
419
+ }
420
+ disclaimers
421
+ disclaimerWarnings {
422
+ icon {
423
+ url
424
+ alt
425
+ __typename
426
+ }
427
+ markdown
428
+ __typename
429
+ }
430
+ restrictedMarkets
431
+ matchingVariant
432
+ shadeable
433
+ productType
434
+ primaryBrand
435
+ brandFamily
436
+ __typename
437
+ }
438
+
439
+ fragment Kit on Kit {
440
+ id
441
+ type
442
+ price {
443
+ currencyCode
444
+ retail
445
+ wholesale
446
+ retailSales
447
+ wholesaleSales
448
+ retailSubscription
449
+ wholesaleSubscription
450
+ __typename
451
+ }
452
+ totalPrice {
453
+ currencyCode
454
+ retail
455
+ wholesale
456
+ retailSales
457
+ wholesaleSales
458
+ retailSubscription
459
+ wholesaleSubscription
460
+ __typename
461
+ }
462
+ points {
463
+ wholesale {
464
+ cv
465
+ pv
466
+ __typename
467
+ }
468
+ subscription {
469
+ cv
470
+ pv
471
+ __typename
472
+ }
473
+ __typename
474
+ }
475
+ totalPoints {
476
+ wholesale {
477
+ cv
478
+ pv
479
+ __typename
480
+ }
481
+ subscription {
482
+ cv
483
+ pv
484
+ __typename
485
+ }
486
+ __typename
487
+ }
488
+ retailDiscount
489
+ wholesaleDiscount
490
+ pvDiscount
491
+ cvDiscount
492
+ sbDiscount
493
+ grpDiscount
494
+ availableChannels
495
+ customerTypes
496
+ purchaseTypes {
497
+ buyOnce
498
+ subscription
499
+ __typename
500
+ }
501
+ status {
502
+ status
503
+ isBackordered
504
+ backorderedAvailableDate
505
+ __typename
506
+ }
507
+ availableQuantity
508
+ chargeShipping
509
+ dangerousGoods
510
+ excludeFromSearch
511
+ isExclusive
512
+ marketAttributes {
513
+ discount
514
+ redeem
515
+ earn
516
+ __typename
517
+ }
518
+ restrictedMarkets
519
+ scanQualifiedCount
520
+ kitProducts {
521
+ quantity
522
+ isMandatory
523
+ product {
524
+ ...Product
525
+ __typename
526
+ }
527
+ __typename
528
+ }
529
+ __typename
530
+ }`
531
+
532
+
533
+ module.exports = {
534
+ getProductByIdQuery
535
+ };
package/src/product.js CHANGED
@@ -69,6 +69,9 @@ const Product = function (productData) {
69
69
  this.marketAttributes = {};
70
70
  this.salesEventText = "";
71
71
 
72
+ // set if item is subscription priced and installments need to be restricted.
73
+ this.subPriceFlag = false;
74
+
72
75
  // agelocme stuff
73
76
  this.agelocme = null; // object containing agelocme information (like code, label, name)
74
77
 
@@ -552,6 +555,7 @@ const Product = function (productData) {
552
555
  retData.inventory = this.inventory;
553
556
  retData.equinoxProductId = this.equinoxProductId;
554
557
  retData.properties = this.properties;
558
+ retData.subPriceFlag = !!this.subPriceFlag;
555
559
  retData.equinox = {
556
560
  sku: {
557
561
  exists: this.equinox.sku.exists
@@ -618,6 +622,7 @@ const Product = function (productData) {
618
622
  this.contentSection = data.contentSection;
619
623
  this.scanQualified = data.scanQualified;
620
624
  this.status = data.status ? data.status : this.status;
625
+ this.subPriceFlag = !!data.subPriceFlag;
621
626
  if (data.availableQuantity) {
622
627
  this.availableQuantity = data.availableQuantity;
623
628
  }
@@ -7,7 +7,7 @@ const CustomerTypes = require('./models/customerTypes');
7
7
  const ProductStatus = require("./models/productStatus");
8
8
  const { mapBackOrderDate, mapAvailableQuantity, mapChildSKU, mapChildSKUBundle } = require('./equinox-helpers');
9
9
  const { productNotFoundInterceptor } = require('./equinox-helpers/interceptors');
10
-
10
+ const { getProduct } = require('./graph-ql');
11
11
  const productTypes = {
12
12
  kit: 'kit',
13
13
  bundle: 'bundle'
@@ -19,19 +19,16 @@ const ProductData = {
19
19
  * @param {string[]} skus
20
20
  * @param {string} locale
21
21
  * @param {string} market
22
- * @param {boolean} isEquinoxEnabled
23
22
  */
24
- getProductData: async function (skus, locale, market, isEquinoxEnabled = false) {
23
+ getProductData: async function (skus, locale, market) {
25
24
  const localeMarket = `${locale}_${market}`;
26
25
 
27
- if (isEquinoxEnabled) {
28
- const config = (await getConfiguration(['Equinox_Markets'])).Equinox_Markets;
29
-
30
- if (config.country_code === market && config.active) {
31
- return await this.getProductFromEquinox(skus, localeMarket, config);
32
- }
26
+ const config = (await getConfiguration(['Equinox_Markets'])).Equinox_Markets;
27
+ if (config.active) {
28
+ return await getProduct(skus[0], market, locale, config);
29
+ } else {
30
+ return await this.getProductFromLegacy(skus, localeMarket);
33
31
  }
34
- return await this.getProductFromLegacy(skus, localeMarket);
35
32
  },
36
33
 
37
34
  getProductFromEquinox: async function (skus, locale, config) {
@@ -60,7 +57,8 @@ const ProductData = {
60
57
 
61
58
  const shoppingContext = window && window.aem && window.aem.ShoppingContext && window.aem.ShoppingContext.getShoppingContext();
62
59
 
63
- if ((shoppingContext && shoppingContext.context === 'storefront') || window.location.hostname.includes(".mynuskin.com")) {
60
+ if ((shoppingContext && shoppingContext.context === 'storefront')
61
+ || window.location.hostname.includes(".mynuskin.com")) {
64
62
  config.API_Base_URLs = config.MySite_API_Base_URLs
65
63
  }
66
64