@nuskin/ns-product-lib 2.6.1-cx24-3608.5 → 2.6.1-cx24-3607.1

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,41 +1,10 @@
1
- ## [2.6.1-cx24-3608.5](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.6.1-cx24-3608.4...v2.6.1-cx24-3608.5) (2023-03-15)
1
+ ## [2.6.1-cx24-3607.1](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.6.0...v2.6.1-cx24-3607.1) (2023-03-15)
2
2
 
3
3
 
4
4
  ### Fix
5
5
 
6
- * imageURL issue when product is kit ([9ccb840](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/9ccb8403d2217d0e20107c560d9fa797c9bbbb95))
7
- * imageURL issue when product is kit ([38eabd3](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/38eabd3b29d8b33462509c17e98805819781f344))
8
- * imageURL issue when product is kit ([5eb2c04](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/5eb2c0439b6e1a456a2c9f232f3d7f502ea46e4b))
9
-
10
- ## [2.6.1-cx24-3608.4](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.6.1-cx24-3608.3...v2.6.1-cx24-3608.4) (2023-03-15)
11
-
12
-
13
- ### Fix
14
-
15
- * imageURL issue when product is kit ([0bde1fb](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/0bde1fb0ce99186a30859c2f3509d32c1861cf7b))
16
- * imageURL issue when product is kit ([e302726](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/e30272648ad6214c0dca08f40a6a3f5511c661cd))
17
-
18
- ## [2.6.1-cx24-3608.3](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.6.1-cx24-3608.2...v2.6.1-cx24-3608.3) (2023-03-15)
19
-
20
-
21
- ### Fix
22
-
23
- * imageURL issue when product is kit ([0e4281d](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/0e4281de4435d1a5749ff9b6d52a7c4a45d75d6d))
24
-
25
- ## [2.6.1-cx24-3608.2](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.6.1-cx24-3608.1...v2.6.1-cx24-3608.2) (2023-03-15)
26
-
27
-
28
- ### Fix
29
-
30
- * imageURL issue when product is kit ([3172244](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/3172244e53c328e90d663a0989c25c25eba967d3))
31
-
32
- ## [2.6.1-cx24-3608.1](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.6.0...v2.6.1-cx24-3608.1) (2023-03-15)
33
-
34
-
35
- ### Fix
36
-
37
- * imageURL issue when product is kit ([2a68af6](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/2a68af668a2ca0835a4b0d0995117ea8ab019bed))
38
- * imageURL issue when product is kit ([656505a](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/656505a32421ae4e5d8e29dd451b68b24e72f30d))
6
+ * (equinox-enabled) skip product mapping when an error occurs in PLP #CX24-3607 ([950c165](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/950c1650115f92badc5b898b5df722568b034afe)), closes [#CX24-3607](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-3607)
7
+ * Cannot read properties of undefined (reading 'qty') in PLP #CX24-3607 ([8cde88f](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/8cde88f2f61279d20794a0e43696187c4326ca28)), closes [#CX24-3607](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-3607)
39
8
 
40
9
  # [2.6.0](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.5.2...v2.6.0) (2023-03-13)
41
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/ns-product-lib",
3
- "version": "2.6.1-cx24-3608.5",
3
+ "version": "2.6.1-cx24-3607.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,25 @@
1
+ /**
2
+ * childSkus creates an array of object that contains
3
+ * the list of SKUs of a kit.
4
+ *
5
+ * @param {import('./').KitSKUQuantity[]} kits
6
+ * @param {import('./').EquinoxProduct} product
7
+ */
8
+ function childSkus(kits, product) {
9
+ const sku = product.sku[0];
10
+ const kit = kits.filter(k => k.sku === sku.identifier)[0];
11
+
12
+ return {
13
+ productId: product.identifier,
14
+ skuId: sku.identifier,
15
+ type: 'MANDATORY',
16
+ skuQuantity: kit.qty,
17
+ availableChannels: sku.properties.availableChannels,
18
+ inventory: {
19
+ atpQty: sku.inventoryProperties.atpQty,
20
+ backOrdered: sku.inventoryProperties.backOrdered
21
+ }
22
+ }
23
+ }
24
+
25
+ module.exports = childSkus;
@@ -1,10 +1,11 @@
1
1
  /**
2
+ * @description This model represents the mapped values of a product
2
3
  * @typedef Product
3
4
  * @type {object}
4
- * @property {ChildSku[]} childSkus
5
+ * @property {ProductChildSku[]} childSkus
5
6
  * @property {Inventory} [inventoryProperties]
6
- *
7
- * @typedef ChildSku
7
+ *
8
+ * @typedef ProductChildSku
8
9
  * @type {object}
9
10
  * @property {string} productId
10
11
  * @property {string} skuId
@@ -12,14 +13,48 @@
12
13
  * @property {number} skuQuantity
13
14
  * @property {string} availableChannels
14
15
  * @property {Inventory} [inventory]
16
+ *
17
+ * ---
18
+ *
19
+ * @description This model represents a product within an Equinox response.
20
+ * @typedef EquinoxProduct
21
+ * @type {object}
22
+ * @property {EquinoxProduct[]} sku
23
+ * @property {"kit"|"bundle"} [type]
24
+ *
25
+ * @typedef EquinoxProductSKU
26
+ * @type {object}
27
+ * @property {string} identifier
28
+ * @property {EquinoxProductProperties} properties
29
+ * @property {Inventory} inventoryProperties
30
+ *
31
+ * @typedef EquinoxProductProperties
32
+ * @type {object}
33
+ * @property {string} availableChannels
34
+ *
35
+ * ---
36
+ *
37
+ * Types common to Product model and Equinox Product model
15
38
  *
16
39
  * @typedef Inventory
17
40
  * @type {object}
18
41
  * @property {number} atpQty
19
42
  * @property {boolean} backOrdered
43
+ *
44
+ * ---
45
+ *
46
+ * Standalone types. These are types not related to Product
47
+ * and Equinox Product models.
48
+ *
49
+ * @typedef KitSKUQuantity
50
+ * @type {object}
51
+ * @property {string} sku
52
+ * @property {number} number
20
53
  */
21
54
  const availableQuantity = require('./availableQuantity');
55
+ const childSkus = require('./childSkus');
22
56
 
23
57
  module.exports = {
24
- mapAvailableQuantity: availableQuantity
58
+ mapAvailableQuantity: availableQuantity,
59
+ mapChildSkus: childSkus
25
60
  };
@@ -5,7 +5,7 @@ const contentstack = require('./contentstack/contentstack');
5
5
  const Product = require("./product");
6
6
  const CustomerTypes = require('./models/customerTypes');
7
7
  const ProductStatus = require("./models/productStatus");
8
- const { mapAvailableQuantity } = require('./equinox-helpers');
8
+ const { mapAvailableQuantity, mapChildSkus } = require('./equinox-helpers');
9
9
 
10
10
  const productTypes = {
11
11
  kit: 'kit'
@@ -129,8 +129,15 @@ const ProductData = {
129
129
  */
130
130
  eqProductVariantMapper: function (eqVariant) {
131
131
 
132
- let imageURL = eqVariant.properties.imageURL ? eqVariant.properties.imageURL : '';
133
- let thumbnailImage = (imageURL) ? imageURL + '?width=40' : ''
132
+ let imageURL = eqVariant.properties.imageURL;
133
+ const regex = /\d+\.\d+/
134
+ let thumbnailImage = ''
135
+
136
+ if (imageURL.includes('contentstack')) {
137
+ thumbnailImage = imageURL + '?width=40'
138
+ } else {
139
+ thumbnailImage = imageURL.replace(regex, '40.40')
140
+ }
134
141
 
135
142
  const { eventName, eventLabels, computedPrice, defaultProductPrice } = this.getEqProductPromotions(eqVariant);
136
143
  const productPrice = eventName ? defaultProductPrice : eqVariant.priceFacets["Regular Price"];
@@ -337,131 +344,142 @@ const ProductData = {
337
344
  },
338
345
 
339
346
  eqProductMapper: async function (productDataResponse, skus) {
340
- // console.log(productDataResponse, skus);
341
347
  let count = 0;
342
348
  let variants = {};
343
349
  const products = [];
344
350
 
345
351
  for (const productData of productDataResponse) {
346
- let product = (productData.type && productData.type === "kit") ? productData : productData.sku[count];
347
- let imageURL = product.properties.imageURL ? product.properties.imageURL : '';
348
- let thumbnailImage = imageURL ? imageURL + '?width=40' : ''
352
+ try {
353
+ let product = (productData.type && productData.type === "kit") ? productData : productData.sku[count];
354
+ let imageURL = product.properties.imageURL;
355
+ const regex = /\d+\.\d+/
356
+ let thumbnailImage = ''
357
+
358
+ if (imageURL.includes('contentstack')) {
359
+ thumbnailImage = imageURL + '?width=40'
360
+ } else {
361
+ thumbnailImage = imageURL.replace(regex, '40.40')
362
+ }
349
363
 
364
+ if (productData.sku && productData.sku.length > 1) {
365
+ // exclude base product from variants
366
+ productData.sku.filter(v => v.identifier.substring(2, 4) !== "55").map(variant => {
367
+ variants[variant.identifier] = this.eqProductVariantMapper(variant);
368
+ return variant;
369
+ });
370
+ }
350
371
 
351
- if (productData.sku && productData.sku.length > 1) {
352
- // exclude base product from variants
353
- productData.sku.filter(v => v.identifier.substring(2, 4) !== "55").map(variant => {
354
- variants[variant.identifier] = this.eqProductVariantMapper(variant);
355
- return variant;
356
- });
372
+ const {
373
+ eventName,
374
+ eventLabels,
375
+ computedPrice,
376
+ defaultProductPrice
377
+ } = this.getEqProductPromotions(product);
378
+ const productPrice = eventName ? defaultProductPrice : product.priceFacets["Regular Price"];
379
+ const discountedPrice = eventName ? computedPrice : product.priceFacets["Regular Price"];
380
+
381
+ product.childSkus = await this.fetchChildSkus(product);
382
+ product.availableQuantity = mapAvailableQuantity(product);
383
+ product = {
384
+ ...product,
385
+ "sku": product.identifier,
386
+ "globalProductID": productData.identifier,
387
+ "title": productData.properties.name,
388
+ "country": product.properties.market,
389
+ "language": "en",
390
+ "shortDescr": productData.properties.description,
391
+ "longDescr": productData.properties.productDetailsDescription,
392
+ "fullImage": imageURL,
393
+ "imageAltText": productData.properties.name,
394
+ "productCarouselImages": [
395
+ {
396
+ "contentType": "img",
397
+ "src": "/content/products/24/00/35/24003529/jcr:content/fullImage.imgw.1280.1280.png",
398
+ "alt": ""
399
+ }
400
+ ],
401
+ "thumbnail": thumbnailImage,
402
+ "ingredients": productData.properties.ingredients,
403
+ "benefits": productData.properties.benefits,
404
+ "usage": productData.properties.usage,
405
+ "resources": product.properties.resources,
406
+ "videos": "",
407
+ "movie": "",
408
+ "youtube": "",
409
+ "salesEventText": "",
410
+ "contentSection": [
411
+ {
412
+ "sectionContent": "<div class=\"contentSections\"></div>\n"
413
+ }
414
+ ],
415
+ "scanQualified": productData.properties.scanQualifiedCount,
416
+ "maxQuantity": 999,
417
+ "points": "",
418
+ "cv": (product.priceFacets.CV) ? product.priceFacets.CV : '',
419
+ "pv": product.priceFacets.PV,
420
+ "priceType": "WRTL",
421
+ "price": discountedPrice,
422
+ "priceMap": {
423
+ "WRTL": productPrice,
424
+ "WADW-WRTL": product.priceFacets["Regular Price"],
425
+ "WADR": product.priceFacets["Regular Price"],
426
+ "RTL": product.priceFacets["Regular Price"],
427
+ "WADW": product.priceFacets["Wholesale Price"],
428
+ "WHL": product.priceFacets["Wholesale Price"],
429
+ "WWHL": product.priceFacets["Wholesale Price"]
430
+ },
431
+ "cvMap": {
432
+ "WWHL": (product.priceFacets.CV) ? product.priceFacets.CV : '',
433
+ "WADW": (product.priceFacets.CV) ? product.priceFacets.CV : '',
434
+ "WHL": (product.priceFacets.CV) ? product.priceFacets.CV : ''
435
+ },
436
+ "pvMap": {
437
+ "WWHL": product.priceFacets.PV,
438
+ "WADW": product.priceFacets.PV,
439
+ "WHL": product.priceFacets.PV
440
+ },
441
+ "orderTypes": this._setOrderType(product.properties),
442
+ "custTypes": this.switchCustType(product.properties.customerTypes),
443
+ "division": productData.properties.division,
444
+ "backOrderDate": null,
445
+ "locallyProduced": false,
446
+ "agelocme": null,
447
+ "count": "",
448
+ "flavor": "",
449
+ "size": product.properties.size,
450
+ "shade": "",
451
+ "status": this.switchStatusFromEquinox(product.properties.productStatus),
452
+ "variantType": "Other",
453
+ "variantDropdownLabel": product.properties.variantLabel || "",
454
+ "variantDropdownPlaceholder": "Select Type",
455
+ "variantsLabel": product.properties.variantLabel || "",
456
+ "groupOffer": false,
457
+ "personalOffer": false,
458
+ "savedEventName": eventName,
459
+ "salesLabel": eventLabels,
460
+ "eventName": eventName,
461
+ "sizeWeight": '',
462
+ "nettoWeight": "",
463
+ "variants": variants,
464
+ "searchScore": 0,
465
+ "isExclusive": product.properties.isExclusive || false,
466
+ "marketAttributes": {
467
+ "discount": true,
468
+ "redeem": true,
469
+ "earn": true
470
+ },
471
+ "restrictedMarkets": [],
472
+ "addOns": [],
473
+ "inventory": product.inventory || "", //inventory label
474
+ "equinoxProductId": productData.identifier
475
+ };
476
+
477
+ products.push(new Product(product));
478
+ } catch (err) {
479
+ console.error('Unable to map the product', productData.identifier, ':', err);
480
+ console.error('Product info:', productDataResponse, skus);
481
+ continue;
357
482
  }
358
-
359
- const {
360
- eventName,
361
- eventLabels,
362
- computedPrice,
363
- defaultProductPrice
364
- } = this.getEqProductPromotions(product);
365
- const productPrice = eventName ? defaultProductPrice : product.priceFacets["Regular Price"];
366
- const discountedPrice = eventName ? computedPrice : product.priceFacets["Regular Price"];
367
-
368
- product.childSkus = await this.fetchChildSkus(product);
369
- product.availableQuantity = mapAvailableQuantity(product);
370
- product = {
371
- ...product,
372
- "sku": product.identifier,
373
- "globalProductID": productData.identifier,
374
- "title": productData.properties.name,
375
- "country": product.properties.market,
376
- "language": "en",
377
- "shortDescr": productData.properties.description,
378
- "longDescr": productData.properties.productDetailsDescription,
379
- "fullImage": imageURL,
380
- "imageAltText": productData.properties.name,
381
- "productCarouselImages": [
382
- {
383
- "contentType": "img",
384
- "src": "/content/products/24/00/35/24003529/jcr:content/fullImage.imgw.1280.1280.png",
385
- "alt": ""
386
- }
387
- ],
388
- "thumbnail": thumbnailImage,
389
- "ingredients": productData.properties.ingredients,
390
- "benefits": productData.properties.benefits,
391
- "usage": productData.properties.usage,
392
- "resources": product.properties.resources,
393
- "videos": "",
394
- "movie": "",
395
- "youtube": "",
396
- "salesEventText": "",
397
- "contentSection": [
398
- {
399
- "sectionContent": "<div class=\"contentSections\"></div>\n"
400
- }
401
- ],
402
- "scanQualified": productData.properties.scanQualifiedCount,
403
- "maxQuantity": 999,
404
- "points": "",
405
- "cv": (product.priceFacets.CV) ? product.priceFacets.CV : '',
406
- "pv": product.priceFacets.PV,
407
- "priceType": "WRTL",
408
- "price": discountedPrice,
409
- "priceMap": {
410
- "WRTL": productPrice,
411
- "WADW-WRTL": product.priceFacets["Regular Price"],
412
- "WADR": product.priceFacets["Regular Price"],
413
- "RTL": product.priceFacets["Regular Price"],
414
- "WADW": product.priceFacets["Wholesale Price"],
415
- "WHL": product.priceFacets["Wholesale Price"],
416
- "WWHL": product.priceFacets["Wholesale Price"]
417
- },
418
- "cvMap": {
419
- "WWHL": (product.priceFacets.CV) ? product.priceFacets.CV : '',
420
- "WADW": (product.priceFacets.CV) ? product.priceFacets.CV : '',
421
- "WHL": (product.priceFacets.CV) ? product.priceFacets.CV : ''
422
- },
423
- "pvMap": {
424
- "WWHL": product.priceFacets.PV,
425
- "WADW": product.priceFacets.PV,
426
- "WHL": product.priceFacets.PV
427
- },
428
- "orderTypes": this._setOrderType(product.properties),
429
- "custTypes": this.switchCustType(product.properties.customerTypes),
430
- "division": productData.properties.division,
431
- "backOrderDate": null,
432
- "locallyProduced": false,
433
- "agelocme": null,
434
- "count": "",
435
- "flavor": "",
436
- "size": product.properties.size,
437
- "shade": "",
438
- "status": this.switchStatusFromEquinox(product.properties.productStatus),
439
- "variantType": "Other",
440
- "variantDropdownLabel": product.properties.variantLabel || "",
441
- "variantDropdownPlaceholder": "Select Type",
442
- "variantsLabel": product.properties.variantLabel || "",
443
- "groupOffer": false,
444
- "personalOffer": false,
445
- "savedEventName": eventName,
446
- "salesLabel": eventLabels,
447
- "eventName": eventName,
448
- "sizeWeight": '',
449
- "nettoWeight": "",
450
- "variants": variants,
451
- "searchScore": 0,
452
- "isExclusive": product.properties.isExclusive || false,
453
- "marketAttributes": {
454
- "discount": true,
455
- "redeem": true,
456
- "earn": true
457
- },
458
- "restrictedMarkets": [],
459
- "addOns": [],
460
- "inventory": product.inventory || "", //inventory label
461
- "equinoxProductId": productData.identifier
462
- };
463
-
464
- products.push(new Product(product));
465
483
  }
466
484
 
467
485
  let data = {
@@ -504,7 +522,7 @@ const ProductData = {
504
522
  type: 'SKUKIT',
505
523
  availableChannels: product.properties.availableChannels
506
524
  },
507
- ...res.data.product.map(p => this.buildChildSkus(kits, p))
525
+ ...res.data.product.map(p => mapChildSkus(kits, p))
508
526
  ];
509
527
 
510
528
  return childSkus;
@@ -513,23 +531,6 @@ const ProductData = {
513
531
  return [];
514
532
  },
515
533
 
516
- buildChildSkus: function (kits, product) {
517
- const sku = product.sku[0];
518
- const kit = kits.filter(k => k.sku === sku.identifier)[0];
519
-
520
- return {
521
- productId: product.identifier,
522
- skuId: sku.identifier,
523
- type: 'MANDATORY',
524
- skuQuantity: kit.qty,
525
- availableChannels: sku.properties.availableChannels,
526
- inventory: {
527
- atpQty: sku.inventoryProperties.atpQty,
528
- backOrdered: sku.inventoryProperties.backOrdered
529
- }
530
- }
531
- },
532
-
533
534
  /**
534
535
  *
535
536
  * Map status from equinox to legacy