@nuskin/ns-shop 7.1.0-brw-988.1 → 7.1.0
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 +6 -4
- package/src/cart/cart.js +12 -1
- package/src/cart/cartService.js +35 -5
- package/src/cart/csProductHelper.js +274 -0
- package/src/cart/equinoxCartService.js +25 -14
- package/src/cart/productService.js +54 -46
- package/src/order/orderAdapter.js +17 -7
- package/src/payment/externalPaymentService.js +7 -1
- package/src/product/SolrQueryService.js +181 -218
- package/src/product/productSearchService.js +1 -8
- package/src/salesEventService.js +60 -72
- package/src/shipping/pickupUtil.js +96 -2
- package/src/product/productSearchAPIQueryService.js +0 -389
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuskin/ns-shop",
|
|
3
|
-
"version": "7.1.0
|
|
3
|
+
"version": "7.1.0",
|
|
4
4
|
"description": "The description that will amaze and astound your audience when they read it",
|
|
5
5
|
"main": "src/shop.js",
|
|
6
6
|
"scripts": {
|
|
@@ -26,8 +26,10 @@
|
|
|
26
26
|
"@nuskin/ns-common-lib": "1.4.7",
|
|
27
27
|
"@nuskin/ns-feature-flags": "1.4.7",
|
|
28
28
|
"@nuskin/ns-loyalty-web": "1.5.6",
|
|
29
|
-
"@nuskin/ns-product-lib": "2.
|
|
29
|
+
"@nuskin/ns-product-lib": "2.19.1",
|
|
30
30
|
"@nuskin/nuskinjquery": "2.3.1",
|
|
31
|
+
"@nuskin/order-model": "3.1.3",
|
|
32
|
+
"@nuskin/product-lib": "2.2.1",
|
|
31
33
|
"axios": "1.6.5",
|
|
32
34
|
"decimal.js": "10.4.3",
|
|
33
35
|
"jp-conversion": "0.0.7",
|
|
@@ -40,8 +42,8 @@
|
|
|
40
42
|
"@nuskin/exclusive-offer-sdk": "1.2.4",
|
|
41
43
|
"@nuskin/ns-account": "5.9.2",
|
|
42
44
|
"@nuskin/ns-jsanalyzer": "1.0.1",
|
|
43
|
-
"@nuskin/ns-product": "3.50.
|
|
44
|
-
"@nuskin/ns-util": "4.
|
|
45
|
+
"@nuskin/ns-product": "3.50.5",
|
|
46
|
+
"@nuskin/ns-util": "4.6.1",
|
|
45
47
|
"axios-mock-adapter": "1.22.0",
|
|
46
48
|
"babel-cli": "6.26.0",
|
|
47
49
|
"babel-core": "6.26.3",
|
package/src/cart/cart.js
CHANGED
|
@@ -832,9 +832,12 @@ export default function Cart(cartData) {
|
|
|
832
832
|
};
|
|
833
833
|
|
|
834
834
|
this.updateProductEventPrice = function(item, activeEvents) {
|
|
835
|
+
let eventNameAdded = false;
|
|
835
836
|
const user = UserService.getUser();
|
|
836
837
|
const priceType = ShopContext.getPriceType(item.isAdr(), user);
|
|
838
|
+
const eventName = item.product.eventName;
|
|
837
839
|
if (item.product.setPriceAndPvFromType(priceType, activeEvents)) {
|
|
840
|
+
if (!eventName && item.product.eventName) eventNameAdded = true;
|
|
838
841
|
SalesEventService.logAnalyticInfo(
|
|
839
842
|
'product-price-to-event-price',
|
|
840
843
|
item.product.eventName,
|
|
@@ -848,15 +851,20 @@ export default function Cart(cartData) {
|
|
|
848
851
|
}
|
|
849
852
|
});
|
|
850
853
|
}
|
|
854
|
+
return eventNameAdded;
|
|
851
855
|
};
|
|
852
856
|
|
|
853
857
|
this.updateEventPrices = function(activeEvents) {
|
|
858
|
+
let eventNameAdded = false;
|
|
854
859
|
getCartItems({cartItems: true}).forEach(item => {
|
|
855
|
-
this.updateProductEventPrice(item, activeEvents)
|
|
860
|
+
if (this.updateProductEventPrice(item, activeEvents))
|
|
861
|
+
eventNameAdded = true;
|
|
856
862
|
});
|
|
863
|
+
return eventNameAdded;
|
|
857
864
|
};
|
|
858
865
|
|
|
859
866
|
this.setMissingEventNames = async (order) => {
|
|
867
|
+
let cartUpdated = false;
|
|
860
868
|
const orderItems = this.getItems({cartOrderItems: true});
|
|
861
869
|
let nameSet = new Set();
|
|
862
870
|
let itemsChecked = [];
|
|
@@ -875,6 +883,7 @@ export default function Cart(cartData) {
|
|
|
875
883
|
if (itemEvents.includes(ien)) {
|
|
876
884
|
// set this items eventName if another item already has it set.
|
|
877
885
|
item.product.eventName = ien;
|
|
886
|
+
cartUpdated = true;
|
|
878
887
|
}
|
|
879
888
|
return !!item.product.eventName; // causes loop to stop if true
|
|
880
889
|
});
|
|
@@ -896,6 +905,7 @@ export default function Cart(cartData) {
|
|
|
896
905
|
itemEvents.some((ie) => {
|
|
897
906
|
if (eventStatuses[ie]) {
|
|
898
907
|
// set the status if event is active.
|
|
908
|
+
cartUpdated = true;
|
|
899
909
|
item.product.eventName == ie;
|
|
900
910
|
SalesEventService.logAnalyticInfo(
|
|
901
911
|
'cart-eventname-fixed', ie,
|
|
@@ -906,6 +916,7 @@ export default function Cart(cartData) {
|
|
|
906
916
|
})
|
|
907
917
|
});
|
|
908
918
|
}
|
|
919
|
+
return cartUpdated;
|
|
909
920
|
}
|
|
910
921
|
|
|
911
922
|
this.getCartInfo = function(options) {
|
package/src/cart/cartService.js
CHANGED
|
@@ -34,6 +34,7 @@ export default {
|
|
|
34
34
|
hasItems,
|
|
35
35
|
hasEventItems,
|
|
36
36
|
hasPreviewItems,
|
|
37
|
+
hasDangerousGoods,
|
|
37
38
|
getItemCnt,
|
|
38
39
|
addProductToCart,
|
|
39
40
|
addSkuToCart,
|
|
@@ -229,10 +230,23 @@ function updateItemPrices() {
|
|
|
229
230
|
}
|
|
230
231
|
|
|
231
232
|
async function checkForMissingEventNames(order) {
|
|
233
|
+
let outOfSync = false;
|
|
232
234
|
await awaitForConfig();
|
|
233
235
|
const cart = _getCart();
|
|
234
|
-
|
|
236
|
+
|
|
237
|
+
// check to see if cart item has eventName but sapItem does not.
|
|
238
|
+
const orderItems = cart.getItems({cartOrderItems: true});
|
|
239
|
+
orderItems.map((item) => {
|
|
240
|
+
const sapItem = order.sapItems.find((sapItem) => (
|
|
241
|
+
sapItem.sku === item.product.sku && sapItem.isAdr === item.adr
|
|
242
|
+
));
|
|
243
|
+
if (sapItem && item.product.eventName && !sapItem.eventName)
|
|
244
|
+
outOfSync = true;
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
let updated = await cart.setMissingEventNames(order);
|
|
235
248
|
setCart(cart);
|
|
249
|
+
return updated || outOfSync;
|
|
236
250
|
}
|
|
237
251
|
|
|
238
252
|
function getCartProperty(key) {
|
|
@@ -285,6 +299,14 @@ function hasPreviewItems() {
|
|
|
285
299
|
return _getCart().hasPreviewItems();
|
|
286
300
|
}
|
|
287
301
|
|
|
302
|
+
function hasDangerousGoods(options = {cartOrderItems: true}) {
|
|
303
|
+
let retVal = false;
|
|
304
|
+
_getCart().getItems(options).forEach((item) => {
|
|
305
|
+
retVal = retVal || item.product.dangerousGoods;
|
|
306
|
+
});
|
|
307
|
+
return retVal;
|
|
308
|
+
}
|
|
309
|
+
|
|
288
310
|
function getItemCnt(options) {
|
|
289
311
|
return _getCart().getItemCnt(options);
|
|
290
312
|
}
|
|
@@ -354,10 +376,11 @@ async function addProductToCart(options) {
|
|
|
354
376
|
}
|
|
355
377
|
|
|
356
378
|
options.product.isBackOrdered = (options.product.inventory === "BACKORDER") ? true : false
|
|
357
|
-
|
|
379
|
+
|
|
358
380
|
const language = options.product.lang || options.product.language;
|
|
359
381
|
options.product.lang = language;
|
|
360
382
|
options.product.language = language;
|
|
383
|
+
const eventName = options.product.eventName;
|
|
361
384
|
|
|
362
385
|
let itemKey = cart.addProduct({
|
|
363
386
|
id: options.id,
|
|
@@ -377,6 +400,8 @@ async function addProductToCart(options) {
|
|
|
377
400
|
});
|
|
378
401
|
|
|
379
402
|
const item = itemKey ? cart.getItemByKey(itemKey) : null;
|
|
403
|
+
// eventName would get nulled out if sapItem
|
|
404
|
+
item.product.eventName = eventName;
|
|
380
405
|
setCart(cart, item ? !item.isSapLineItem() : true);
|
|
381
406
|
return itemKey;
|
|
382
407
|
}
|
|
@@ -489,7 +514,10 @@ async function getAddToCartQty(product) {
|
|
|
489
514
|
retVal = product.maxQuantity - cartQty;
|
|
490
515
|
if (product.isExclusive) {
|
|
491
516
|
try {
|
|
492
|
-
const qual = await QualificationService.getQualification(product.sku)
|
|
517
|
+
const qual = await QualificationService.getQualification(product.sku);
|
|
518
|
+
if (!qual) {
|
|
519
|
+
return 0;
|
|
520
|
+
}
|
|
493
521
|
const productIdentifier = qual.productId || qual.sku;
|
|
494
522
|
cartQty = await getBaseSkuCartQuantity(productIdentifier)
|
|
495
523
|
retVal = product.maxQuantity - cartQty;
|
|
@@ -1407,8 +1435,10 @@ const cartServiceConfigCallback = async (configs) => {
|
|
|
1407
1435
|
if (_activeEvents != undefined) {
|
|
1408
1436
|
activeEvents = _activeEvents;
|
|
1409
1437
|
const cart = _getCart();
|
|
1410
|
-
cart.updateEventPrices(activeEvents)
|
|
1411
|
-
|
|
1438
|
+
if (cart.updateEventPrices(activeEvents)) {
|
|
1439
|
+
events.setValue(events.shop.CART_EVENT_PRICE_UPDATED, [activeEvents]);
|
|
1440
|
+
setCart(cart);
|
|
1441
|
+
}
|
|
1412
1442
|
}
|
|
1413
1443
|
}, true);
|
|
1414
1444
|
events.publish(events.salesevent.POLL_MARKET_CONFIG);
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import {productLib} from '@nuskin/product-lib';
|
|
2
|
+
import {RunConfigService, events, UrlService, BrowserDetection} from '@nuskin/ns-util';
|
|
3
|
+
import { getConfiguration } from '@nuskin/configuration-sdk';
|
|
4
|
+
import {AccountManager} from '@nuskin/ns-account';
|
|
5
|
+
import {PriceType, Product} from '@nuskin/ns-product-lib';
|
|
6
|
+
|
|
7
|
+
const extractProductData = (data, sku) => {
|
|
8
|
+
let retVal;
|
|
9
|
+
|
|
10
|
+
if (Array.isArray(data.variants) && data.variants.length > 0) {
|
|
11
|
+
retVal = data.variants.find((variant) => variant.sku === sku) || data.variants[0];
|
|
12
|
+
retVal.variantSelectLabel = data.variantSelectLabel;
|
|
13
|
+
} else if (data.bundle) {
|
|
14
|
+
retVal = data.bundle;
|
|
15
|
+
retVal.title = data.title;
|
|
16
|
+
retVal.productImages = data.productImages;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return retVal;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const addPrice = (productData, priceTypeKey, subKey, priceValue) => {
|
|
23
|
+
if (!['Points', 'cv', 'price', 'pv'].includes(priceTypeKey)) {
|
|
24
|
+
// if the priceTypeKey is not one of these, then we don't want it to show.
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (priceTypeKey === 'pv') {
|
|
28
|
+
priceTypeKey = 'psv';
|
|
29
|
+
}
|
|
30
|
+
if (priceTypeKey === 'cv') {
|
|
31
|
+
priceTypeKey = 'csv';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (productData[priceTypeKey] === undefined) {
|
|
35
|
+
if (priceTypeKey === 'Points') {
|
|
36
|
+
if (!productData.price) {
|
|
37
|
+
productData.price = {};
|
|
38
|
+
}
|
|
39
|
+
productData.price.PTS = priceValue;
|
|
40
|
+
return;
|
|
41
|
+
} else {
|
|
42
|
+
productData[priceTypeKey] = {};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
productData[priceTypeKey][subKey] = priceValue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const convertPricing = (pricing, productData) => {
|
|
49
|
+
if (pricing) {
|
|
50
|
+
Object.keys(pricing).forEach((channelKey) => {
|
|
51
|
+
Object.keys(pricing[channelKey]).forEach((contextKey) => {
|
|
52
|
+
Object.keys(pricing[channelKey][contextKey]).forEach((priceTypeKey) => {
|
|
53
|
+
const priceValue = pricing[channelKey][contextKey][priceTypeKey];
|
|
54
|
+
switch (channelKey) {
|
|
55
|
+
case 'wholesale':
|
|
56
|
+
switch (contextKey) {
|
|
57
|
+
case 'webOrder':
|
|
58
|
+
addPrice(productData, priceTypeKey, 'WWHL', priceValue);
|
|
59
|
+
break;
|
|
60
|
+
case 'webAdr':
|
|
61
|
+
case 'WADW':
|
|
62
|
+
case 'ADR5':
|
|
63
|
+
addPrice(productData, priceTypeKey, 'WADW', priceValue);
|
|
64
|
+
break;
|
|
65
|
+
case 'order':
|
|
66
|
+
case 'WHL':
|
|
67
|
+
addPrice(productData, priceTypeKey, 'WHL', priceValue);
|
|
68
|
+
break;
|
|
69
|
+
case 'adr':
|
|
70
|
+
addPrice(productData, priceTypeKey, 'ADW', priceValue);
|
|
71
|
+
break;
|
|
72
|
+
case 'ADR10':
|
|
73
|
+
case 'WADWD':
|
|
74
|
+
addPrice(productData, priceTypeKey, 'WADWD', priceValue);
|
|
75
|
+
break;
|
|
76
|
+
default:
|
|
77
|
+
addPrice(
|
|
78
|
+
productData,
|
|
79
|
+
priceTypeKey,
|
|
80
|
+
`${contextKey}-WWHL`,
|
|
81
|
+
priceValue
|
|
82
|
+
);
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
case 'retail':
|
|
87
|
+
switch (contextKey) {
|
|
88
|
+
case 'webOrder':
|
|
89
|
+
addPrice(productData, priceTypeKey, 'WRTL', priceValue);
|
|
90
|
+
break;
|
|
91
|
+
case 'webAdr':
|
|
92
|
+
addPrice(productData, priceTypeKey, 'WADR', priceValue);
|
|
93
|
+
break;
|
|
94
|
+
case 'order':
|
|
95
|
+
case 'RTL':
|
|
96
|
+
addPrice(productData, priceTypeKey, 'RTL', priceValue);
|
|
97
|
+
break;
|
|
98
|
+
case 'adr':
|
|
99
|
+
addPrice(productData, priceTypeKey, 'ADR', priceValue);
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
addPrice(
|
|
103
|
+
productData,
|
|
104
|
+
priceTypeKey,
|
|
105
|
+
`${contextKey}-WRTL`,
|
|
106
|
+
priceValue
|
|
107
|
+
);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const createDataFromSkuSearch = (searchData, options) => {
|
|
119
|
+
if (!searchData) {
|
|
120
|
+
return new Product();
|
|
121
|
+
}
|
|
122
|
+
let product = new Product();
|
|
123
|
+
|
|
124
|
+
if (searchData) {
|
|
125
|
+
product.sku = options.sku;
|
|
126
|
+
product.country = options.country;
|
|
127
|
+
product.lang = options.language;
|
|
128
|
+
product.isExclusive = searchData.isExclusive;
|
|
129
|
+
if (Array.isArray(searchData.productImages) && searchData.productImages.length > 0) {
|
|
130
|
+
product.setFullImage(searchData.productImages[0].url);
|
|
131
|
+
product.setThumbnail(searchData.productImages[0].thumbnail);
|
|
132
|
+
product.setImageAltText(searchData.productImages[0].altText);
|
|
133
|
+
// product.setProductCarouselImages(???searchData.contents.imageCarousel);
|
|
134
|
+
}
|
|
135
|
+
// product.productLabels = ???
|
|
136
|
+
product.title = searchData.title;
|
|
137
|
+
product.shortDescr = searchData.description;
|
|
138
|
+
// product.longDescr = langObj['longDescription']; looks like it is deprecated
|
|
139
|
+
product.dangerousGoods = searchData.dangerousGoods === true;
|
|
140
|
+
product.ingredients = searchData.ingredients;
|
|
141
|
+
product.benefits = searchData.benefits;
|
|
142
|
+
product.usage = searchData.usage;
|
|
143
|
+
product.resources = searchData.resources;
|
|
144
|
+
// product.videos = searchData.???;
|
|
145
|
+
// product.contentSection =searchData.???;
|
|
146
|
+
// product.sizeWeight = ???;
|
|
147
|
+
product.size = searchData.size;
|
|
148
|
+
product.nettoWeight = searchData.nettoWeight;
|
|
149
|
+
product.salesLabel = searchData.salesLabel;
|
|
150
|
+
// product.movie = searchData.???;
|
|
151
|
+
// product.youtube = searchData.???;
|
|
152
|
+
product.salesEventText = searchData.salesText;
|
|
153
|
+
product.scanQualified = searchData.scanQualifiedCount;
|
|
154
|
+
// product.division = searchData.???
|
|
155
|
+
product.custTypes = Array.isArray(searchData.customerTypes) && searchData.customerTypes.map((ct) => {
|
|
156
|
+
if (ct === 'Preferred') return '30';
|
|
157
|
+
else if (ct === 'Retail') return '20';
|
|
158
|
+
else if (ct === '') return '10';
|
|
159
|
+
});
|
|
160
|
+
product.restrictedMarkets = searchData.restrictedMarkets;
|
|
161
|
+
// if (addOns) {
|
|
162
|
+
// product.addOns = addOns;
|
|
163
|
+
// } else {
|
|
164
|
+
// product.addOns = [];
|
|
165
|
+
// }
|
|
166
|
+
if (options.isGroupOffer) product.isGroupOffer = options.isGroupOffer;
|
|
167
|
+
if (options.isPersonalOffer) product.isPersonalOffer = options.isPersonalOffer;
|
|
168
|
+
|
|
169
|
+
product.variantsLabel = searchData.variantLabel;
|
|
170
|
+
product.variantDropdownLabel = searchData.variantSelectLabel;
|
|
171
|
+
product.shade = searchData.variantColor;
|
|
172
|
+
|
|
173
|
+
const pricing = JSON.parse(searchData.pricingJson);
|
|
174
|
+
const orderTypes = [];
|
|
175
|
+
if (searchData.purchaseTypes.buyOnce) orderTypes.push('order');
|
|
176
|
+
if (searchData.purchaseTypes.subscription) orderTypes.push('adr');
|
|
177
|
+
let status = {
|
|
178
|
+
sku: options.sku,
|
|
179
|
+
globalProductId: searchData.globalId,
|
|
180
|
+
status: searchData.status.status === 'sellable' ? 'RELEASED_FOR_SALE' : 'NOT_RELEASED_FOR_SALE',
|
|
181
|
+
availableQuantity: searchData.availableQuantity,
|
|
182
|
+
maxQuantity: searchData.maxQuantity,
|
|
183
|
+
locallyProduced: searchData.locallyProduced, // ???
|
|
184
|
+
backorderedAvailableDate: searchData.status.isBackordered > 0 ? searchData.status.backorderedAvailableDate : null,
|
|
185
|
+
orderType: orderTypes, // searchData.channels.map((channel) => channel.toLowerCase()),
|
|
186
|
+
childSkus: null // ???
|
|
187
|
+
};
|
|
188
|
+
convertPricing(pricing, status);
|
|
189
|
+
product.addPricingFromStatus(status);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Note: this mapping was originally created for the product data in AEM. This product
|
|
193
|
+
// data comes from content stack and is not identical to what is in AEM. There may
|
|
194
|
+
// need to be some tweaks in here. ESPECIALLY when the data gets moved to the
|
|
195
|
+
// bundle field (vs variants) in the product data.
|
|
196
|
+
|
|
197
|
+
return product;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const handleDetailResponse = async (responseData, options) => {
|
|
201
|
+
let retVal = {success: true},
|
|
202
|
+
dataForProduct = createDataFromSkuSearch(responseData, options);
|
|
203
|
+
|
|
204
|
+
if (dataForProduct.sku) {
|
|
205
|
+
retVal.product = new Product(dataForProduct);
|
|
206
|
+
|
|
207
|
+
const siteUrl = UrlService.getSiteUrl();
|
|
208
|
+
const isEdge = BrowserDetection.isEdge();
|
|
209
|
+
const isFirefox = BrowserDetection.isFirefox();
|
|
210
|
+
|
|
211
|
+
// set the base url for images, etc
|
|
212
|
+
retVal.product.setBaseUrl(siteUrl);
|
|
213
|
+
|
|
214
|
+
// fix image paths for non-edge/firefox
|
|
215
|
+
if (!isEdge && !isFirefox) {
|
|
216
|
+
retVal.product.fullImage = retVal.product.fullImage
|
|
217
|
+
? `${retVal.product.fullImage.split("?")[0]}?format=pjpg`
|
|
218
|
+
: undefined;
|
|
219
|
+
retVal.product.thumbnail = retVal.product.thumbnail
|
|
220
|
+
? `${retVal.product.thumbnail.split("?")[0]}?format=pjpg`
|
|
221
|
+
: undefined;
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
retVal.success = false;
|
|
225
|
+
retVal.failedSku = options.sku;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (retVal.product && options.priceType) {
|
|
229
|
+
const {Cart: cartCfg} = await getConfiguration(['Cart']);
|
|
230
|
+
const priceType = cartCfg.showWholeSalePricing && !AccountManager.isLoggedIn()
|
|
231
|
+
? PriceType.WWHL
|
|
232
|
+
: options.priceType;
|
|
233
|
+
retVal.product.setPriceAndPvFromType(priceType);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return retVal;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const getProductDetail = async (options) => {
|
|
240
|
+
let response;
|
|
241
|
+
|
|
242
|
+
// Hit the PMD and get all the data for the product including the price information.
|
|
243
|
+
try {
|
|
244
|
+
response = await productLib.getProduct({
|
|
245
|
+
fromId: options.sku,
|
|
246
|
+
env: RunConfigService.getEnvironmentCode(),
|
|
247
|
+
market: options.country,
|
|
248
|
+
language: options.language
|
|
249
|
+
})
|
|
250
|
+
} catch (e) {
|
|
251
|
+
throw {error: e, failedSku: options.sku, type: events.errors.PRODUCT_LOOKUP};
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return extractProductData(response.data, options.sku);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const getProductBySku = async (options) => {
|
|
258
|
+
const data = await getProductDetail(options);
|
|
259
|
+
|
|
260
|
+
let result = await handleDetailResponse(data, options);
|
|
261
|
+
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const getProductData = async (options) => {
|
|
266
|
+
const data = await getProductDetail(options);
|
|
267
|
+
|
|
268
|
+
return createDataFromSkuSearch(data, options);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export {
|
|
272
|
+
getProductBySku,
|
|
273
|
+
getProductData
|
|
274
|
+
}
|
|
@@ -20,7 +20,8 @@ const shoppingContextCartTypes = {
|
|
|
20
20
|
|
|
21
21
|
const DEFAULT_CART_TYPE = 'USER';
|
|
22
22
|
|
|
23
|
-
let
|
|
23
|
+
let requestStatus = 'idle';
|
|
24
|
+
let cartPromise = null;
|
|
24
25
|
|
|
25
26
|
export default {
|
|
26
27
|
addProductToEquinoxCart,
|
|
@@ -46,8 +47,15 @@ function _getEquinoxSession() {
|
|
|
46
47
|
method: 'GET',
|
|
47
48
|
endpoint: 'customers'
|
|
48
49
|
}
|
|
50
|
+
const customerSession = sessionStorage.getItem('customerSession') ? JSON.parse(sessionStorage.getItem('customerSession')) : ''
|
|
51
|
+
if (customerSession === '') {
|
|
52
|
+
sessionStorage.setItem('customerSession', true)
|
|
53
|
+
return _equinoxRequest(equinoxRequestOptions)
|
|
54
|
+
} else {
|
|
55
|
+
return null
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
|
|
50
|
-
return _equinoxRequest(equinoxRequestOptions);
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
/**
|
|
@@ -216,22 +224,25 @@ function _getCartShoppingContext() {
|
|
|
216
224
|
async function getEquinoxCart() {
|
|
217
225
|
|
|
218
226
|
const cartType = _getCartShoppingContext();
|
|
219
|
-
|
|
227
|
+
|
|
220
228
|
const equinoxRequestOptions = {
|
|
221
229
|
method: 'GET',
|
|
222
230
|
endpoint: `carts/${cartType}`
|
|
223
231
|
}
|
|
224
|
-
if
|
|
225
|
-
|
|
226
|
-
cartContents = result;
|
|
227
|
-
});
|
|
232
|
+
if(requestStatus === 'pending'){
|
|
233
|
+
return await resolveCartPromise();
|
|
228
234
|
}
|
|
235
|
+
if (requestStatus === 'idle'){
|
|
236
|
+
requestStatus = 'pending';
|
|
237
|
+
cartPromise = _equinoxRequest(equinoxRequestOptions);
|
|
238
|
+
return await resolveCartPromise();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
229
241
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
return cartContents;
|
|
242
|
+
async function resolveCartPromise () {
|
|
243
|
+
const response = await cartPromise;
|
|
244
|
+
requestStatus = 'idle';
|
|
245
|
+
return response;
|
|
235
246
|
}
|
|
236
247
|
|
|
237
248
|
/**
|
|
@@ -262,7 +273,6 @@ async function getAddToCartQty(product) {
|
|
|
262
273
|
const qualification = await QualificationService.getQualification(product.sku)
|
|
263
274
|
qualifiedQuantity = qualification.isConsumable ? qualification.quantity : 0
|
|
264
275
|
} catch (err) {
|
|
265
|
-
console.error(err)
|
|
266
276
|
qualifiedQuantity = 0;
|
|
267
277
|
}
|
|
268
278
|
}
|
|
@@ -394,6 +404,7 @@ function _assembleChildSkus(requestData, options) {
|
|
|
394
404
|
if(personalOffer != null && productWithVariant.length > 0 && productWithVariant[0].variantSelected){
|
|
395
405
|
selectedVariants = productWithVariant[0].variantSelected;
|
|
396
406
|
}
|
|
407
|
+
if (personalOffer != null && selectedVariants && cs.skuId != selectedVariants[cs.productId] && (cs.type !== "BUNDLE" && cs.type !== "OPTIONAL")) return null
|
|
397
408
|
const childSku =
|
|
398
409
|
(personalOffer != null && selectedVariants && selectedVariants[cs.productId] && config.MySite_graphql_active)
|
|
399
410
|
? {
|
|
@@ -414,6 +425,7 @@ function _assembleChildSkus(requestData, options) {
|
|
|
414
425
|
|
|
415
426
|
return childSku;
|
|
416
427
|
});
|
|
428
|
+
requestData.skus = requestData.skus.filter(n => n)
|
|
417
429
|
}
|
|
418
430
|
|
|
419
431
|
return requestData;
|
|
@@ -459,7 +471,6 @@ const runConfigCallback = async (runConfig) => {
|
|
|
459
471
|
const publishEquinoxCartCount = (options) => {
|
|
460
472
|
getEquinoxCart().then((response) => {
|
|
461
473
|
const cart = response.data;
|
|
462
|
-
cartContents = null;
|
|
463
474
|
events.publish(events.shop.CART_UPDATED, { cartInfo: { qty: cart.value.count }, ...options });
|
|
464
475
|
});
|
|
465
476
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import $ from '@nuskin/nuskinjquery';
|
|
2
1
|
import {PriceType, Product} from '@nuskin/ns-product-lib';
|
|
3
|
-
import {RunConfigService,
|
|
2
|
+
import {RunConfigService, events, util, BrowserDetection, UrlService} from '@nuskin/ns-util';
|
|
4
3
|
import {UserService, AccountManager} from '@nuskin/ns-account';
|
|
5
4
|
import ProductStatusService from '../product/ProductStatusService.js';
|
|
6
5
|
import _ from 'lodash';
|
|
7
6
|
import { getConfiguration } from '@nuskin/configuration-sdk';
|
|
7
|
+
import { getProductBySku as getCsProductBySku, getProductData as getCsProductData } from './csProductHelper.js';
|
|
8
8
|
import axios from 'axios';
|
|
9
9
|
|
|
10
10
|
let ProductService = function() {
|
|
@@ -21,24 +21,13 @@ let ProductService = function() {
|
|
|
21
21
|
* @returns {null}
|
|
22
22
|
*/
|
|
23
23
|
getProductBySku: async function(_options) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
let values = await Promise.all(promises);
|
|
30
|
-
|
|
31
|
-
let result = await handleDetailResponse(values[0], options);
|
|
32
|
-
|
|
33
|
-
if (values[1] && values[1][0]) {
|
|
34
|
-
handleStatusResponse(result.product, values[1][0], options);
|
|
24
|
+
const options = verifyLocaleFields(_options)
|
|
25
|
+
const {Cart: cartCfg} = await getConfiguration(['Cart']);
|
|
26
|
+
if (cartCfg.useContentStackProductData) {
|
|
27
|
+
return await getCsProductBySku(options)
|
|
35
28
|
} else {
|
|
36
|
-
|
|
37
|
-
// This is done to prevent the product detail component from locking up unnecessarily.
|
|
38
|
-
result.product.availableQuantity = 10000;
|
|
29
|
+
return await legacyGetProductBySku(options);
|
|
39
30
|
}
|
|
40
|
-
|
|
41
|
-
return result;
|
|
42
31
|
},
|
|
43
32
|
|
|
44
33
|
/**
|
|
@@ -47,35 +36,34 @@ let ProductService = function() {
|
|
|
47
36
|
* @param {string} sku - ex. 01111155
|
|
48
37
|
* @returns {Promise}
|
|
49
38
|
*/
|
|
50
|
-
getProductData: function(sku, country, language) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if(
|
|
54
|
-
optionsData
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
reject(response);
|
|
39
|
+
getProductData: async function(sku, country, language) {
|
|
40
|
+
let retVal;
|
|
41
|
+
|
|
42
|
+
if (sku) {
|
|
43
|
+
const optionsData = {
|
|
44
|
+
country: country ? country : undefined,
|
|
45
|
+
language: language ? language : undefined,
|
|
46
|
+
sku
|
|
47
|
+
};
|
|
48
|
+
const options = verifyLocaleFields(optionsData);
|
|
49
|
+
const {Cart: cartCfg} = await getConfiguration(['Cart']);
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
|
|
53
|
+
if (cartCfg.useContentStackProductData) {
|
|
54
|
+
retVal = await getCsProductData(options);
|
|
55
|
+
} else {
|
|
56
|
+
const tokenizedSku = tokenizeSku(sku);
|
|
57
|
+
const url = UrlService.getSiteUrl() + "/content/products/" + tokenizedSku + "/" +
|
|
58
|
+
options.language + ".service." + options.country + ".json";
|
|
59
|
+
const response = await axios.get(url);
|
|
60
|
+
retVal = createDataFromSkuSearch(response, options);
|
|
73
61
|
}
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
62
|
+
} catch (err) {
|
|
63
|
+
console.error("There was a problem retrieving product data", err);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return retVal;
|
|
79
67
|
}
|
|
80
68
|
};
|
|
81
69
|
|
|
@@ -84,6 +72,26 @@ let ProductService = function() {
|
|
|
84
72
|
// Private Methods
|
|
85
73
|
//
|
|
86
74
|
// ---------------------------------------------
|
|
75
|
+
async function legacyGetProductBySku(options) {
|
|
76
|
+
const promises = [getProductDetail(options)];
|
|
77
|
+
|
|
78
|
+
promises.push(getProductStatus(options));
|
|
79
|
+
|
|
80
|
+
let values = await Promise.all(promises);
|
|
81
|
+
|
|
82
|
+
let result = await handleDetailResponse(values[0], options);
|
|
83
|
+
|
|
84
|
+
if (values[1] && values[1][0]) {
|
|
85
|
+
handleStatusResponse(result.product, values[1][0], options);
|
|
86
|
+
} else {
|
|
87
|
+
// Fallback for product quantity on a failed product status call.
|
|
88
|
+
// This is done to prevent the product detail component from locking up unnecessarily.
|
|
89
|
+
result.product.availableQuantity = 10000;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
async function getProductDetail(_options) {
|
|
88
96
|
let options = _options;
|
|
89
97
|
let url = await getSkuSearchUrl(options);
|