@nuskin/ns-product-lib 2.6.1-cx24-3607.3 → 2.6.1-cx24-337701.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +4 -17
- package/package.json +1 -1
- package/src/equinox-helpers/index.js +4 -43
- package/src/productData.js +163 -126
- package/src/equinox-helpers/childSKU.js +0 -31
package/CHANGELOG.md
CHANGED
@@ -1,24 +1,11 @@
|
|
1
|
-
## [2.6.1-cx24-
|
1
|
+
## [2.6.1-cx24-337701.1](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/compare/v2.6.0...v2.6.1-cx24-337701.1) (2023-03-19)
|
2
2
|
|
3
3
|
|
4
4
|
### Fix
|
5
5
|
|
6
|
-
*
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
### Fix
|
12
|
-
|
13
|
-
* (equinox-enabled) skip product mapping when an error occurs in PLP #CX24-3607 ([49fa749](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/49fa7499b390aa84cc887fc631037363421d252a)), closes [#CX24-3607](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/issues/CX24-3607)
|
14
|
-
|
15
|
-
## [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)
|
16
|
-
|
17
|
-
|
18
|
-
### Fix
|
19
|
-
|
20
|
-
* (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)
|
21
|
-
* 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)
|
6
|
+
* The variant drop down label ([bd60148](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/bd60148d1a50e895d36139932740fe4ee7f9f50a))
|
7
|
+
* The variant drop down label ([749b476](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/749b47605995405886460b29f20411a21e45fb68))
|
8
|
+
* The variant drop down label ([bc555ab](https://code.tls.nuskin.io/ns-am/product/js-libs/ns-product-lib/commit/bc555abec97bca95fc0ba18a0eb4f0a0c9cd537a))
|
22
9
|
|
23
10
|
# [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)
|
24
11
|
|
package/package.json
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
/**
|
2
|
-
* @description This model represents the mapped values of a product
|
3
2
|
* @typedef Product
|
4
3
|
* @type {object}
|
5
|
-
* @property {
|
4
|
+
* @property {ChildSku[]} childSkus
|
6
5
|
* @property {Inventory} [inventoryProperties]
|
7
|
-
*
|
8
|
-
* @typedef
|
6
|
+
*
|
7
|
+
* @typedef ChildSku
|
9
8
|
* @type {object}
|
10
9
|
* @property {string} productId
|
11
10
|
* @property {string} skuId
|
@@ -13,52 +12,14 @@
|
|
13
12
|
* @property {number} skuQuantity
|
14
13
|
* @property {string} availableChannels
|
15
14
|
* @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 {string} identifier
|
23
|
-
* @property {EquinoxProductSKU[]} sku
|
24
|
-
* @property {"kit"|"bundle"} [type]
|
25
|
-
*
|
26
|
-
* @typedef EquinoxProductSKU
|
27
|
-
* @type {object}
|
28
|
-
* @property {boolean} default
|
29
|
-
* For multi-variant products, this indicates that this is the searched SKU
|
30
|
-
* when using catalogs/search endpoint.
|
31
|
-
* @property {string} identifier
|
32
|
-
* @property {Inventory} inventoryProperties
|
33
|
-
* @property {EquinoxProductProperties} properties
|
34
|
-
*
|
35
|
-
* @typedef EquinoxProductProperties
|
36
|
-
* @type {object}
|
37
|
-
* @property {string} availableChannels
|
38
|
-
*
|
39
|
-
* ---
|
40
|
-
*
|
41
|
-
* Types common to Product model and Equinox Product model
|
42
15
|
*
|
43
16
|
* @typedef Inventory
|
44
17
|
* @type {object}
|
45
18
|
* @property {number} atpQty
|
46
19
|
* @property {boolean} backOrdered
|
47
|
-
*
|
48
|
-
* ---
|
49
|
-
*
|
50
|
-
* Standalone types. These are types not related to Product
|
51
|
-
* and Equinox Product models.
|
52
|
-
*
|
53
|
-
* @typedef KitSKUQuantity
|
54
|
-
* @type {object}
|
55
|
-
* @property {string} sku
|
56
|
-
* @property {number} qty
|
57
20
|
*/
|
58
21
|
const availableQuantity = require('./availableQuantity');
|
59
|
-
const childSKU = require('./childSKU');
|
60
22
|
|
61
23
|
module.exports = {
|
62
|
-
mapAvailableQuantity: availableQuantity
|
63
|
-
mapChildSKU: childSKU
|
24
|
+
mapAvailableQuantity: availableQuantity
|
64
25
|
};
|
package/src/productData.js
CHANGED
@@ -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
|
8
|
+
const { mapAvailableQuantity } = require('./equinox-helpers');
|
9
9
|
|
10
10
|
const productTypes = {
|
11
11
|
kit: 'kit'
|
@@ -129,9 +129,15 @@ const ProductData = {
|
|
129
129
|
*/
|
130
130
|
eqProductVariantMapper: function (eqVariant) {
|
131
131
|
|
132
|
-
let imageURL = eqVariant.properties.imageURL
|
133
|
-
|
132
|
+
let imageURL = eqVariant.properties.imageURL;
|
133
|
+
const regex = /\d+\.\d+/
|
134
|
+
let thumbnailImage = ''
|
134
135
|
|
136
|
+
if (imageURL.includes('contentstack')) {
|
137
|
+
thumbnailImage = imageURL + '?width=40'
|
138
|
+
} else {
|
139
|
+
thumbnailImage = imageURL.replace(regex, '40.40')
|
140
|
+
}
|
135
141
|
|
136
142
|
const { eventName, eventLabels, computedPrice, defaultProductPrice } = this.getEqProductPromotions(eqVariant);
|
137
143
|
const productPrice = eventName ? defaultProductPrice : eqVariant.priceFacets["Regular Price"];
|
@@ -337,137 +343,151 @@ const ProductData = {
|
|
337
343
|
}
|
338
344
|
},
|
339
345
|
|
346
|
+
moveArray: function (arr, from, to) {
|
347
|
+
arr.splice(to, 0, arr.splice(from, 1)[0]);
|
348
|
+
return arr;
|
349
|
+
},
|
350
|
+
|
351
|
+
|
340
352
|
eqProductMapper: async function (productDataResponse, skus) {
|
353
|
+
// console.log(productDataResponse, skus);
|
341
354
|
let count = 0;
|
342
355
|
let variants = {};
|
343
356
|
const products = [];
|
344
357
|
|
345
358
|
for (const productData of productDataResponse) {
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
359
|
+
let product = (productData.type && productData.type === "kit") ? productData : productData.sku[count];
|
360
|
+
let imageURL = product.properties.imageURL;
|
361
|
+
const regex = /\d+\.\d+/
|
362
|
+
let thumbnailImage = ''
|
363
|
+
|
364
|
+
if (imageURL.includes('contentstack')) {
|
365
|
+
thumbnailImage = imageURL + '?width=40'
|
366
|
+
} else {
|
367
|
+
thumbnailImage = imageURL.replace(regex, '40.40')
|
368
|
+
}
|
369
|
+
|
370
|
+
if (productData.sku && productData.sku.length > 1) {
|
371
|
+
// exclude base product from variants
|
372
|
+
productData.sku.filter(v => v.identifier.substring(2, 4) !== "55").map(variant => {
|
373
|
+
variants[variant.identifier] = this.eqProductVariantMapper(variant);
|
374
|
+
return variant;
|
375
|
+
});
|
376
|
+
|
377
|
+
//check variants for default and put it in the first element of the variants array
|
378
|
+
if (variants.length > 1) {
|
379
|
+
let defaultKey = variants.map(e => e.default).indexOf(true);
|
380
|
+
variants = this.moveArray(variants, defaultKey, 0);
|
358
381
|
}
|
359
382
|
|
360
|
-
const {
|
361
|
-
eventName,
|
362
|
-
eventLabels,
|
363
|
-
computedPrice,
|
364
|
-
defaultProductPrice
|
365
|
-
} = this.getEqProductPromotions(product);
|
366
|
-
const productPrice = eventName ? defaultProductPrice : product.priceFacets["Regular Price"];
|
367
|
-
const discountedPrice = eventName ? computedPrice : product.priceFacets["Regular Price"];
|
368
|
-
|
369
|
-
product.childSkus = await this.fetchChildSkus(product);
|
370
|
-
product.availableQuantity = mapAvailableQuantity(product);
|
371
|
-
product = {
|
372
|
-
...product,
|
373
|
-
"sku": product.identifier,
|
374
|
-
"globalProductID": productData.identifier,
|
375
|
-
"title": productData.properties.name,
|
376
|
-
"country": product.properties.market,
|
377
|
-
"language": "en",
|
378
|
-
"shortDescr": productData.properties.description,
|
379
|
-
"longDescr": productData.properties.productDetailsDescription,
|
380
|
-
"fullImage": imageURL,
|
381
|
-
"imageAltText": productData.properties.name,
|
382
|
-
"productCarouselImages": [
|
383
|
-
{
|
384
|
-
"contentType": "img",
|
385
|
-
"src": "/content/products/24/00/35/24003529/jcr:content/fullImage.imgw.1280.1280.png",
|
386
|
-
"alt": ""
|
387
|
-
}
|
388
|
-
],
|
389
|
-
"thumbnail": thumbnailImage,
|
390
|
-
"ingredients": productData.properties.ingredients,
|
391
|
-
"benefits": productData.properties.benefits,
|
392
|
-
"usage": productData.properties.usage,
|
393
|
-
"resources": product.properties.resources,
|
394
|
-
"videos": "",
|
395
|
-
"movie": "",
|
396
|
-
"youtube": "",
|
397
|
-
"salesEventText": "",
|
398
|
-
"contentSection": [
|
399
|
-
{
|
400
|
-
"sectionContent": "<div class=\"contentSections\"></div>\n"
|
401
|
-
}
|
402
|
-
],
|
403
|
-
"scanQualified": productData.properties.scanQualifiedCount,
|
404
|
-
"maxQuantity": 999,
|
405
|
-
"points": "",
|
406
|
-
"cv": (product.priceFacets.CV) ? product.priceFacets.CV : '',
|
407
|
-
"pv": product.priceFacets.PV,
|
408
|
-
"priceType": "WRTL",
|
409
|
-
"price": discountedPrice,
|
410
|
-
"priceMap": {
|
411
|
-
"WRTL": productPrice,
|
412
|
-
"WADW-WRTL": product.priceFacets["Regular Price"],
|
413
|
-
"WADR": product.priceFacets["Regular Price"],
|
414
|
-
"RTL": product.priceFacets["Regular Price"],
|
415
|
-
"WADW": product.priceFacets["Wholesale Price"],
|
416
|
-
"WHL": product.priceFacets["Wholesale Price"],
|
417
|
-
"WWHL": product.priceFacets["Wholesale Price"]
|
418
|
-
},
|
419
|
-
"cvMap": {
|
420
|
-
"WWHL": (product.priceFacets.CV) ? product.priceFacets.CV : '',
|
421
|
-
"WADW": (product.priceFacets.CV) ? product.priceFacets.CV : '',
|
422
|
-
"WHL": (product.priceFacets.CV) ? product.priceFacets.CV : ''
|
423
|
-
},
|
424
|
-
"pvMap": {
|
425
|
-
"WWHL": product.priceFacets.PV,
|
426
|
-
"WADW": product.priceFacets.PV,
|
427
|
-
"WHL": product.priceFacets.PV
|
428
|
-
},
|
429
|
-
"orderTypes": this._setOrderType(product.properties),
|
430
|
-
"custTypes": this.switchCustType(product.properties.customerTypes),
|
431
|
-
"division": productData.properties.division,
|
432
|
-
"backOrderDate": null,
|
433
|
-
"locallyProduced": false,
|
434
|
-
"agelocme": null,
|
435
|
-
"count": "",
|
436
|
-
"flavor": "",
|
437
|
-
"size": product.properties.size,
|
438
|
-
"shade": "",
|
439
|
-
"status": this.switchStatusFromEquinox(product.properties.productStatus),
|
440
|
-
"variantType": "Other",
|
441
|
-
"variantDropdownLabel": product.properties.variantLabel || "",
|
442
|
-
"variantDropdownPlaceholder": "Select Type",
|
443
|
-
"variantsLabel": product.properties.variantLabel || "",
|
444
|
-
"groupOffer": false,
|
445
|
-
"personalOffer": false,
|
446
|
-
"savedEventName": eventName,
|
447
|
-
"salesLabel": eventLabels,
|
448
|
-
"eventName": eventName,
|
449
|
-
"sizeWeight": '',
|
450
|
-
"nettoWeight": "",
|
451
|
-
"variants": variants,
|
452
|
-
"searchScore": 0,
|
453
|
-
"isExclusive": product.properties.isExclusive || false,
|
454
|
-
"marketAttributes": {
|
455
|
-
"discount": true,
|
456
|
-
"redeem": true,
|
457
|
-
"earn": true
|
458
|
-
},
|
459
|
-
"restrictedMarkets": [],
|
460
|
-
"addOns": [],
|
461
|
-
"inventory": product.inventory || "", //inventory label
|
462
|
-
"equinoxProductId": productData.identifier
|
463
|
-
};
|
464
|
-
|
465
|
-
products.push(new Product(product));
|
466
|
-
} catch (err) {
|
467
|
-
console.error('Unable to map the product', productData.identifier, ':', err);
|
468
|
-
console.error('Product info:', productDataResponse, skus);
|
469
|
-
continue;
|
470
383
|
}
|
384
|
+
|
385
|
+
const {
|
386
|
+
eventName,
|
387
|
+
eventLabels,
|
388
|
+
computedPrice,
|
389
|
+
defaultProductPrice
|
390
|
+
} = this.getEqProductPromotions(product);
|
391
|
+
const productPrice = eventName ? defaultProductPrice : product.priceFacets["Regular Price"];
|
392
|
+
const discountedPrice = eventName ? computedPrice : product.priceFacets["Regular Price"];
|
393
|
+
|
394
|
+
product.childSkus = await this.fetchChildSkus(product);
|
395
|
+
product.availableQuantity = mapAvailableQuantity(product);
|
396
|
+
product = {
|
397
|
+
...product,
|
398
|
+
"sku": product.identifier,
|
399
|
+
"globalProductID": productData.identifier,
|
400
|
+
"title": productData.properties.name,
|
401
|
+
"country": product.properties.market,
|
402
|
+
"language": "en",
|
403
|
+
"shortDescr": productData.properties.description,
|
404
|
+
"longDescr": productData.properties.productDetailsDescription,
|
405
|
+
"fullImage": imageURL,
|
406
|
+
"imageAltText": productData.properties.name,
|
407
|
+
"productCarouselImages": [
|
408
|
+
{
|
409
|
+
"contentType": "img",
|
410
|
+
"src": "/content/products/24/00/35/24003529/jcr:content/fullImage.imgw.1280.1280.png",
|
411
|
+
"alt": ""
|
412
|
+
}
|
413
|
+
],
|
414
|
+
"thumbnail": thumbnailImage,
|
415
|
+
"ingredients": productData.properties.ingredients,
|
416
|
+
"benefits": productData.properties.benefits,
|
417
|
+
"usage": productData.properties.usage,
|
418
|
+
"resources": product.properties.resources,
|
419
|
+
"videos": "",
|
420
|
+
"movie": "",
|
421
|
+
"youtube": "",
|
422
|
+
"salesEventText": "",
|
423
|
+
"contentSection": [
|
424
|
+
{
|
425
|
+
"sectionContent": "<div class=\"contentSections\"></div>\n"
|
426
|
+
}
|
427
|
+
],
|
428
|
+
"scanQualified": productData.properties.scanQualifiedCount,
|
429
|
+
"maxQuantity": 999,
|
430
|
+
"points": "",
|
431
|
+
"cv": (product.priceFacets.CV) ? product.priceFacets.CV : '',
|
432
|
+
"pv": product.priceFacets.PV,
|
433
|
+
"priceType": "WRTL",
|
434
|
+
"price": discountedPrice,
|
435
|
+
"priceMap": {
|
436
|
+
"WRTL": productPrice,
|
437
|
+
"WADW-WRTL": product.priceFacets["Regular Price"],
|
438
|
+
"WADR": product.priceFacets["Regular Price"],
|
439
|
+
"RTL": product.priceFacets["Regular Price"],
|
440
|
+
"WADW": product.priceFacets["Wholesale Price"],
|
441
|
+
"WHL": product.priceFacets["Wholesale Price"],
|
442
|
+
"WWHL": product.priceFacets["Wholesale Price"]
|
443
|
+
},
|
444
|
+
"cvMap": {
|
445
|
+
"WWHL": (product.priceFacets.CV) ? product.priceFacets.CV : '',
|
446
|
+
"WADW": (product.priceFacets.CV) ? product.priceFacets.CV : '',
|
447
|
+
"WHL": (product.priceFacets.CV) ? product.priceFacets.CV : ''
|
448
|
+
},
|
449
|
+
"pvMap": {
|
450
|
+
"WWHL": product.priceFacets.PV,
|
451
|
+
"WADW": product.priceFacets.PV,
|
452
|
+
"WHL": product.priceFacets.PV
|
453
|
+
},
|
454
|
+
"orderTypes": this._setOrderType(product.properties),
|
455
|
+
"custTypes": this.switchCustType(product.properties.customerTypes),
|
456
|
+
"division": productData.properties.division,
|
457
|
+
"backOrderDate": null,
|
458
|
+
"locallyProduced": false,
|
459
|
+
"agelocme": null,
|
460
|
+
"count": "",
|
461
|
+
"flavor": "",
|
462
|
+
"size": product.properties.size,
|
463
|
+
"shade": "",
|
464
|
+
"status": this.switchStatusFromEquinox(product.properties.productStatus),
|
465
|
+
"variantType": "Other",
|
466
|
+
"variantDropdownLabel": product.properties.variantLabel || "",
|
467
|
+
"variantDropdownPlaceholder": "Select Type",
|
468
|
+
"variantsLabel": product.properties.variantLabel || "",
|
469
|
+
"groupOffer": false,
|
470
|
+
"personalOffer": false,
|
471
|
+
"savedEventName": eventName,
|
472
|
+
"salesLabel": eventLabels,
|
473
|
+
"eventName": eventName,
|
474
|
+
"sizeWeight": '',
|
475
|
+
"nettoWeight": "",
|
476
|
+
"variants": variants,
|
477
|
+
"searchScore": 0,
|
478
|
+
"isExclusive": product.properties.isExclusive || false,
|
479
|
+
"marketAttributes": {
|
480
|
+
"discount": true,
|
481
|
+
"redeem": true,
|
482
|
+
"earn": true
|
483
|
+
},
|
484
|
+
"restrictedMarkets": [],
|
485
|
+
"addOns": [],
|
486
|
+
"inventory": product.inventory || "", //inventory label
|
487
|
+
"equinoxProductId": productData.identifier
|
488
|
+
};
|
489
|
+
|
490
|
+
products.push(new Product(product));
|
471
491
|
}
|
472
492
|
|
473
493
|
let data = {
|
@@ -510,7 +530,7 @@ const ProductData = {
|
|
510
530
|
type: 'SKUKIT',
|
511
531
|
availableChannels: product.properties.availableChannels
|
512
532
|
},
|
513
|
-
...res.data.product.map(p =>
|
533
|
+
...res.data.product.map(p => this.buildChildSkus(kits, p))
|
514
534
|
];
|
515
535
|
|
516
536
|
return childSkus;
|
@@ -519,6 +539,23 @@ const ProductData = {
|
|
519
539
|
return [];
|
520
540
|
},
|
521
541
|
|
542
|
+
buildChildSkus: function (kits, product) {
|
543
|
+
const sku = product.sku[0];
|
544
|
+
const kit = kits.filter(k => k.sku === sku.identifier)[0];
|
545
|
+
|
546
|
+
return {
|
547
|
+
productId: product.identifier,
|
548
|
+
skuId: sku.identifier,
|
549
|
+
type: 'MANDATORY',
|
550
|
+
skuQuantity: kit.qty,
|
551
|
+
availableChannels: sku.properties.availableChannels,
|
552
|
+
inventory: {
|
553
|
+
atpQty: sku.inventoryProperties.atpQty,
|
554
|
+
backOrdered: sku.inventoryProperties.backOrdered
|
555
|
+
}
|
556
|
+
}
|
557
|
+
},
|
558
|
+
|
522
559
|
/**
|
523
560
|
*
|
524
561
|
* Map status from equinox to legacy
|
@@ -1,31 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* childSKU maps a product variant. Used mainly in subscription.
|
3
|
-
*
|
4
|
-
* @param {import('.').KitSKUQuantity[]} kits
|
5
|
-
* @param {import('.').EquinoxProduct} product
|
6
|
-
*/
|
7
|
-
function childSKU(kits, product) {
|
8
|
-
const sku = product.sku.filter(sku => sku.default)[0];
|
9
|
-
if (!sku) {
|
10
|
-
throw Error('Unable to find the default SKU.');
|
11
|
-
}
|
12
|
-
|
13
|
-
const kit = kits.filter(k => k.sku === sku.identifier)[0];
|
14
|
-
if (!kit) {
|
15
|
-
throw Error('SKU kit does not exist in the list of available variants.');
|
16
|
-
}
|
17
|
-
|
18
|
-
return {
|
19
|
-
productId: product.identifier,
|
20
|
-
skuId: sku.identifier,
|
21
|
-
type: 'MANDATORY',
|
22
|
-
skuQuantity: kit.qty,
|
23
|
-
availableChannels: sku.properties.availableChannels,
|
24
|
-
inventory: {
|
25
|
-
atpQty: sku.inventoryProperties.atpQty,
|
26
|
-
backOrdered: sku.inventoryProperties.backOrdered
|
27
|
-
}
|
28
|
-
}
|
29
|
-
}
|
30
|
-
|
31
|
-
module.exports = childSKU;
|