@nuskin/ns-shop 7.0.11-CodeFix.1 → 7.0.11-pur-813.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/ns-shop",
3
- "version": "7.0.11-CodeFix.1",
3
+ "version": "7.0.11-pur-813.2",
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.17.6",
29
+ "@nuskin/ns-product-lib": "2.19.1-pur-816.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",
@@ -0,0 +1,318 @@
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);
12
+ } else if (data.bundle) {
13
+ retVal = data.bundle;
14
+ retVal.title = data.title;
15
+ retVal.productImages = data.productImages;
16
+ }
17
+
18
+ return retVal;
19
+ }
20
+
21
+ const addPrice = (productData, priceTypeKey, subKey, priceValue) => {
22
+ if (!['Points', 'cv', 'price', 'pv'].includes(priceTypeKey)) {
23
+ // if the priceTypeKey is not one of these, then we don't want it to show.
24
+ return;
25
+ }
26
+ if (priceTypeKey === 'pv') {
27
+ priceTypeKey = 'psv';
28
+ }
29
+ if (priceTypeKey === 'cv') {
30
+ priceTypeKey = 'csv';
31
+ }
32
+
33
+ if (productData[priceTypeKey] === undefined) {
34
+ if (priceTypeKey === 'Points') {
35
+ if (!productData.price) {
36
+ productData.price = {};
37
+ }
38
+ productData.price.PTS = priceValue;
39
+ return;
40
+ } else {
41
+ productData[priceTypeKey] = {};
42
+ }
43
+ }
44
+ productData[priceTypeKey][subKey] = priceValue;
45
+ }
46
+
47
+ const convertPricing = (pricing, productData) => {
48
+ if (pricing) {
49
+ Object.keys(pricing).forEach((channelKey) => {
50
+ Object.keys(pricing[channelKey]).forEach((contextKey) => {
51
+ Object.keys(pricing[channelKey][contextKey]).forEach((priceTypeKey) => {
52
+ const priceValue = pricing[channelKey][contextKey][priceTypeKey];
53
+ switch (channelKey) {
54
+ case 'wholesale':
55
+ switch (contextKey) {
56
+ case 'webOrder':
57
+ addPrice(productData, priceTypeKey, 'WWHL', priceValue);
58
+ break;
59
+ case 'webAdr':
60
+ case 'WADW':
61
+ case 'ADR5':
62
+ addPrice(productData, priceTypeKey, 'WADW', priceValue);
63
+ break;
64
+ case 'order':
65
+ case 'WHL':
66
+ addPrice(productData, priceTypeKey, 'WHL', priceValue);
67
+ break;
68
+ case 'adr':
69
+ addPrice(productData, priceTypeKey, 'ADW', priceValue);
70
+ break;
71
+ case 'ADR10':
72
+ case 'WADWD':
73
+ addPrice(productData, priceTypeKey, 'WADWD', priceValue);
74
+ break;
75
+ default:
76
+ addPrice(
77
+ productData,
78
+ priceTypeKey,
79
+ `${contextKey}-WWHL`,
80
+ priceValue
81
+ );
82
+ break;
83
+ }
84
+ break;
85
+ case 'retail':
86
+ switch (contextKey) {
87
+ case 'webOrder':
88
+ addPrice(productData, priceTypeKey, 'WRTL', priceValue);
89
+ break;
90
+ case 'webAdr':
91
+ addPrice(productData, priceTypeKey, 'WADR', priceValue);
92
+ break;
93
+ case 'order':
94
+ case 'RTL':
95
+ addPrice(productData, priceTypeKey, 'RTL', priceValue);
96
+ break;
97
+ case 'adr':
98
+ addPrice(productData, priceTypeKey, 'ADR', priceValue);
99
+ break;
100
+ default:
101
+ addPrice(
102
+ productData,
103
+ priceTypeKey,
104
+ `${contextKey}-WRTL`,
105
+ priceValue
106
+ );
107
+ break;
108
+ }
109
+ break;
110
+ }
111
+ });
112
+ });
113
+ });
114
+ }
115
+ }
116
+
117
+ const createDataFromSkuSearch = (searchData, options) => {
118
+ if (!searchData) {
119
+ return new Product();
120
+ }
121
+ let product = new Product(),
122
+ langObj = null, //getLangObj(searchData['contents']['language'], options.language),
123
+ marketObj = null; //searchData['market'];
124
+ // if (Array.isArray(marketObj)) {
125
+ // marketObj = getMarketObj(searchData['market'], options.country);
126
+ // }
127
+ let {orderType: mktOrderTypes, custType: mktCustTypes, restrictedMarket: restrictedMarkets, addOns} = {}; //marketObj;
128
+
129
+ if (searchData) {
130
+ product.sku = options.sku;
131
+ product.lang = options.language;
132
+ product.isExclusive = searchData.isExclusive;
133
+ if (Array.isArray(searchData.productImages) && searchData.productImages.length > 0) {
134
+ product.setFullImage(searchData.productImages[0].url);
135
+ product.setThumbnail(searchData.productImages[0].thumbnail);
136
+ // product.setProductCarouselImages(???searchData.contents.imageCarousel);
137
+ }
138
+ // product.productLabels = ???
139
+ product.title = searchData.title;
140
+ product.shortDescr = searchData.description;
141
+
142
+ const pricing = JSON.parse(searchData.pricingJson);
143
+ const orderTypes = [];
144
+ if (searchData.purchaseTypes.buyOnce) orderTypes.push('order');
145
+ if (searchData.purchaseTypes.subscription) orderTypes.push('adr');
146
+ let status = {
147
+ sku: options.sku,
148
+ globalProductId: searchData.globalId,
149
+ status: searchData.status.status === 'sellable' ? 'RELEASED_FOR_SALE' : 'NOT_RELEASED_FOR_SALE',
150
+ availableQuantity: searchData.availableQuantity,
151
+ maxQuantity: searchData.maxQuantity,
152
+ locallyProduced: searchData.locallyProduced, // ???
153
+ backorderedAvailableDate: searchData.status.isBackordered > 0 ? searchData.status.backorderedAvailableDate : null,
154
+ orderType: orderTypes, // searchData.channels.map((channel) => channel.toLowerCase()),
155
+ childSkus: null // ???
156
+ };
157
+ convertPricing(pricing, status);
158
+ product.addPricingFromStatus(status);
159
+ }
160
+
161
+
162
+ if (marketObj !== null) {
163
+ // product.sku = searchData.sku;
164
+ // product.isExclusive = Object.hasOwn(searchData, 'isExclusive') ? searchData.isExclusive : false;
165
+ if (Object.hasOwn(searchData, 'contents')) {
166
+ // product.setFullImage(searchData.contents.fullImage);
167
+ // product.setThumbnail(searchData.contents.fullImage.replace(/\.img\.[0-9]+\.[0-9]+\.png/i, '.img.160.160.png'));
168
+ // if (Object.hasOwn(searchData.contents, 'imageCarousel')) {
169
+ // product.setProductCarouselImages(searchData.contents.imageCarousel);
170
+ // }
171
+ }
172
+ // AEM-8320 - it returns two BP (08007070 and 08129080), 08129080 does not have any translation yet.
173
+ // Note that langObj can be null (have a BP that does not have any translation)
174
+
175
+ // product.productLabels = marketObj['populateProductLabels'];
176
+ if (langObj) {
177
+ // product.lang = langObj['languageCode'];
178
+ // product.title = langObj['name'];
179
+ // product.shortDescr = langObj['shortDescription'];
180
+ product.longDescr = langObj['longDescription'];
181
+ product.ingredients = langObj['ingredients'];
182
+ product.benefits = langObj['benefits'];
183
+ product.usage = langObj['usage'];
184
+ product.resources = langObj['resources'];
185
+ product.videos = langObj['videos'];
186
+ product.contentSection = langObj['contentSection'];
187
+ product.sizeWeight = langObj['size_weight'];
188
+ product.nettoWeight = langObj['netto_weight'];
189
+ product.salesLabel = langObj['salesLabel'];
190
+ product.movie = langObj['movie'];
191
+ product.youtube = langObj['youtube'];
192
+ product.salesEventText = langObj['tdc_salesEventText'];
193
+ if (langObj.variantInfo) {
194
+ if (langObj.variantInfo.tdc_dropdownLabel) {
195
+ product.variantDropdownLabel = langObj.variantInfo.tdc_dropdownLabel
196
+ }
197
+ if (langObj.variantInfo.tdc_dropdownPlaceholder) {
198
+ product.variantDropdownPlaceholder = langObj.variantInfo.tdc_dropdownPlaceholder;
199
+ }
200
+ if (langObj.variantInfo.tdc_variantsLabel) {
201
+ product.variantsLabel = langObj.variantInfo.tdc_variantsLabel;
202
+ }
203
+ }
204
+ }
205
+ product.setImageAltText(searchData['contents']['altText']);
206
+ product.country = marketObj['countryCode'];
207
+ product.scanQualified = marketObj['scanQualified'];
208
+ product.division = searchData['division'];
209
+
210
+ if (mktOrderTypes) {
211
+ product.orderTypes = mktOrderTypes;
212
+ }
213
+ if (mktCustTypes) {
214
+ product.custTypes = mktCustTypes;
215
+ }
216
+ if (restrictedMarkets) {
217
+ product.restrictedMarkets = restrictedMarkets;
218
+ }
219
+ if (addOns) {
220
+ product.addOns = addOns;
221
+ } else {
222
+ product.addOns = [];
223
+ }
224
+
225
+ if (options.isGroupOffer)
226
+ product.isGroupOffer = options.isGroupOffer;
227
+ if (options.isPersonalOffer)
228
+ product.isPersonalOffer = options.isPersonalOffer;
229
+ }
230
+
231
+ if (searchData.variantConfig) {
232
+ if (searchData.variantConfig.variantType) {
233
+ product.variantType = searchData.variantConfig.variantType;
234
+ }
235
+ if (searchData.variantConfig.variants) {
236
+ searchData.variantConfig.variants.forEach((variant) => {
237
+ product.setVariant(createDataFromSkuSearch(variant, options));
238
+ });
239
+ }
240
+ if (searchData.variantConfig.swatchColor) {
241
+ product.shade = searchData.variantConfig.swatchColor;
242
+ }
243
+ if (searchData.variantConfig.baseSku) {
244
+ product.baseSku = searchData.variantConfig.baseSku;
245
+ }
246
+ }
247
+
248
+ return product;
249
+ }
250
+
251
+ const handleDetailResponse = async (responseData, options) => {
252
+ let retVal = {success: true},
253
+ dataForProduct = createDataFromSkuSearch(responseData, options);
254
+
255
+ if (dataForProduct.sku) {
256
+ retVal.product = new Product(dataForProduct);
257
+
258
+ const siteUrl = UrlService.getSiteUrl();
259
+ const isEdge = BrowserDetection.isEdge();
260
+ const isFirefox = BrowserDetection.isFirefox();
261
+
262
+ // set the base url for images, etc
263
+ retVal.product.setBaseUrl(siteUrl);
264
+
265
+ // fix image paths for non-edge/firefox
266
+ if (!isEdge && !isFirefox) {
267
+ retVal.product.fullImage = retVal.product.fullImage
268
+ ? `${retVal.product.fullImage.split("?")[0]}?format=pjpg`
269
+ : undefined;
270
+ retVal.product.thumbnail = retVal.product.thumbnail
271
+ ? `${retVal.product.thumbnail.split("?")[0]}?format=pjpg`
272
+ : undefined;
273
+ }
274
+ } else {
275
+ retVal.success = false;
276
+ retVal.failedSku = options.sku;
277
+ }
278
+
279
+ if (retVal.product && options.priceType) {
280
+ const {Cart: cartCfg} = await getConfiguration(['Cart']);
281
+ const priceType = cartCfg.showWholeSalePricing && !AccountManager.isLoggedIn()
282
+ ? PriceType.WWHL
283
+ : options.priceType;
284
+ retVal.product.setPriceAndPvFromType(priceType);
285
+ }
286
+
287
+ return retVal;
288
+ }
289
+
290
+ const getProductDetail = async (options) => {
291
+ let response;
292
+
293
+ // Hit the PMD and get all the data for the product including the price information.
294
+ try {
295
+ response = await productLib.getProduct({
296
+ fromId: options.sku,
297
+ env: RunConfigService.getEnvironmentCode(),
298
+ market: options.country,
299
+ language: options.language
300
+ })
301
+ } catch (e) {
302
+ throw {error: e, failedSku: options.sku, type: events.errors.PRODUCT_LOOKUP};
303
+ }
304
+
305
+ return extractProductData(response.data, options.sku);
306
+ }
307
+
308
+ const getProductBySku = async (options) => {
309
+ const data = await getProductDetail(options);
310
+
311
+ let result = await handleDetailResponse(data, options);
312
+
313
+ return result;
314
+ }
315
+
316
+ export {
317
+ getProductBySku
318
+ }
@@ -404,7 +404,7 @@ function _assembleChildSkus(requestData, options) {
404
404
  if(personalOffer != null && productWithVariant.length > 0 && productWithVariant[0].variantSelected){
405
405
  selectedVariants = productWithVariant[0].variantSelected;
406
406
  }
407
- if (personalOffer != null && selectedVariants && cs.skuId != selectedVariants[cs.productId] && (cs.type !== "BUNDLE" && cs.type !== "OPTIONAL" && cs.type !== "SKUKIT")) return null
407
+ if (personalOffer != null && selectedVariants && cs.skuId != selectedVariants[cs.productId] && (cs.type !== "BUNDLE" && cs.type !== "OPTIONAL")) return null
408
408
  const childSku =
409
409
  (personalOffer != null && selectedVariants && selectedVariants[cs.productId] && config.MySite_graphql_active)
410
410
  ? {
@@ -1,10 +1,11 @@
1
1
  import $ from '@nuskin/nuskinjquery';
2
2
  import {PriceType, Product} from '@nuskin/ns-product-lib';
3
- import {RunConfigService, util, events, BrowserDetection, UrlService} from '@nuskin/ns-util';
3
+ import {RunConfigService, events, util, BrowserDetection, UrlService} from '@nuskin/ns-util';
4
4
  import {UserService, AccountManager} from '@nuskin/ns-account';
5
5
  import ProductStatusService from '../product/ProductStatusService.js';
6
6
  import _ from 'lodash';
7
7
  import { getConfiguration } from '@nuskin/configuration-sdk';
8
+ import { getProductBySku as getCsProductBySku } from './csProductHelper.js';
8
9
  import axios from 'axios';
9
10
 
10
11
  let ProductService = function() {
@@ -21,24 +22,13 @@ let ProductService = function() {
21
22
  * @returns {null}
22
23
  */
23
24
  getProductBySku: async function(_options) {
24
- let options = verifyLocaleFields(_options),
25
- promises = [getProductDetail(options)];
26
-
27
- promises.push(getProductStatus(options));
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);
25
+ const options = verifyLocaleFields(_options)
26
+ const {Cart: cartCfg} = await getConfiguration(['Cart']);
27
+ if (cartCfg.useContentStackProductData) {
28
+ return await getCsProductBySku(options)
35
29
  } else {
36
- // Fallback for product quantity on a failed product status call.
37
- // This is done to prevent the product detail component from locking up unnecessarily.
38
- result.product.availableQuantity = 10000;
30
+ return await legacyGetProductBySku(options);
39
31
  }
40
-
41
- return result;
42
32
  },
43
33
 
44
34
  /**
@@ -84,6 +74,26 @@ let ProductService = function() {
84
74
  // Private Methods
85
75
  //
86
76
  // ---------------------------------------------
77
+ async function legacyGetProductBySku(options) {
78
+ const promises = [getProductDetail(options)];
79
+
80
+ promises.push(getProductStatus(options));
81
+
82
+ let values = await Promise.all(promises);
83
+
84
+ let result = await handleDetailResponse(values[0], options);
85
+
86
+ if (values[1] && values[1][0]) {
87
+ handleStatusResponse(result.product, values[1][0], options);
88
+ } else {
89
+ // Fallback for product quantity on a failed product status call.
90
+ // This is done to prevent the product detail component from locking up unnecessarily.
91
+ result.product.availableQuantity = 10000;
92
+ }
93
+
94
+ return result;
95
+ }
96
+
87
97
  async function getProductDetail(_options) {
88
98
  let options = _options;
89
99
  let url = await getSkuSearchUrl(options);
@@ -5,6 +5,7 @@ import {RunConfigService, events, util, PersonalOfferStorageService, BrowserDete
5
5
  import {getCachedConfigField} from '@nuskin/configuration-sdk';
6
6
  import {UserService} from "@nuskin/ns-account";
7
7
  import PaymentAdapter from '../payment/PaymentAdapter';
8
+ import pickupUtil from '../shipping/pickupUtil';
8
9
 
9
10
  let splitLineItems = [];
10
11
 
@@ -865,13 +866,14 @@ let setSelectedShipMethod = function(order, matchMethod = {}) {
865
866
 
866
867
  /**
867
868
  * Parses pickup points from SAP response, in case shipping method is set to pickup points!
868
- * @param {Object[]} custom The Custom array on the salesorderrequest
869
+ * @param {Object[]} oldPup The Custom array on the salesorderrequest
870
+ * @param {Object[]} newPup The Custom array on the salesorderrequest
869
871
  * @param {Object} order
870
872
  */
871
- function setPickupPoints(custom, order) {
872
- const pupLocations = custom || [];
873
+ function setPickupPoints(oldPup, newPup, order) {
874
+ const pupLocations = oldPup || [];
873
875
  if (order.selectedShippingMethod && PickupUtil.supports(order.selectedShippingMethod.Code)) {
874
- order.pickupPoints = PickupUtil.parse(pupLocations);
876
+ order.pickupPoints = newPup ? newPup : PickupUtil.parse(pupLocations);
875
877
  if (order.selectedPickupPoint) {
876
878
  order.selectedPickupPoint = order.pickupPoints.find(pickupPoint => order.selectedPickupPoint.id === pickupPoint.id);
877
879
  }
@@ -1090,13 +1092,19 @@ const toOrder = async (salesOrderDetail, adr, createResponse) => {
1090
1092
  }
1091
1093
 
1092
1094
  if (salesOrderDetail.ShippingAvailableMethods && salesOrderDetail.ShippingAvailableMethods.length > 0) {
1093
- order.shippingAvailableMethods = sortShippingAvailableMethods(salesOrderDetail.ShippingAvailableMethods);
1095
+ const useShipMethodsApi = getCachedConfigField('useShipMethodsApi');
1096
+ const shipMethods = useShipMethodsApi ? await pickupUtil.getShipMethods() : salesOrderDetail.ShippingAvailableMethods;
1097
+ order.shippingAvailableMethods = sortShippingAvailableMethods(shipMethods);
1094
1098
  setShippingAvailableMethodsPickupInfo(order.shippingAvailableMethods);
1095
1099
  setSelectedShipMethod(order, salesOrderDetail.Shipping.ShippingMethod);
1096
1100
  // When an order or ADR is created. The response from the create call is missing the list of pickup locations
1097
1101
  // The list isn't needed in this case since the user has already created the order so we don't need to update the pickup points
1098
1102
  if (!createResponse) {
1099
- setPickupPoints(salesOrderDetail.Custom, order);
1103
+ let oldPup = null;
1104
+ if (!useShipMethodsApi) oldPup = salesOrderDetail.Custom;
1105
+ let newPup = null;
1106
+ if (useShipMethodsApi) newPup = await pickupUtil.getPickupPoints();
1107
+ setPickupPoints(oldPup, newPup, order);
1100
1108
  }
1101
1109
  }
1102
1110
  shippingHack(order, salesOrderDetail.OrderTotals.Shipping, salesOrderDetail.Currency);
@@ -1,3 +1,11 @@
1
+ import OrderAdapter from '../order/orderAdapter';
2
+ import {getCachedConfiguration} from '@nuskin/configuration-sdk';
3
+ import {Order} from '@nuskin/order-model';
4
+ import {RunConfigService} from '@nuskin/ns-util';
5
+ // import {CartService} from '@nuskin/ns-shop';
6
+ import axios from 'axios';
7
+ import { OrderManager } from '../shop';
8
+
1
9
  let PickupUtil = function() {
2
10
  'use strict';
3
11
  const SERVICE_GROUP = 'SERVICE_GROUP',
@@ -15,6 +23,10 @@ let PickupUtil = function() {
15
23
  UNIT = 'UNIT',
16
24
  CARRIER_CODE = 'CARRIER_CODE';
17
25
 
26
+ let promise = Promise.resolve();
27
+ let shipMethods = [];
28
+ let pickupPoints = [];
29
+
18
30
  /**
19
31
  * Pickup Point shipping methods.
20
32
  * Values are shipping method codes.
@@ -130,12 +142,75 @@ let PickupUtil = function() {
130
142
  return markers;
131
143
  }
132
144
 
145
+ function getUrl() {
146
+ switch (RunConfigService.getEnvironmentCode()) {
147
+ case 'dev':
148
+ return 'https://ship-methods.api.dev.nuskin.com/v1';
149
+ case 'test':
150
+ return 'https://ship-methods.api.test.nuskin.com/v1';
151
+ case 'stage':
152
+ return 'https://ship-methods.api.dev.nuskin.com/v1';
153
+ case 'prod':
154
+ return 'https://ship-methods.api.dev.nuskin.com/v1';
155
+ default:
156
+ return 'https://ship-methods.api.dev.nuskin.com/v1';
157
+ }
158
+ }
159
+
160
+ function loadShipMethods() {
161
+ const order = Order.fromSalesOrderRequest(OrderAdapter.populateSalesOrder('SIMULATE'));
162
+
163
+ const postalCode = order.shippingPostalCode;
164
+ const {metapackMarket, metapackZipExclusions} = getCachedConfiguration('Checkout');
165
+
166
+ if (metapackMarket) {
167
+ const order = OrderManager.getOrder();
168
+ let includePickupPoints = true;
169
+ for (const zipRegEx of metapackZipExclusions || []) {
170
+ const regEx = new RegExp(zipRegEx);
171
+ includePickupPoints = includePickupPoints && !postalCode.match(regEx);
172
+ }
173
+
174
+ promise = axios.post(
175
+ getUrl(),
176
+ {
177
+ order,
178
+ pudo: includePickupPoints,
179
+ orderValue: order && order.orderTotals && order.orderTotals.grandTotal || 0.0
180
+ },
181
+ {
182
+ headers: {
183
+ 'Content-Type': 'application/json; charset=UTF-8'
184
+ }
185
+ }
186
+ ).then((results) => {
187
+ shipMethods = results.data.shipMethods;
188
+ pickupPoints = results.data.pickupPoints;
189
+ })
190
+ }
191
+ }
192
+
193
+ async function getShipMethods() {
194
+ await promise;
195
+
196
+ return shipMethods;
197
+ }
198
+
199
+ async function getPickupPoints() {
200
+ await promise;
201
+
202
+ return pickupPoints;
203
+ }
204
+
133
205
  return {
134
206
  allMethods: shippingMethods,
135
207
  supports: isPickupPointShippingMethod,
136
208
  parse: parsePickupPoints,
137
209
  bounds: getBounds,
138
- markers: generateMarkers
210
+ markers: generateMarkers,
211
+ loadShipMethods,
212
+ getShipMethods,
213
+ getPickupPoints
139
214
  }
140
215
  }();
141
216