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

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 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