@nuskin/cs-product-lib 1.0.8 → 1.0.9-cx12-6632.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/cs-product-lib",
3
- "version": "1.0.8",
3
+ "version": "1.0.9-cx12-6632.2",
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
@@ -35,6 +35,7 @@ const validateConfig = (props) => {
35
35
  const csProduct = (props) => {
36
36
  const DEV_ENVIRONMENT = 'public-dev'
37
37
  const VARIANTS = 'variants'
38
+ const VARIANT = 'variant'
38
39
  const KEY_INGREDIENTS = 'ingredients.key_ingredients'
39
40
  const PRODUCT_HIGHLIGHTS = 'product_details.highlights'
40
41
  const VARIANT_HIGHLIGHTS = 'variants.product_details.highlights'
@@ -54,13 +55,16 @@ const csProduct = (props) => {
54
55
  const OPTIONAL = 'optional_products.product.'
55
56
  const BUNDLE_TYPE = 'bundle'
56
57
  const PRODUCT_BUNDLE = 'product_bundle'
58
+ const PRODUCT_SKU_KIT = 'sku_kit'
57
59
 
58
60
  // eslint-disable-next-line max-len
59
- const productIncludes = `&include[]=${VARIANTS}&include[]=${PRODUCT_FAQS}&include[]=${KEY_INGREDIENTS}&include[]=${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_RESOURCES}&include[]=${VARIANT_KEY_INGREDIENTS}&include[]=${VARIANT_HIGHLIGHTS}&include[]=${VARIANT_FAQS}&include[]=${VARIANT_RESOURCES}&include[]=${PRODUCT_CATEGORY}&include[]=${PRODUCT_SUBCATEGORIES}&include[]=${PRODUCT_BRAND_STYLE}&include[]=${PRODUCT_BUNDLE}`
61
+ const productIncludes = `&include[]=${VARIANTS}&include[]=${PRODUCT_FAQS}&include[]=${KEY_INGREDIENTS}&include[]=${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_RESOURCES}&include[]=${VARIANT_KEY_INGREDIENTS}&include[]=${VARIANT_HIGHLIGHTS}&include[]=${VARIANT_FAQS}&include[]=${VARIANT_RESOURCES}&include[]=${PRODUCT_CATEGORY}&include[]=${PRODUCT_SUBCATEGORIES}&include[]=${PRODUCT_BRAND_STYLE}&include[]=${PRODUCT_BUNDLE}&include[]=${PRODUCT_SKU_KIT}`
60
62
  const requiredIncludes = `&include[]=${REQUIRED}${VARIANTS}&include[]=${REQUIRED}${PRODUCT_FAQS}&include[]=${REQUIRED}${KEY_INGREDIENTS}&include[]=${REQUIRED}${PRODUCT_HIGHLIGHTS}&include[]=${REQUIRED}${PRODUCT_RESOURCES}&include[]=${REQUIRED}${VARIANT_KEY_INGREDIENTS}&include[]=${REQUIRED}${VARIANT_HIGHLIGHTS}&include[]=${REQUIRED}${VARIANT_FAQS}&include[]=${REQUIRED}${VARIANT_RESOURCES}&include[]=${REQUIRED}${PRODUCT_CATEGORY}&include[]=${REQUIRED}${PRODUCT_SUBCATEGORIES}`
61
63
  const optionalIncludes = `&include[]=${OPTIONAL}${VARIANTS}&include[]=${OPTIONAL}${PRODUCT_FAQS}&include[]=${OPTIONAL}${KEY_INGREDIENTS}&include[]=${OPTIONAL}${PRODUCT_HIGHLIGHTS}&include[]=${OPTIONAL}${PRODUCT_RESOURCES}&include[]=${OPTIONAL}${VARIANT_KEY_INGREDIENTS}&include[]=${OPTIONAL}${VARIANT_HIGHLIGHTS}&include[]=${OPTIONAL}${VARIANT_FAQS}&include[]=${OPTIONAL}${VARIANT_RESOURCES}&include[]=${OPTIONAL}${PRODUCT_CATEGORY}&include[]=${OPTIONAL}${PRODUCT_SUBCATEGORIES}`
62
64
  const bundleRequiredIncludes = `&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_FAQS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_FAQS}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${VARIANT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_CATEGORY}&include[]=${PRODUCT_BUNDLE}.${REQUIRED}${PRODUCT_SUBCATEGORIES}`
63
65
  const bundlOptionalIncludes = `&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_FAQS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_KEY_INGREDIENTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_HIGHLIGHTS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_FAQS}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${VARIANT_RESOURCES}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_CATEGORY}&include[]=${PRODUCT_BUNDLE}.${OPTIONAL}${PRODUCT_SUBCATEGORIES}`
66
+ const kit = `&include[]=${PRODUCT_SKU_KIT}.${VARIANTS}&include[]=${PRODUCT_SKU_KIT}.${VARIANTS}.${VARIANT}`
67
+
64
68
 
65
69
  validateConfig(props)
66
70
  const { apiKey, environment, deliveryToken, homeUrl, awsBase, clientId } = props
@@ -164,13 +168,16 @@ const csProduct = (props) => {
164
168
  })
165
169
  }
166
170
 
167
- const formatBundleWithSchema = (bundles = []) => {
171
+ const formatKitWithSchema = (bundles = [], noFormat) => {
168
172
  return bundles?.map((bundle) => {
169
173
  const formattedBundle = transformBundle(bundle, homeUrl)
170
174
 
171
175
  formattedBundle.requiredProducts = formattedBundle?.requiredProducts?.map(
172
176
  ({product, quantity}) => {
173
177
  if (product) {
178
+ if (noFormat) {
179
+ return {product : product, quantity}
180
+ }
174
181
  const [formattedProduct] = formatProductWithSchema([product])
175
182
  return {product : formattedProduct, quantity}
176
183
  } else {
@@ -181,8 +188,15 @@ const csProduct = (props) => {
181
188
 
182
189
  formattedBundle.optionalProducts = formattedBundle?.optionalProducts?.map(
183
190
  ({product, quantity}) => {
184
- const [formattedProduct] = formatProductWithSchema([product])
185
- return {product : formattedProduct, quantity}
191
+ if (product) {
192
+ if (noFormat) {
193
+ return {product : product, quantity}
194
+ }
195
+ const [formattedProduct] = formatProductWithSchema([product])
196
+ return {product : formattedProduct, quantity}
197
+ } else {
198
+ return {}
199
+ }
186
200
  }
187
201
  )
188
202
 
@@ -190,42 +204,91 @@ const csProduct = (props) => {
190
204
  })
191
205
  }
192
206
 
193
- const formatBundleKit = async (products, locale, translations) => {
207
+ const convertKitToRequiredProducts = async (skuKit, locale) => {
208
+ let productBundle = {}
209
+ const variantSkus = []
210
+ for (const kitItem of skuKit[0].variants) {
211
+ const skuData = helpers.getBestSkuData((kitItem.variant || [])[0])
212
+ variantSkus.push((skuData || {}).sku)
213
+ }
214
+ const products = await getProductsBySku(variantSkus, locale)
215
+ const requiredProducts = []
216
+ for (let i = 0; i < products.length; i++) {
217
+ for (let v = 0; v < products[i].variants.length; v++) {
218
+ if (products[i].variants[v].sku !== variantSkus[i]) {
219
+ products[i].variants.splice(v, 1)
220
+ v--
221
+ }
222
+ }
223
+ requiredProducts.push({
224
+ product: [products[i]],
225
+ quantity: skuKit[0].variants[i].quantity
226
+ })
227
+ }
228
+ productBundle.required_products = requiredProducts
229
+ productBundle.charge_shipping = skuKit[0].charge_shipping
230
+ productBundle.cvdis = skuKit[0].cvdis
231
+ productBundle.foreign_limit = skuKit[0].foreign_limit
232
+ productBundle.grpdis = skuKit[0].grpdis
233
+ productBundle.is_exclusive = skuKit[0].is_exclusive
234
+ productBundle.bundle_id = skuKit[0].kit_id
235
+ productBundle.locale = skuKit[0].locale
236
+ productBundle.point_discount = skuKit[0].point_discount
237
+ productBundle.point_earn = skuKit[0].point_earn
238
+ productBundle.point_redeem = skuKit[0].point_redeem
239
+ productBundle.product_status = skuKit[0].product_status
240
+ productBundle.pvdis = skuKit[0].pvdis
241
+ productBundle.rtlpricedis = skuKit[0].rtlpricedis
242
+ productBundle.sbdis = skuKit[0].sbdis
243
+ productBundle.scan_qualified_count = skuKit[0].scan_qualified_count
244
+ productBundle.tax_class = skuKit[0].tax_class
245
+ productBundle.title = skuKit[0].title
246
+ productBundle.uid = skuKit[0].uid
247
+ productBundle.whlpricedis = skuKit[0].whlpricedis
248
+ return [productBundle]
249
+ }
250
+
251
+ const formatKit = async (products, locale, translations) => {
194
252
  for (let p = 0; p < products.length; p++) {
195
- for (let b = 0; b < products[p]?.product_bundle?.length || 0; b++) {
196
-
197
- for (
198
- let i = 0;
199
- i < (products[p].product_bundle[b].required_products || []).length;
200
- i++
201
- ) {
202
- await removeInvalidVariants(
203
- products[p].product_bundle[b].required_products[i].product,
204
- locale,
205
- translations
206
- )
253
+ let noFormat = false
254
+ if (products[p]?.sku_kit?.length > 0) {
255
+ products[p].type = "kit"
256
+ products[p].product_bundle = await convertKitToRequiredProducts(products[p].sku_kit, locale)
257
+ noFormat = true
258
+ }
259
+ if (products[p]?.product_bundle?.length > 0) {
260
+ for (let b = 0; b < products[p]?.product_bundle?.length || 0; b++) {
261
+ for (
262
+ let i = 0;
263
+ i < (products[p].product_bundle[b].required_products || []).length;
264
+ i++
265
+ ) {
266
+ await removeInvalidVariants(
267
+ products[p].product_bundle[b].required_products[i].product,
268
+ locale,
269
+ translations
270
+ )
271
+ }
272
+ for (
273
+ let i = 0;
274
+ i < (products[p].product_bundle[b].optional_products || []).length;
275
+ i++
276
+ ) {
277
+ await removeInvalidVariants(
278
+ products[p].product_bundle[b].optional_products[i].product,
279
+ locale,
280
+ translations
281
+ )
282
+ }
207
283
  }
208
- for (
209
- let i = 0;
210
- i < (products[p].product_bundle[b].optional_products || []).length;
211
- i++
212
- ) {
213
- await removeInvalidVariants(
214
- products[p].product_bundle[b].optional_products[i].product,
215
- locale,
216
- translations
217
- )
284
+ if(products[p].product_bundle?.length > 0){
285
+ products[p].bundle = formatKitWithSchema(products[p].product_bundle, noFormat)
286
+ products[p].variants = []
287
+ products[p].type = products[p].type || "bundle"
288
+ products[p].bundle[0].type = products[p].type
289
+ delete products[p].product_bundle
218
290
  }
219
- products[p].product_bundle[b].type = "bundle"
220
- }
221
- products[p].bundle = formatBundleWithSchema(products[p].product_bundle)
222
- if(products[p].product_bundle?.length > 0){
223
- products[p].variants = []
224
291
  }
225
- products[p].type = (products[p].product_bundle?.length || 0) > 0 ? "bundle" : null
226
- delete products[p].product_bundle
227
-
228
-
229
292
  }
230
293
  }
231
294
 
@@ -246,6 +309,7 @@ const csProduct = (props) => {
246
309
  url += productIncludes
247
310
  url += bundleRequiredIncludes
248
311
  url += bundlOptionalIncludes
312
+ url += kit
249
313
  }
250
314
  if (contentType === BUNDLE_TYPE) {
251
315
  url += requiredIncludes
@@ -312,8 +376,9 @@ const csProduct = (props) => {
312
376
  )
313
377
  }
314
378
  }
315
- return formatBundleWithSchema(bundles)?.[0]
379
+ return formatKitWithSchema(bundles)?.[0]
316
380
  }
381
+
317
382
  const getBundles = async (ids, locale) => {
318
383
  const query = `{ "$or": [{ "bundle_id": { "$in": ${helpers?.arrayString(ids)} }}, { "uid": { "$in": ${helpers?.arrayString(ids)} }}] }`
319
384
  const bundles = await getEntriesByQuery({
@@ -347,7 +412,7 @@ const csProduct = (props) => {
347
412
  )
348
413
  }
349
414
  }
350
- return formatBundleWithSchema(bundles)
415
+ return formatKitWithSchema(bundles)
351
416
  }
352
417
 
353
418
  const getProductsBySku = async (skus, locale) => {
@@ -360,7 +425,7 @@ const csProduct = (props) => {
360
425
 
361
426
  let products = await queryProducts(query, locale)
362
427
  const translations = await getTranslations(locale)
363
- await formatBundleKit(products, locale, translations)
428
+ await formatKit(products, locale, translations)
364
429
  await removeInvalidVariants(products, locale, translations)
365
430
  for (const product of products) {
366
431
  product.skus = skus
@@ -379,7 +444,7 @@ const csProduct = (props) => {
379
444
 
380
445
  let products = await queryProducts(query, locale)
381
446
  const translations = await getTranslations(locale)
382
- await formatBundleKit(products, locale, translations)
447
+ await formatKit(products, locale, translations)
383
448
  await removeInvalidVariants(products, locale, translations)
384
449
  return formatProductWithSchema(products)
385
450
  }
@@ -394,7 +459,7 @@ const csProduct = (props) => {
394
459
 
395
460
  const products = await queryProducts(query, locale)
396
461
  const translations = await getTranslations(locale)
397
- await formatBundleKit(products, locale, translations)
462
+ await formatKit(products, locale, translations)
398
463
  await removeInvalidVariants(products, locale, translations)
399
464
  return formatProductWithSchema(products)
400
465
  }
@@ -406,7 +471,7 @@ const csProduct = (props) => {
406
471
  const query = `{"uid": {"$in": ${helpers?.arrayString(ids)}}}`
407
472
  let products = await queryProducts(query, locale)
408
473
  const translations = await getTranslations(locale)
409
- await formatBundleKit(products, locale, translations)
474
+ await formatKit(products, locale, translations)
410
475
  await removeInvalidVariants(products, locale, translations)
411
476
  return formatProductWithSchema(products)
412
477
  }
package/src/formatKit.js CHANGED
@@ -17,9 +17,9 @@ const parseStatus = (variant) => {
17
17
  } else if(properties.productStatus) {
18
18
  let isBackordered = false
19
19
  let backorderedAvailableDate = null
20
- if (variant.skuKit) {
20
+ if (variant.kit) {
21
21
  try {
22
- const latestBODate = Math.min(...variant.skuKit.flatMap(a=>a.sku.map(s=>s.inventoryProperties.expectedBackOrderAvailabilityDate))) || 0
22
+ const latestBODate = Math.min(...variant.kit.flatMap(a=>a.sku.map(s=>s.inventoryProperties.expectedBackOrderAvailabilityDate))) || 0
23
23
  if (latestBODate) {
24
24
  isBackordered = true
25
25
  backorderedAvailableDate = moment(Date(latestBODate)).format(dateFormat)
@@ -54,24 +54,64 @@ const parseStatus = (variant) => {
54
54
  }
55
55
  };
56
56
 
57
- const parsePrice = (variant) => {
58
- const price = {}
59
- const points = {}
60
- price.currencyCode = (variant.prices || [])?.[0]?.currencyCode || (variant?.prices || [])?.[0]?.currencySymbol
61
- const priceFacets = variant?.priceFacets || {}
62
- price.retail = priceFacets['Regular Price'] || ((variant?.prices || [])[0] || {}).price
63
- price.wholesale = priceFacets['Wholesale Price'] || ((variant?.prices || [])[0] || {}).price
64
- price.retailSubscription = priceFacets['Regular Price'] || ((variant?.prices || [])[0] || {}).price
65
- price.wholesaleSubscription = priceFacets['Wholesale Price'] || ((variant?.prices || [])[0] || {}).price
66
- points.wholesale = {cv: priceFacets.CV, pv: priceFacets.PV, sb: priceFacets.SB}
67
- // Where do we pull subscription price/points from?
68
- points.subscription = {cv: priceFacets.CV, pv: priceFacets.PV, sb: priceFacets.SB}
69
- return {price, points}
57
+ const parsePrice = (product = []) => {
58
+ const requiredProducts = product.map(p => p.requiredProducts) .flat()
59
+
60
+ const variants = requiredProducts?.map(p => {
61
+ const [firstVariant] = p?.product?.variants || []
62
+ return firstVariant
63
+ })
64
+
65
+ const defaultValues = {
66
+ price : {
67
+ retail: 0,
68
+ retailSubscription : 0,
69
+ wholesale : 0,
70
+ wholesaleSubscription : 0
71
+ },
72
+ points : {
73
+ subscription : {
74
+ cv: 0,
75
+ pv: 0,
76
+ sb: 0
77
+ },
78
+ wholesale: {
79
+ cv: 0,
80
+ pv: 0,
81
+ sb: 0
82
+ }
83
+ }
84
+ }
85
+
86
+ // sum of price and points from 1st variant of product bundle
87
+ const sunOfPriceAndPoints = variants.reduce((acc, curr) => {
88
+ const price = {}
89
+ const points = {
90
+ subscription : {},
91
+ wholesale : {}
92
+ }
93
+
94
+ price.retail = Number(acc?.price?.retail || 0) + Number(curr?.price?.retail || 0)
95
+ price.retailSubscription = Number(acc?.price?.retailSubscription || 0) + Number(curr?.price?.retailSubscription || 0)
96
+ price.wholesale = Number(acc?.price?.wholesale || 0) + Number(curr?.price?.wholesale || 0)
97
+ price.wholesaleSubscription = Number(acc?.price?.wholesaleSubscription || 0) + Number(curr?.price?.wholesaleSubscription || 0)
98
+ price.currencyCode = curr?.price.currencyCode
99
+
100
+ points.subscription.cv = Number(acc?.points?.subscription?.cv || 0) + Number(curr?.points?.subscription?.cv || 0)
101
+ points.subscription.pv = Number(acc?.points?.subscription?.pv || 0) + Number(curr?.points?.subscription?.pv || 0)
102
+ points.subscription.sb = Number(acc?.points?.subscription?.sb || 0) + Number(curr?.points?.subscription?.sb || 0)
103
+ points.wholesale.cv = Number(acc?.points?.wholesale?.cv || 0) + Number(curr?.points?.wholesale?.cv || 0)
104
+ points.wholesale.pv = Number(acc?.points?.wholesale?.pv || 0) + Number(curr?.points?.wholesale?.pv || 0)
105
+ points.wholesale.sb = Number(acc?.points?.wholesale?.sb || 0) + Number(curr?.points?.wholesale?.sb || 0)
106
+
107
+ return { price, points}
108
+ }, defaultValues)
109
+ return sunOfPriceAndPoints
70
110
  }
71
111
 
72
- const parseKitAvailableQuantity = (skuKit) => {
112
+ const parseKitAvailableQuantity = (kit) => {
73
113
  try {
74
- return Math.min(...skuKit.flatMap(a=>a.sku.map(s=>s.inventoryProperties.atpQty))) || 0
114
+ return Math.min(...kit.flatMap(a=>a.sku.map(s=>s.inventoryProperties.atpQty))) || 0
75
115
  } catch {
76
116
  return 0
77
117
  }
@@ -122,16 +162,16 @@ const parseKit = (product, market) => {
122
162
  kits.status = parseStatus(product)
123
163
  if ((kits.status || {}).status === 'active') kits.status.status = 'sellable'
124
164
  const kitProducts = []
125
- if (properties.type === 'kit') {
126
- kits.type = 'skuKit'
127
- kits.availableQuantity = parseKitAvailableQuantity(product.skuKit)
128
- for (const kit of product.skuKit) {
165
+ if (properties.type === 'kit' && product.kit) {
166
+ kits.type = 'kit'
167
+ kits.availableQuantity = parseKitAvailableQuantity(product.kit)
168
+ for (const kit of product.kit || []) {
129
169
  const kitProduct = formatKit(kit, market)
130
170
  kitProduct.id = kit.identifier
131
171
  kitProducts.push({product: kitProduct, quantity: (kit.properties || {}).quantity || 0, isMandatory:true})
132
172
  }
133
- } else if (properties.type === 'bundle') {
134
- kits.type = 'bundle'
173
+ } else if (properties.type === 'bundle' || (properties.type === 'kit' && properties.requiredProducts)) {
174
+ kits.type = properties.type
135
175
  kits.availableQuantity = parseBundleAvailableQuantity(properties)
136
176
  for (const kit of properties?.requiredProducts || []) {
137
177
  if (kit.product) {
@@ -7,32 +7,32 @@ const formatProduct = (parent, homeUrl) => {
7
7
  const formattedProduct = {
8
8
  // Each value is a function with a parameter 'parent' that is the current instance of a Product
9
9
  // ContentStack references need to be queried separately (ie: variants)
10
- id: parent.uid,
11
- slug: parent?.seo_information?.slug,
12
- variantSelectLabel: parent.variant_select_label,
13
- secondaryTitle: parent.secondary_title,
14
- title: parent.name,
15
- productImages: helpers?.getProductImages(parent),
16
- salesLabel: parent.sales_label,
17
- salesText: parent.sales_text,
18
- description: entities.decodeHTML(parent.short_description || ''),
19
- salesDisclaimer: helpers?.mapSalesDisclaimer(parent.sales_disclaimer),
20
- features: helpers?.mapFeatures(parent),
21
- productDetails: helpers?.mapProductDetails(parent),
10
+ id: parent?.uid || parent?.id,
11
+ slug: parent?.seo_information?.slug || parent?.slug,
12
+ variantSelectLabel: parent?.variant_select_label || parent?.variantSelectLabel,
13
+ secondaryTitle: parent?.secondary_title || parent?.secondaryTitle,
14
+ title: parent?.name || parent?.title,
15
+ productImages: parent?.productImages || helpers?.getProductImages(parent),
16
+ salesLabel: parent?.sales_label || parent?.salesLabel,
17
+ salesText: parent?.sales_text || parent?.salesText,
18
+ description: parent?.description || entities.decodeHTML(parent?.short_description || ''),
19
+ salesDisclaimer: parent?.salesDisclaimer || helpers?.mapSalesDisclaimer(parent?.sales_disclaimer),
20
+ features: helpers?.mapFeatures(parent) || parent?.features,
21
+ productDetails: parent?.productDetails || helpers?.mapProductDetails(parent),
22
22
  benefitsMedia: {
23
- image: helpers?.mapImage(parent.benefits_media?.image),
24
- youTubeVideoId: parent.benefits_media?.youtube_video_id
23
+ image: parent?.benefitsMedia?.image || helpers?.mapImage(parent?.benefits_media?.image),
24
+ youTubeVideoId: parent?.benefitsMedia?.youTubeVideoId || parent?.benefits_media?.youtube_video_id
25
25
  },
26
- benefits: helpers?.mapBenefits(parent),
27
- benefitsAndFeatures: helpers?.mapBenefitsAndFeatures(parent),
28
- bundle: parent?.bundle,
29
- type: parent?.type,
30
- results: helpers?.mapResults(parent),
31
- sustainability: helpers?.mapSustainability(parent),
32
- usage: helpers?.mapUsage(parent, parent.legacy_usage),
33
- resources: helpers?.mapResources(parent),
34
- faqs: helpers?.mapFaqs(parent),
35
- categories: parent.categories?.map((category) => ({
26
+ benefits: helpers?.mapBenefits(parent) || parent?.benefits,
27
+ benefitsAndFeatures: parent?.benefitsAndFeatures || helpers?.mapBenefitsAndFeatures(parent),
28
+ bundle: parent?.bundle || parent?.kit,
29
+ type: parent?.type || "product",
30
+ results: helpers?.mapResults(parent) || parent?.results,
31
+ sustainability: helpers?.mapSustainability(parent) || parent?.sustainability,
32
+ usage: helpers?.mapUsage(parent, parent?.legacy_usage) || parent?.usage,
33
+ resources: helpers?.mapResources(parent) || parent?.resources,
34
+ faqs: helpers?.mapFaqs(parent) || parent?.faqs,
35
+ categories: parent?.categories?.map((category) => ({
36
36
  displayName: category.display_name,
37
37
  id: category.category_id,
38
38
  subcategories: category.subcategories?.map((subcategory) => ({
@@ -41,42 +41,46 @@ const formatProduct = (parent, homeUrl) => {
41
41
  }))
42
42
  })),
43
43
  ingredients: helpers?.mapIngredients(
44
- parent.ingredients,
45
- parent.legacy_ingredients
44
+ parent?.ingredients,
45
+ parent?.legacy_ingredients || parent?.legacyIngredients
46
46
  ),
47
- legacyBenefits: parent.legacy_benefits,
48
- legacyLongDescription: parent.legacy_long_description,
49
- legacyResources: parent.legacy_resources,
50
- legacyUsage: parent.legacy_usage,
51
- legacyIngredients: parent.legacy_ingredients,
52
- legacyImages: parent.legacy_images || [],
53
- legacyYouTube: parent.legacy_youtube_video,
54
- disclaimers: parent.disclaimers || [],
55
- disclaimerWarnings: helpers?.mapDisclaimerWarnings(
56
- parent.disclaimer_warnings
47
+ legacyBenefits: parent?.legacy_benefits || parent?.legacyBenefits,
48
+ legacyLongDescription: parent?.legacy_long_description || parent?.legacyLongDescription,
49
+ legacyResources: parent?.legacy_resources || parent?.legacyResources,
50
+ legacyUsage: parent?.legacy_usage || parent?.legacyUsage,
51
+ legacyIngredients: parent?.legacy_ingredients || parent?.legacyIngredients,
52
+ legacyImages: parent?.legacy_images || parent?.legacyImages || [],
53
+ legacyYouTube: parent?.legacy_youtube_video || parent?.legacyYouTube,
54
+ disclaimers: parent?.disclaimers || [],
55
+ disclaimerWarnings: parent?.disclaimerWarnings || helpers?.mapDisclaimerWarnings(
56
+ parent?.disclaimer_warnings
57
57
  ),
58
- seoInformation: helpers?.mapSeoInformation(parent, homeUrl),
59
- variants: helpers?.mapVariants(parent),
60
- refund: helpers?.mapRefund(parent),
61
- shipping: helpers?.mapShipping(parent),
62
- generalDisclaimer: parent.translations?.general_disclaimer_text,
63
- thirdPartyScripts: parent.third_party_scripts
58
+ seoInformation: parent?.seoInformation || helpers?.mapSeoInformation(parent, homeUrl),
59
+ variants: helpers?.mapVariants(parent) || parent?.variants,
60
+ refund: helpers?.mapRefund(parent) || parent?.refund,
61
+ shipping: helpers?.mapShipping(parent) || parent?.shipping,
62
+ generalDisclaimer: parent?.generalDisclaimer || parent?.translations?.general_disclaimer_text,
63
+ thirdPartyScripts: parent?.thirdPartyScripts || parent?.third_party_scripts
64
64
  ?.filter((tps) => tps.enabled && !!tps.script)
65
65
  ?.map((tps) => tps.script),
66
- csAtts: {
67
- version: parent._version || 0,
68
- updatedAt: parent.updated_at || '',
69
- updatedBy: parent.updated_by || '',
70
- createdAt: parent.created_at || '',
71
- createdBy: parent.created_by || '',
72
- locale: parent.locale || ''
66
+ csAtts: parent.csAtts || {
67
+ version: parent?._version || 0,
68
+ updatedAt: parent?.updated_at || '',
69
+ updatedBy: parent?.updated_by || '',
70
+ createdAt: parent?.created_at || '',
71
+ createdBy: parent?.created_by || '',
72
+ locale: parent?.locale || ''
73
73
  },
74
- relevancyRank: parent.relevancy_rank || null,
75
- warranty: helpers?.mapWarranty(parent),
76
- upSellProductIds: helpers?.mapUpSellProductIds(parent),
77
- crossProductIds: helpers?.mapCrossProductIds(parent)
74
+ relevancyRank: parent?.relevancy_rank || parent?.relevancyRank || null,
75
+ warranty: helpers?.mapWarranty(parent) || parent?.warranty,
76
+ upSellProductIds: parent?.upSellProductIds || helpers?.mapUpSellProductIds(parent),
77
+ crossProductIds: parent?.crossProductIds || helpers?.mapCrossProductIds(parent)
78
+ }
79
+ if (parent.bundle || parent.sku_kit || parent.product_bundle) {
80
+ return formatKit(formattedProduct)
81
+ } else {
82
+ return formattedProduct
78
83
  }
79
- return formatKit(formattedProduct)
80
84
  }
81
85
 
82
86
  module.exports = {
@@ -5,29 +5,29 @@ const entities = require('entities')
5
5
  const formatVariant = (parent) => ({
6
6
  // Each value is a function with a parameter 'parent' that is the current instance of a Variant
7
7
  // ContentStack references need to be queried separately
8
- id: parent?.uid,
9
- globalId: parent?.sap_data?.global_id,
10
- sku: helpers?.getBestSkuData(parent)?.sku,
8
+ id: parent?.uid || parent?.id,
9
+ globalId: parent?.sap_data?.global_id || parent?.globalId,
10
+ sku: parent?.sku || helpers?.getBestSkuData(parent)?.sku,
11
11
  slug: parent?.slug,
12
12
  size: parent?.size,
13
- variantLabel: parent?.select_label,
14
- variantColor: parent?.select_color,
15
- title: parent?.name || parent?.defaults?.name,
16
- salesLabel: parent?.sales_label,
17
- salesText: parent?.sales_text,
13
+ variantLabel: parent?.select_label || parent?.variantLabel,
14
+ variantColor: parent?.select_color || parent?.variantColor,
15
+ title: parent?.name || parent?.defaults?.name || parent?.title,
16
+ salesLabel: parent?.sales_label || parent?.salesLabel,
17
+ salesText: parent?.sales_text || parent?.salesText,
18
18
  description: entities.decodeHTML(
19
19
  parent?.short_description_override || parent?.defaults.description || ''
20
- ),
21
- salesDisclaimer: helpers?.mapSalesDisclaimer(parent?.sales_disclaimer),
22
- nettoWeight: parent?.netto_weight,
23
- productImages: helpers?.mapProductImages(parent),
24
- isExclusive: parent?.is_exclusive,
25
- pricingJson: JSON.stringify(parent?.defaults?.status?.pricing) || null,
26
- price: helpers?.mapPrice(parent),
27
- points: helpers?.mapPoints(parent),
28
- availableQuantity: _.get(parent, 'defaults.status.availableQuantity', 0),
29
- maxQuantity: _.get(parent, 'defaults.status.maxQuantity', 0),
30
- status: {
20
+ ) || parent?.description,
21
+ salesDisclaimer: helpers?.mapSalesDisclaimer(parent?.sales_disclaimer) || parent?.salesDisclaimer,
22
+ nettoWeight: parent?.netto_weight || parent?.nettoWeight,
23
+ productImages: parent?.productImages || helpers?.mapProductImages(parent),
24
+ isExclusive: parent?.is_exclusive || parent?.isExclusive,
25
+ pricingJson: parent?.pricingJson || JSON.stringify(parent?.defaults?.status?.pricing) || null,
26
+ price: helpers?.mapPrice(parent) || parent?.price,
27
+ points: helpers?.mapPoints(parent) || parent?.points,
28
+ availableQuantity: parent?.availableQuantity || _.get(parent, 'defaults.status.availableQuantity', 0),
29
+ maxQuantity: parent?.maxQuantity || _.get(parent, 'defaults.status.maxQuantity', 0),
30
+ status: parent?.status || {
31
31
  status: _.get(parent, 'defaults.status.status.retail', null),
32
32
  retail: _.get(parent, 'defaults.status.status.retail', null),
33
33
  wholesale: _.get(parent, 'defaults.status.status.wholesale', null),
@@ -38,33 +38,33 @@ const formatVariant = (parent) => ({
38
38
  ''
39
39
  )
40
40
  },
41
- csStatus: helpers?.mapCsStatus(parent),
42
- purchaseTypes: helpers?.mapPurchaseTypes(parent),
43
- features: helpers?.mapFeatures(parent),
44
- productDetails: helpers?.mapProductDetails(parent),
45
- ingredients: helpers?.mapIngredients(
41
+ csStatus: parent?.csStatus || helpers?.mapCsStatus(parent),
42
+ purchaseTypes: parent?.purchaseTypes || helpers?.mapPurchaseTypes(parent),
43
+ features: helpers?.mapFeatures(parent) || parent?.features,
44
+ productDetails: parent?.productDetails || helpers?.mapProductDetails(parent),
45
+ ingredients: parent?.ingredients || helpers?.mapIngredients(
46
46
  parent.ingredients_override,
47
47
  parent.legacy_ingredients
48
48
  ),
49
- benefitsAndFeatures: helpers?.mapBenefitsAndFeatures(parent),
50
- results: helpers?.mapResults(parent),
51
- usage: helpers?.mapUsage(parent, parent.legacy_usage),
52
- resources: helpers?.mapResources(parent),
53
- faqs: helpers?.mapFaqs(parent),
54
- disclaimers: parent.disclaimers || [],
55
- disclaimerWarnings: helpers?.mapDisclaimerWarnings(
49
+ benefitsAndFeatures: parent?.benefitsAndFeatures || helpers?.mapBenefitsAndFeatures(parent),
50
+ results: helpers?.mapResults(parent) || parent?.results,
51
+ usage: helpers?.mapUsage(parent, parent.legacy_usage) || parent?.usage,
52
+ resources: helpers?.mapResources(parent) || parent?.resources,
53
+ faqs: helpers?.mapFaqs(parent) || parent?.faqs,
54
+ disclaimers: parent?.disclaimers || [],
55
+ disclaimerWarnings: parent?.disclaimerWarnings || helpers?.mapDisclaimerWarnings(
56
56
  parent.disclaimer_warnings
57
57
  ),
58
- matchingVariant:
58
+ matchingVariant: parent?.matchingVariant ||
59
59
  parent.sap_data?.sku_data?.findIndex((s) =>
60
60
  parent.searchedSkus.includes(s.sku)
61
61
  ) > -1,
62
- shadeable: parent.shadeable || false,
63
- restrictedMarkets: parent.restricted_markets || [],
64
- productType: parent?.sap_data?.product_type,
65
- primaryBrand: parent.sap_data?.primary_brand,
66
- brandFamily: parent?.sap_data?.brand_family,
67
- marketAttributes: {
62
+ shadeable: parent?.shadeable || false,
63
+ restrictedMarkets: parent?.restricted_markets || parent?.restrictedMarkets || [],
64
+ productType: parent?.sap_data?.product_type || parent?.productType,
65
+ primaryBrand: parent.sap_data?.primary_brand || parent?.primaryBrand,
66
+ brandFamily: parent?.sap_data?.brand_family || parent?.brandFamily,
67
+ marketAttributes: parent?.marketAttributes || {
68
68
  discount: _.get(
69
69
  parent,
70
70
  'defaults.status.marketAttributes.discount',
@@ -73,14 +73,14 @@ const formatVariant = (parent) => ({
73
73
  redeem: _.get(parent, 'defaults.status.marketAttributes.redeem', null),
74
74
  earn: _.get(parent, 'defaults.status.marketAttributes.earn', null)
75
75
  },
76
- legacyBenefits: parent.legacy_benefits,
77
- legacyLongDescription: parent.legacy_long_description,
78
- legacyResources: parent.legacy_resources,
79
- legacyUsage: parent.legacy_usage,
80
- legacyIngredients: parent.legacy_ingredients,
81
- legacyImages: parent.legacy_images || [],
82
- legacyYouTube: parent.legacy_youtube_video,
83
- csAtts: {
76
+ legacyBenefits: parent.legacy_benefits || parent?.legacyBenefits,
77
+ legacyLongDescription: parent.legacy_long_description || parent?.legacyLongDescription,
78
+ legacyResources: parent.legacy_resources || parent?.legacyResources,
79
+ legacyUsage: parent.legacy_usage || parent?.legacyResources,
80
+ legacyIngredients: parent.legacy_ingredients || parent?.legacyIngredients,
81
+ legacyImages: parent.legacy_images || parent?.legacyImages || [],
82
+ legacyYouTube: parent.legacy_youtube_video || parent?.legacyYouTube,
83
+ csAtts: parent?.csAtts || {
84
84
  version: parent._version || 0,
85
85
  updatedAt: parent.updated_at || '',
86
86
  updatedBy: parent.updated_by || '',
@@ -88,24 +88,24 @@ const formatVariant = (parent) => ({
88
88
  createdBy: parent.created_by || '',
89
89
  locale: parent.locale || ''
90
90
  },
91
- searchKeywords: parent.search_keywords,
92
- excludeFromSearch: parent.exclude_from_search || helpers?.mapCsStatus(parent).status === 'discontinued' || _.get(parent, 'defaults.status.status.retail', null) === 'DISCONTINUED',
93
- customerTypes: helpers?.getBestSkuData(parent)?.status_selections
91
+ searchKeywords: parent?.search_keywords || parent?.searchKeywords,
92
+ excludeFromSearch: parent?.exclude_from_search || parent?.excludeFromSearch || helpers?.mapCsStatus(parent).status === 'discontinued' || _.get(parent, 'defaults.status.status.retail', null) === 'DISCONTINUED',
93
+ customerTypes: parent?.customerTypes || helpers?.getBestSkuData(parent)?.status_selections
94
94
  ?.customer_types,
95
- availableChannels: helpers?.getBestSkuData(parent)?.status_selections
95
+ availableChannels: parent?.availableChannels || helpers?.getBestSkuData(parent)?.status_selections
96
96
  ?.display_channels,
97
- displayChannels: helpers?.getBestSkuData(parent)?.status_selections
97
+ displayChannels: parent?.displayChannels || helpers?.getBestSkuData(parent)?.status_selections
98
98
  ?.display_channels,
99
- scanQualifiedCount: helpers?.getBestSkuData(parent)?.status_selections
99
+ scanQualifiedCount: parent?.scanQualifiedCount || helpers?.getBestSkuData(parent)?.status_selections
100
100
  ?.scan_qualify_count,
101
- scanQualifyCount: helpers?.getBestSkuData(parent)?.status_selections
101
+ scanQualifyCount: parent?.scanQualifyCount || helpers?.getBestSkuData(parent)?.status_selections
102
102
  ?.scan_qualify_count,
103
- chargeShipping: helpers?.getBestSkuData(parent)?.charge_shipping,
104
- dangerousGoods: helpers?.getBestSkuData(parent)?.dangerous_goods,
105
- channels: helpers?.getBestSkuData(parent)?.channels,
106
- foreignLimit: helpers?.getBestSkuData(parent)?.foreign_limit,
107
- foreignOrderLimit: helpers?.getBestSkuData(parent)?.foreign_limit,
108
- orderType: parent.sap_data?.order_type
103
+ chargeShipping: parent?.chargeShipping || helpers?.getBestSkuData(parent)?.charge_shipping,
104
+ dangerousGoods: parent?.dangerousGoods || helpers?.getBestSkuData(parent)?.dangerous_goods,
105
+ channels: parent?.channels || helpers?.getBestSkuData(parent)?.channels,
106
+ foreignLimit: parent?.foreignLimit || helpers?.getBestSkuData(parent)?.foreign_limit,
107
+ foreignOrderLimit: parent?.foreignOrderLimit || helpers?.getBestSkuData(parent)?.foreign_limit,
108
+ orderType: parent?.orderType || parent.sap_data?.order_type
109
109
  })
110
110
 
111
111
  module.exports = {
package/src/helpers.js CHANGED
@@ -20,7 +20,7 @@ function mapBrandStyle(feature, type) {
20
20
  // otherwise make text white, and use feature.background_color if it exists or default the background color to be #4f4d4d if not
21
21
  const isBrandStyle = feature.brand_style && Array.isArray(feature.brand_style) && feature.brand_style.length > 0;
22
22
  // eslint-disable-next-line no-nested-ternary
23
- const backgroundColor = isBrandStyle ? feature.brand_style[0].background_color : feature.background_color.length > 1 ? feature.background_color : '#4f4d4d';
23
+ const backgroundColor = isBrandStyle ? feature.brand_style[0].background_color : feature.background_color?.length > 1 ? feature.background_color : '#4f4d4d';
24
24
  const textColor = isBrandStyle && feature.brand_style[0].background_color?.length > 0 ? '#000000' : '#ffffff';
25
25
 
26
26
  switch (type) {
@@ -120,21 +120,21 @@ function mapSubscriptions(subscriptions) {
120
120
 
121
121
  /* istanbul ignore next */
122
122
  function mapProductImages(parent) {
123
- if ((parent.product_images_bynder || []).length) {
124
- return parent.product_images_bynder.map((img) => mapImage(img))
123
+ if ((parent?.product_images_bynder || []).length) {
124
+ return parent?.product_images_bynder.map((img) => mapImage(img))
125
125
  }
126
- if ((parent.product_images || []).length) {
127
- return parent.product_images.map((img) => mapImage(img))
128
- } else if ((parent.baseImages || []).length) {
129
- return parent.baseImages
126
+ if ((parent?.product_images || []).length) {
127
+ return parent?.product_images.map((img) => mapImage(img))
128
+ } else if ((parent?.baseImages || []).length) {
129
+ return parent?.baseImages
130
130
  }
131
- return (parent.legacy_images || []).length
132
- ? parent.legacy_images.map((img) => ({
131
+ return (parent?.legacy_images || []).length
132
+ ? parent?.legacy_images.map((img) => ({
133
133
  url: img,
134
134
  alt: '',
135
135
  thumbnail: img
136
136
  }))
137
- : parent.legacyImages || []
137
+ : parent?.legacyImages || []
138
138
  }
139
139
 
140
140
  /* istanbul ignore next */
@@ -251,32 +251,32 @@ const getProductImages = (parent = {}) => {
251
251
 
252
252
  function mapRefund(parent) {
253
253
  return {
254
- message: parent.translations
255
- ? (parent.translations.common_strings_overrides.refund || {}).message ||
256
- (parent.translations.common_strings.product || {}).refundMessage: '',
257
- linkText: parent.translations
258
- ? (parent.translations.common_strings_overrides.refund || {})
254
+ message: parent?.translations
255
+ ? (parent?.translations.common_strings_overrides.refund || {}).message ||
256
+ (parent?.translations.common_strings.product || {}).refundMessage: '',
257
+ linkText: parent?.translations
258
+ ? (parent?.translations.common_strings_overrides.refund || {})
259
259
  .link_text ||
260
- (parent.translations.common_strings.product || {}).refundLinkText: '',
261
- linkUrl: parent.translations
262
- ? (parent.translations.common_strings_overrides.refund || {})
260
+ (parent?.translations.common_strings.product || {}).refundLinkText: '',
261
+ linkUrl: parent?.translations
262
+ ? (parent?.translations.common_strings_overrides.refund || {})
263
263
  .link_url ||
264
- (parent.translations.common_strings.product || {}).refundLinkUrl
264
+ (parent?.translations.common_strings.product || {}).refundLinkUrl
265
265
  : ''
266
266
  }
267
267
  }
268
268
 
269
269
  function mapShipping(parent) {
270
270
  return {
271
- message: parent.translations
272
- ? (parent.translations.common_strings_overrides.shipping || {})
271
+ message: parent?.translations
272
+ ? (parent?.translations.common_strings_overrides.shipping || {})
273
273
  .message ||
274
- (parent.translations.common_strings.product || {}).shippingMessage
274
+ (parent?.translations.common_strings.product || {}).shippingMessage
275
275
  : '',
276
- boldText: parent.translations
277
- ? (parent.translations.common_strings_overrides.shipping || {})
276
+ boldText: parent?.translations
277
+ ? (parent?.translations.common_strings_overrides.shipping || {})
278
278
  .bold_text ||
279
- (parent.translations.common_strings.product || {})
279
+ (parent?.translations.common_strings.product || {})
280
280
  .shippingBoldText
281
281
  : ''
282
282
  }
@@ -284,27 +284,27 @@ function mapShipping(parent) {
284
284
 
285
285
  /* istanbul ignore next */
286
286
  function mapVariants(parent) {
287
- const _variants = (parent.variants || []).map((variant) => ({
287
+ const _variants = (parent?.variants || []).map((variant) => ({
288
288
  ...variant,
289
- country: parent.country,
290
- locale: parent.locale,
291
- searchedSkus: Array.isArray(parent.skus) ? parent.skus : [parent.skus],
289
+ country: parent?.country,
290
+ locale: parent?.locale,
291
+ searchedSkus: Array.isArray(parent?.skus) ? parent?.skus : [parent?.skus],
292
292
  baseImages: getProductImages(parent),
293
- legacyImages: (parent.legacy_images || []).map((img) => ({
293
+ legacyImages: (parent?.legacy_images || []).map((img) => ({
294
294
  url: img,
295
295
  alt: '',
296
296
  thumbnail: img
297
297
  })),
298
298
  defaults: {
299
- name: `${parent.name} ${
299
+ name: `${parent?.name} ${
300
300
  variant.select_label ? variant.select_label : ''
301
301
  }`,
302
- description: parent.short_description,
302
+ description: parent?.short_description,
303
303
  productDetailsDescription: Array.isArray(
304
- (parent.product_details || {}).long_description
304
+ (parent?.product_details || {}).long_description
305
305
  )
306
- ? (parent.product_details || {}).long_description
307
- : [(parent.product_details || {}).long_description],
306
+ ? (parent?.product_details || {}).long_description
307
+ : [(parent?.product_details || {}).long_description],
308
308
  status: variant.status || {},
309
309
  marketData: variant.marketData
310
310
  }
@@ -315,14 +315,14 @@ function mapVariants(parent) {
315
315
  function mapSeoInformation(parent, homeUrl) {
316
316
  const { ogImage } = parent?.seo_information || {}
317
317
  const seoData = {
318
- metaTitle: parent?.seo_information?.meta_title || parent.name,
318
+ metaTitle: parent?.seo_information?.meta_title || parent?.name,
319
319
  metaDescription:
320
- parent.seo_information?.meta_description ||
320
+ parent?.seo_information?.meta_description ||
321
321
  parent?.short_description,
322
322
  canonicalURL: `${homeUrl}/catalog/${
323
- parent.localeData?.country
324
- }/${parent.localeData?.language}/product/${
325
- parent?.seo_information?.slug || parent.sku
323
+ parent?.localeData?.country
324
+ }/${parent?.localeData?.language}/product/${
325
+ parent?.seo_information?.slug || parent?.sku
326
326
  }`,
327
327
  ogImage: { url: '', alt: '' }
328
328
  }
@@ -352,6 +352,7 @@ function mapPoints(parent) {
352
352
  return {
353
353
  wholesale: {
354
354
  cv:
355
+ _.get(parent, 'points.wholesale.cv', null) ||
355
356
  _.get(
356
357
  parent,
357
358
  'defaults.status.pricing.wholesale.webOrder.cv',
@@ -363,6 +364,7 @@ function mapPoints(parent) {
363
364
  null
364
365
  ),
365
366
  pv:
367
+ _.get(parent, 'points.wholesale.pv', null) ||
366
368
  _.get(
367
369
  parent,
368
370
  'defaults.status.pricing.wholesale.webOrder.pv',
@@ -376,6 +378,7 @@ function mapPoints(parent) {
376
378
  },
377
379
  subscription: {
378
380
  cv:
381
+ _.get(parent, 'points.subscription.cv', null) ||
379
382
  _.get(
380
383
  parent,
381
384
  'defaults.status.pricing.wholesale.WADW.cv',
@@ -387,6 +390,7 @@ function mapPoints(parent) {
387
390
  null
388
391
  ),
389
392
  pv:
393
+ _.get(parent, 'points.subscription.pv', null) ||
390
394
  _.get(
391
395
  parent,
392
396
  'defaults.status.pricing.wholesale.WADW.pv',
@@ -400,18 +404,22 @@ function mapPoints(parent) {
400
404
  function mapPrice(parent) {
401
405
  return {
402
406
  retail:
407
+ _.get(parent, 'price.retail', null) ||
403
408
  _.get(
404
409
  parent,
405
410
  'defaults.status.pricing.retail.webOrder.price',
406
411
  null
407
412
  ) ||
408
413
  _.get(parent, 'defaults.status.pricing.retail.order.price', null),
409
- retailSubscription: _.get(
410
- parent,
411
- 'defaults.status.pricing.retail.webAdr.price',
412
- null
413
- ),
414
+ retailSubscription:
415
+ _.get(parent, 'price.retailSubscription', null) ||
416
+ _.get(
417
+ parent,
418
+ 'defaults.status.pricing.retail.webAdr.price',
419
+ null
420
+ ),
414
421
  wholesale:
422
+ _.get(parent, 'price.wholesale', null) ||
415
423
  _.get(
416
424
  parent,
417
425
  'defaults.status.pricing.wholesale.webOrder.price',
@@ -423,6 +431,7 @@ function mapPrice(parent) {
423
431
  null
424
432
  ),
425
433
  wholesaleSubscription:
434
+ _.get(parent, 'price.wholesaleSubscription', null) ||
426
435
  _.get(
427
436
  parent,
428
437
  'defaults.status.pricing.wholesale.ADR5.price',
@@ -491,12 +500,12 @@ function mapLink(link) {
491
500
 
492
501
  function mapProductDetails(productOrVariant) {
493
502
  const productDetails = (productOrVariant || {}).product_details || {}
494
- if ((productOrVariant.long_description_override || []).length > 0) {
503
+ if ((productOrVariant?.long_description_override || []).length > 0) {
495
504
  productDetails.long_description =
496
- productOrVariant.long_description_override
505
+ productOrVariant?.long_description_override
497
506
  }
498
- if ((productOrVariant.included_items_override || []).length > 0) {
499
- productDetails.included_items = productOrVariant.included_items_override
507
+ if ((productOrVariant?.included_items_override || []).length > 0) {
508
+ productDetails.included_items = productOrVariant?.included_items_override
500
509
  }
501
510
  let description = productDetails.long_description
502
511
  if (!Array.isArray(description)) {
@@ -585,7 +594,7 @@ function benefitsToMarkdown(legacyBenefits, jsonBenefits) {
585
594
 
586
595
  function mapBenefits(parent) {
587
596
  if (parent?.benefits?.length > 0) {
588
- return parent.benefits.map((benefit) => ({
597
+ return parent?.benefits.map((benefit) => ({
589
598
  title: benefit.header,
590
599
  benefits: benefit.benefits || []
591
600
  }))
@@ -597,48 +606,48 @@ function mapBenefits(parent) {
597
606
  function mapBenefitsAndFeatures(productOrVariant) {
598
607
  let benefitsMedia = (productOrVariant || {}).benefits_media || {}
599
608
  const legacyBenefits = Array.isArray((productOrVariant || {}).benefits)
600
- ? productOrVariant.benefits
609
+ ? productOrVariant?.benefits
601
610
  : []
602
611
  if (
603
612
  (productOrVariant || {}).benefits &&
604
- (productOrVariant.benefits.image ||
605
- productOrVariant.benefits.youtube_video_id)
613
+ (productOrVariant?.benefits.image ||
614
+ productOrVariant?.benefits.youtube_video_id)
606
615
  ) {
607
616
  benefitsMedia = {
608
- image: Array.isArray(productOrVariant.benefits.image)
609
- ? productOrVariant.benefits.image[0]
610
- : productOrVariant.benefits.image,
611
- youTubeVideoId: productOrVariant.benefits.youtube_video_id
617
+ image: Array.isArray(productOrVariant?.benefits.image)
618
+ ? productOrVariant?.benefits.image[0]
619
+ : productOrVariant?.benefits.image,
620
+ youTubeVideoId: productOrVariant?.benefits.youtube_video_id
612
621
  }
613
622
  }
614
623
  // Account for new section in Product
615
624
  if (
616
625
  (productOrVariant || {}).benefits_and_key_features &&
617
626
  rteHasContent((productOrVariant || {}).benefits_and_key_features) &&
618
- (productOrVariant.benefits_and_key_features.image ||
619
- productOrVariant.benefits_and_key_features.youtube_video_id)
627
+ (productOrVariant?.benefits_and_key_features.image ||
628
+ productOrVariant?.benefits_and_key_features.youtube_video_id)
620
629
  ) {
621
630
  benefitsMedia = {
622
631
  image: Array.isArray(
623
- productOrVariant.benefits_and_key_features.image
632
+ productOrVariant?.benefits_and_key_features.image
624
633
  )
625
- ? productOrVariant.benefits_and_key_features.image[0]
626
- : productOrVariant.benefits_and_key_features.image,
634
+ ? productOrVariant?.benefits_and_key_features.image[0]
635
+ : productOrVariant?.benefits_and_key_features.image,
627
636
  youTubeVideoId:
628
- productOrVariant.benefits_and_key_features.youtube_video_id
637
+ productOrVariant?.benefits_and_key_features.youtube_video_id
629
638
  }
630
639
  }
631
640
  let jsonBenefits =
632
641
  (productOrVariant || {}).benefits &&
633
- productOrVariant.benefits.benefits &&
634
- productOrVariant.benefits.benefits.type
635
- ? productOrVariant.benefits.benefits
642
+ productOrVariant?.benefits.benefits &&
643
+ productOrVariant?.benefits.benefits.type
644
+ ? productOrVariant?.benefits.benefits
636
645
  : null
637
646
  // Account for new section in Product
638
647
  jsonBenefits =
639
648
  (productOrVariant || {}).benefits_and_key_features &&
640
- productOrVariant.benefits_and_key_features.benefits
641
- ? productOrVariant.benefits_and_key_features.benefits
649
+ productOrVariant?.benefits_and_key_features.benefits
650
+ ? productOrVariant?.benefits_and_key_features.benefits
642
651
  : jsonBenefits
643
652
 
644
653
  return {
@@ -750,17 +759,17 @@ function mapResource(resource) {
750
759
  /* istanbul ignore next */
751
760
  function mapResources(productOrVariant) {
752
761
  if (
753
- productOrVariant.resources &&
754
- Array.isArray(productOrVariant.resources) &&
755
- productOrVariant.resources.length > 0
762
+ productOrVariant?.resources &&
763
+ Array.isArray(productOrVariant?.resources) &&
764
+ productOrVariant?.resources.length > 0
756
765
  ) {
757
- return productOrVariant.resources.map((resource) =>
766
+ return productOrVariant?.resources.map((resource) =>
758
767
  mapResource(resource)
759
768
  )
760
769
  }
761
770
  try {
762
771
  const legacyResources = JSON.parse(
763
- productOrVariant.legacy_resources || '[]'
772
+ productOrVariant?.legacy_resources || '[]'
764
773
  )
765
774
  return (legacyResources || []).map((resource) => ({
766
775
  title: resource.title,
@@ -2,37 +2,37 @@ const helpers = require('./helpers')
2
2
 
3
3
  /* istanbul ignore next */
4
4
  const transformBundle = (parent, homeUrl) => ({
5
- id: parent.bundle_id,
6
- uid: parent.uid,
7
- title: parent.title,
8
- type: parent.type,
9
- requiredProducts: parent.required_products?.map((r) => ({
5
+ id: parent?.bundle_id || parent?.kit_id,
6
+ uid: parent?.uid,
7
+ title: parent?.name,
8
+ type: parent?.type,
9
+ requiredProducts: parent?.required_products?.map((r) => ({
10
10
  product: r?.product?.[0],
11
11
  quantity: r.quantity
12
12
  })),
13
- optionalProducts: parent.optional_products?.map((o) => ({
13
+ optionalProducts: parent?.optional_products?.map((o) => ({
14
14
  product: o?.product?.[0],
15
15
  quantity: o.quantity
16
16
  })),
17
- retailDiscount: parent.rtlpricedis || 0,
18
- wholesaleDiscount: parent.whlpricedis || 0,
19
- pvDiscount: parent.pvdis || 0,
20
- cvDiscount: parent.cvdis || 0,
21
- sbDiscount: parent.sbdis || 0,
22
- grpDiscount: parent.grpdis || 0,
23
- shortDescription: parent.short_description,
24
- description: helpers?.createMarkdown(parent.description),
25
- salesLabel: parent.sales_label,
26
- salesText: parent.sales_text,
17
+ retailDiscount: parent?.rtlpricedis || 0,
18
+ wholesaleDiscount: parent?.whlpricedis || 0,
19
+ pvDiscount: parent?.pvdis || 0,
20
+ cvDiscount: parent?.cvdis || 0,
21
+ sbDiscount: parent?.sbdis || 0,
22
+ grpDiscount: parent?.grpdis || 0,
23
+ shortDescription: parent?.short_description,
24
+ description: helpers?.createMarkdown(parent?.description),
25
+ salesLabel: parent?.sales_label,
26
+ salesText: parent?.sales_text,
27
27
  features: {
28
28
  image: helpers?.mapImage(parent?.features?.image),
29
29
  subtitle: parent?.features?.header,
30
30
  features: parent?.features?.features,
31
31
  backgroundColor: parent?.features?.background_color
32
32
  },
33
- disclaimers: parent.disclaimers || [],
33
+ disclaimers: parent?.disclaimers || [],
34
34
  disclaimerWarnings: helpers?.mapDisclaimerWarnings(
35
- parent.disclaimer_warnings
35
+ parent?.disclaimer_warnings
36
36
  ),
37
37
  seoInformation: helpers?.mapSeoInformation(parent, homeUrl),
38
38
  resources: helpers?.mapResources(parent),
@@ -44,22 +44,22 @@ const transformBundle = (parent, homeUrl) => ({
44
44
  id: subcategory.category_id
45
45
  }))
46
46
  })),
47
- availableChannels: parent.product_status.display_channels,
48
- customerTypes: parent.product_status.customer_types,
47
+ availableChannels: parent?.product_status.display_channels,
48
+ customerTypes: parent?.product_status.customer_types,
49
49
  status: {
50
- status: parent.product_status.status,
51
- wholesale: parent.product_status.status,
52
- retail: parent.product_status.status
50
+ status: parent?.product_status.status,
51
+ wholesale: parent?.product_status.status,
52
+ retail: parent?.product_status.status
53
53
  },
54
- taxClass: parent.tax_class,
55
- foreignOrderLimit: parent.foreign_limit,
56
- scanQualifiedCount: parent.scan_qualified_count,
57
- chargeShipping: parent.charge_shipping,
58
- dangerousGoods: parent.dangerous_goods,
54
+ taxClass: parent?.tax_class,
55
+ foreignOrderLimit: parent?.foreign_limit,
56
+ scanQualifiedCount: parent?.scan_qualified_count,
57
+ chargeShipping: parent?.charge_shipping,
58
+ dangerousGoods: parent?.dangerous_goods,
59
59
  marketAttributes: {
60
- discount: parent.point_discount,
61
- redeem: parent.point_redeem,
62
- earn: parent.point_earn
60
+ discount: parent?.point_discount,
61
+ redeem: parent?.point_redeem,
62
+ earn: parent?.point_earn
63
63
  }
64
64
  })
65
65