@nuskin/cs-product-lib 1.7.2 → 1.8.0-bundleonly-members.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/package.json +1 -1
- package/src/csProduct.js +68 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuskin/cs-product-lib",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0-bundleonly-members.1",
|
|
4
4
|
"description": "Library for pulling and parsing product content (and applying business logic) retrieved from Contentstack",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
package/src/csProduct.js
CHANGED
|
@@ -42,6 +42,9 @@ const validateConfig = (props) => {
|
|
|
42
42
|
/* istanbul ignore next */
|
|
43
43
|
const csProduct = (props) => {
|
|
44
44
|
const DEV_ENVIRONMENT = 'public-dev'
|
|
45
|
+
// CS-native sellable gate for the bypassProductStatus path -- mirrors
|
|
46
|
+
// content-validator ValidationSteps (csStatus === 'sellable' || 'bundleOnly').
|
|
47
|
+
const CS_SELLABLE_STATUSES = ['sellable', 'bundleOnly']
|
|
45
48
|
const VARIANTS = 'variants'
|
|
46
49
|
const VARIANT = 'variant'
|
|
47
50
|
const KEY_INGREDIENTS = 'ingredients.key_ingredients'
|
|
@@ -108,7 +111,7 @@ const csProduct = (props) => {
|
|
|
108
111
|
}
|
|
109
112
|
}
|
|
110
113
|
|
|
111
|
-
const removeInvalidVariants = async (products = [], locale, translations) => {
|
|
114
|
+
const removeInvalidVariants = async (products = [], locale, translations, keepBundleOnly = false, bypassProductStatus = false) => {
|
|
112
115
|
const validSkus = []
|
|
113
116
|
for (const product of products) {
|
|
114
117
|
for (const variant of product?.variants || []) {
|
|
@@ -125,13 +128,35 @@ const csProduct = (props) => {
|
|
|
125
128
|
let status = {}
|
|
126
129
|
let marketData = {}
|
|
127
130
|
if (validSkus?.length > 0) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
if (bypassProductStatus) {
|
|
132
|
+
// Equinox markets: derive status from the CS entry instead of
|
|
133
|
+
// calling product-status. Live availability/quantity is
|
|
134
|
+
// intentionally not available on this path. Temporary until
|
|
135
|
+
// cs-product-graphql is retired.
|
|
136
|
+
status = {}
|
|
137
|
+
for (const product of products) {
|
|
138
|
+
for (const variant of product?.variants || []) {
|
|
139
|
+
const best = helpers?.getBestSkuData(variant)
|
|
140
|
+
if (best?.sku) {
|
|
141
|
+
const csStatus = helpers.mapCsStatus(variant)
|
|
142
|
+
status[best.sku] = {
|
|
143
|
+
status: { retail: csStatus.retail, wholesale: csStatus.wholesale },
|
|
144
|
+
csStatus: csStatus.status,
|
|
145
|
+
isBackordered: false,
|
|
146
|
+
backorderedAvailableDate: null
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
status = await getProductStatus(
|
|
153
|
+
validSkus,
|
|
154
|
+
locale,
|
|
155
|
+
homeUrl,
|
|
156
|
+
awsBase,
|
|
157
|
+
clientId
|
|
158
|
+
)
|
|
159
|
+
}
|
|
135
160
|
const localeSplit = locale.split('_')
|
|
136
161
|
let market =
|
|
137
162
|
localeSplit?.length > 1 ? localeSplit[1].toUpperCase() : 'XX'
|
|
@@ -154,11 +179,18 @@ const csProduct = (props) => {
|
|
|
154
179
|
const bestSkuData = helpers?.getBestSkuData(variant)
|
|
155
180
|
if (bestSkuData.sku) {
|
|
156
181
|
const varStatus = status[bestSkuData.sku]
|
|
157
|
-
|
|
182
|
+
const isBundleOnly =
|
|
183
|
+
bestSkuData?.status_selections?.status === 'bundleOnly'
|
|
184
|
+
const passesBypassGate =
|
|
185
|
+
bypassProductStatus &&
|
|
186
|
+
CS_SELLABLE_STATUSES.includes(varStatus?.csStatus)
|
|
187
|
+
const passesStatusGate =
|
|
188
|
+
!bypassProductStatus && varStatus && varStatus.status.retail
|
|
189
|
+
if (passesStatusGate || passesBypassGate || (keepBundleOnly && isBundleOnly)) {
|
|
158
190
|
variant.sap_data.sku_data = [bestSkuData]
|
|
159
191
|
validVariants.push({
|
|
160
192
|
...variant,
|
|
161
|
-
status: varStatus,
|
|
193
|
+
status: varStatus || { status: { retail: 'bundleOnly', wholesale: 'bundleOnly' } },
|
|
162
194
|
backorderQuantity: varStatus?.backordered ? varStatus?.availableQuantity : 0,
|
|
163
195
|
atpQuantity: varStatus?.backordered ? 0 : varStatus?.availableQuantity,
|
|
164
196
|
availableQuantity: varStatus?.availableQuantity,
|
|
@@ -254,7 +286,7 @@ const csProduct = (props) => {
|
|
|
254
286
|
})
|
|
255
287
|
}
|
|
256
288
|
|
|
257
|
-
const convertKitToRequiredProducts = async (skuKit, locale) => {
|
|
289
|
+
const convertKitToRequiredProducts = async (skuKit, locale, bypassProductStatus = false) => {
|
|
258
290
|
let productBundle = {}
|
|
259
291
|
const variantSkus = []
|
|
260
292
|
for (let kitItem of skuKit[0].variants) {
|
|
@@ -262,8 +294,9 @@ const csProduct = (props) => {
|
|
|
262
294
|
variantSkus.push((skuData || {}).sku)
|
|
263
295
|
kitItem.sku = (skuData || {}).sku
|
|
264
296
|
}
|
|
265
|
-
const products = await getProductsBySku(variantSkus, locale)
|
|
297
|
+
const products = await getProductsBySku(variantSkus, locale, true, bypassProductStatus)
|
|
266
298
|
const requiredProducts = []
|
|
299
|
+
const seenSkuQuantities = new Set()
|
|
267
300
|
for (let i = 0; i < products?.length; i++) {
|
|
268
301
|
for (const variantSku of variantSkus) {
|
|
269
302
|
const productSelect = JSON.parse(JSON.stringify(products[i]))
|
|
@@ -274,10 +307,15 @@ const csProduct = (props) => {
|
|
|
274
307
|
}
|
|
275
308
|
}
|
|
276
309
|
if (!isNullOrEmpty(productSelect?.variants)) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
310
|
+
const quantity = skuKit[0].variants.find(v=>v.sku === variantSku).quantity
|
|
311
|
+
const dedupKey = `${variantSku}:${quantity}`
|
|
312
|
+
if (!seenSkuQuantities.has(dedupKey)) {
|
|
313
|
+
seenSkuQuantities.add(dedupKey)
|
|
314
|
+
requiredProducts.push({
|
|
315
|
+
product: [productSelect],
|
|
316
|
+
quantity
|
|
317
|
+
})
|
|
318
|
+
}
|
|
281
319
|
}
|
|
282
320
|
}
|
|
283
321
|
}
|
|
@@ -314,14 +352,15 @@ const csProduct = (props) => {
|
|
|
314
352
|
return [productBundle]
|
|
315
353
|
}
|
|
316
354
|
|
|
317
|
-
const formatKit = async (products, locale, translations) => {
|
|
355
|
+
const formatKit = async (products, locale, translations, bypassProductStatus = false) => {
|
|
318
356
|
for (let p = 0; p < products.length; p++) {
|
|
319
357
|
let noFormat = false
|
|
320
358
|
if (products[p]?.sku_kit?.length > 0) {
|
|
321
359
|
products[p].type = 'kit'
|
|
322
360
|
products[p].product_bundle = await convertKitToRequiredProducts(
|
|
323
361
|
products[p].sku_kit,
|
|
324
|
-
locale
|
|
362
|
+
locale,
|
|
363
|
+
bypassProductStatus
|
|
325
364
|
)
|
|
326
365
|
noFormat = true
|
|
327
366
|
}
|
|
@@ -437,8 +476,8 @@ const csProduct = (props) => {
|
|
|
437
476
|
* @deprecated use getProductsByUID instead
|
|
438
477
|
* @returns
|
|
439
478
|
*/
|
|
440
|
-
const getBundle = async (id, locale) => {
|
|
441
|
-
const bundles = await getBundles(id, locale)
|
|
479
|
+
const getBundle = async (id, locale, bypassProductStatus = false) => {
|
|
480
|
+
const bundles = await getBundles(id, locale, bypassProductStatus)
|
|
442
481
|
return bundles && bundles[0] ? bundles[0] : null
|
|
443
482
|
}
|
|
444
483
|
|
|
@@ -462,7 +501,7 @@ const csProduct = (props) => {
|
|
|
462
501
|
* @deprecated use getProductsByUID instead
|
|
463
502
|
* @returns
|
|
464
503
|
*/
|
|
465
|
-
const getBundles = async (ids, locale) => {
|
|
504
|
+
const getBundles = async (ids, locale, bypassProductStatus = false) => {
|
|
466
505
|
locale = badLocaleMap(locale)
|
|
467
506
|
if (!Array.isArray(ids)) {
|
|
468
507
|
ids = [ids]
|
|
@@ -478,9 +517,11 @@ const csProduct = (props) => {
|
|
|
478
517
|
const products = await queryProducts(query, locale)
|
|
479
518
|
if (Array.isArray(products) && products.length > 0) {
|
|
480
519
|
const translations = await getTranslations(locale)
|
|
481
|
-
await formatKit(products, locale, translations)
|
|
482
|
-
await removeInvalidVariants(products, locale, translations)
|
|
483
|
-
const status =
|
|
520
|
+
await formatKit(products, locale, translations, bypassProductStatus)
|
|
521
|
+
await removeInvalidVariants(products, locale, translations, false, bypassProductStatus)
|
|
522
|
+
const status = bypassProductStatus
|
|
523
|
+
? {}
|
|
524
|
+
: await getProductStatus(getAllBundleIds(products), helpers?.reorderLocale(locale), homeUrl, awsBase, clientId)
|
|
484
525
|
return formatProductWithSchema(products, status)
|
|
485
526
|
}
|
|
486
527
|
const errorResponse = products.response || {}
|
|
@@ -488,7 +529,7 @@ const csProduct = (props) => {
|
|
|
488
529
|
return [{error: {message: products.message, name: products.name, status: errorResponse.status, errors: [`${responseData.error_code}: ${responseData.error_message}`]}}]
|
|
489
530
|
}
|
|
490
531
|
|
|
491
|
-
const getProductsBySku = async (skus, locale) => {
|
|
532
|
+
const getProductsBySku = async (skus, locale, keepBundleOnly = false, bypassProductStatus = false) => {
|
|
492
533
|
locale = badLocaleMap(locale)
|
|
493
534
|
if (!Array.isArray(skus)) {
|
|
494
535
|
skus = [skus]
|
|
@@ -514,8 +555,8 @@ const csProduct = (props) => {
|
|
|
514
555
|
return bundleProducts
|
|
515
556
|
}
|
|
516
557
|
const translations = await getTranslations(locale)
|
|
517
|
-
await formatKit(products, locale, translations)
|
|
518
|
-
await removeInvalidVariants(products, locale, translations)
|
|
558
|
+
await formatKit(products, locale, translations, bypassProductStatus)
|
|
559
|
+
await removeInvalidVariants(products, locale, translations, keepBundleOnly, bypassProductStatus)
|
|
519
560
|
const formattedProducts = formatProductWithSchema(products)
|
|
520
561
|
for (const product of formattedProducts) {
|
|
521
562
|
product.skus = skus
|