UNPKG

@vtex/vtex-search-mapper

Version:

Be a utility library to translate form VTEX Search results to VTEX Catalog json format

281 lines (272 loc) 13.4 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } function last(arr, defaultValue) { if (!arr || !Array.isArray(arr) || arr.length === 0) { return defaultValue; } return arr[arr.length - 1]; } function leftPad(n) { if (n < 0) { return ''; } if (n < 10) { return `0${n}`; } return n.toString(); } function getDateStringFromTimestamp(epochTimestamp) { if (!epochTimestamp) { return ''; } const date = new Date(epochTimestamp); const day = leftPad(date.getUTCDate()); const month = leftPad(date.getUTCMonth() + 1); const year = leftPad(date.getUTCFullYear()); const hours = leftPad(date.getUTCHours()); const minutes = leftPad(date.getUTCMinutes()); const seconds = leftPad(date.getUTCSeconds()); return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`; } function mergeProps(props1, props2, { keys, defaultValue }) { const finalProps = {}; keys.forEach((key) => { var _a, _b; finalProps[key] = (_b = (_a = props1[key]) !== null && _a !== void 0 ? _a : props2[key]) !== null && _b !== void 0 ? _b : defaultValue; }); return finalProps; } function uniqById(values) { const idsVisited = {}; if (!values || values.length === 0) { return []; } return values.filter((value) => { if (idsVisited[value.id]) { return false; } idsVisited[value.id] = true; return true; }); } function castToTwoDecimalFloat(num) { if (num.toString() === num.toFixed(2)) { return num; } return parseFloat((Math.floor(num * 100) / 100).toFixed(2)); } const PRICE_KEYS = ['price', 'oldPrice', 'stock']; function convertFromBiggyInstallmentsToCatalogApiInstallments(totalValue, installment) { if (!totalValue || !installment) { return []; } const catalogInstallments = []; for (let installmentNum = 1; installmentNum <= installment.count; installmentNum++) { catalogInstallments.push({ Value: castToTwoDecimalFloat(totalValue / installmentNum), InterestRate: 0, TotalValuePlusInterestRate: totalValue, NumberOfInstallments: installmentNum, PaymentSystemName: '', PaymentSystemGroupName: '', Name: '', }); } return catalogInstallments; } function convertFromBiggySellerAndSkuToCatalogApiSeller(seller, sku, { sc, domain = '' }) { var _a, _b, _c, _d, _e, _f; const pricesProps = { Price: (_a = seller.price) !== null && _a !== void 0 ? _a : null, ListPrice: (_b = seller.oldPrice) !== null && _b !== void 0 ? _b : null, PriceWithoutDiscount: (_c = seller.price) !== null && _c !== void 0 ? _c : null, }; const intPrice = Math.round(((_d = pricesProps.Price) !== null && _d !== void 0 ? _d : 0) * 100); return { sellerId: seller.id, sellerName: seller.name, addToCartLink: `${domain}/checkout/cart/add?sku=${sku.id}&qty=1&seller=${seller.id}&sc=${sc}&price=${intPrice}`, sellerDefault: false, commertialOffer: { CacheVersionUsedToCallCheckout: '', DeliverySlaSamplesPerRegion: {}, DiscountHighLight: [], GiftSkuIds: [], Teasers: [], BuyTogether: [], ItemMetadataAttachment: [], RewardValue: 0, PriceValidUntil: null, DeliverySlaSamples: [], GetInfoErrorMessage: null, Price: pricesProps.Price, ListPrice: pricesProps.ListPrice, PriceWithoutDiscount: pricesProps.PriceWithoutDiscount, AvailableQuantity: (_e = seller.stock) !== null && _e !== void 0 ? _e : 0, Tax: seller.tax, PaymentOptions: null, Installments: convertFromBiggyInstallmentsToCatalogApiInstallments((_f = pricesProps.Price) !== null && _f !== void 0 ? _f : 0, sku === null || sku === void 0 ? void 0 : sku.installment), }, }; } function convertFromBiggySkuToCatalogApiSellers(sku, extraInfo) { const { sellers, policies } = sku; const { sc } = extraInfo; let defaultSellerIndex = 0; let seller1WithStockIndex; const currentPolicy = policies.find((policy) => policy.id === sc); const currentPolicySellers = currentPolicy ? currentPolicy.sellers : []; const skuSellers = uniqById([...sellers, ...currentPolicySellers]); const newSellers = skuSellers.map((rawSeller, index) => { const seller = Object.assign(Object.assign({}, rawSeller), mergeProps(rawSeller, sku, { keys: PRICE_KEYS, defaultValue: 0, })); if (seller.stock) { defaultSellerIndex = index; if (seller.id === '1') { seller1WithStockIndex = index; } } return convertFromBiggySellerAndSkuToCatalogApiSeller(seller, sku, extraInfo); }); defaultSellerIndex = seller1WithStockIndex !== null && seller1WithStockIndex !== void 0 ? seller1WithStockIndex : defaultSellerIndex; if (newSellers[defaultSellerIndex]) { newSellers[defaultSellerIndex].sellerDefault = true; } return newSellers; } function convertFromBiggyProductImagesToCatalogApiImages(product) { return product.images.map((img) => { var _a, _b; return ({ imageId: '', imageLabel: (_a = img.name) !== null && _a !== void 0 ? _a : null, imageTag: '', imageUrl: img.value, imageText: (_b = img.name) !== null && _b !== void 0 ? _b : '', imageLastModified: '', }); }); } function convertFromBiggySkuAttributesToVariations(attributes) { const result = { variations: [] }; attributes.forEach((attribute) => { result.variations.push(attribute.key); result[attribute.key] = [attribute.value]; }); return result; } function convertFromBiggySkuAndProductToCatalogApiItem(rawSku, product, extraInfo) { var _a; const sku = Object.assign(Object.assign(Object.assign({}, rawSku), mergeProps(rawSku, product, { keys: PRICE_KEYS, defaultValue: 0, })), { installment: (_a = rawSku === null || rawSku === void 0 ? void 0 : rawSku.installment) !== null && _a !== void 0 ? _a : product.installment }); const _b = convertFromBiggySkuAttributesToVariations(sku.attributes), { variations } = _b, catalogSkuVariations = __rest(_b, ["variations"]); // fooling typescript so it doesn't throw error return Object.assign({ itemId: sku.id, name: '', nameComplete: '', complementName: '', ean: '', referenceId: [{ Key: 'RefId', Value: sku.reference }], measurementUnit: product.measurementUnit, unitMultiplier: product.unitMultiplier, modalType: null, isKit: false, Videos: [], estimatedDateArrival: null, images: convertFromBiggyProductImagesToCatalogApiImages(product), sellers: convertFromBiggySkuToCatalogApiSellers(sku, extraInfo), variations }, catalogSkuVariations); } function convertFromBiggyProductToCatalogApiItems(product, extraInfo) { const { skus } = product; // Catalog have items list ordered by sku ids, but biggy not necessarily skus.sort((a, b) => (a.id < b.id ? -1 : 1)); return skus.map((sku) => convertFromBiggySkuAndProductToCatalogApiItem(sku, product, extraInfo)); } function convertFromBiggySpecificationsToCatalogApiSpecifications(specificationGroups, textAttributes) { const parsedSpecifications = JSON.parse(specificationGroups); const allSpecificationsGroups = Object.keys(parsedSpecifications).reverse(); const result = Object.assign(Object.assign({}, parsedSpecifications), { allSpecificationsGroups }); const specificationKeyMap = {}; const specificationKeyValueMap = {}; allSpecificationsGroups.forEach((specificationsGroup) => { parsedSpecifications[specificationsGroup].forEach((specificationKey) => { specificationKeyMap[specificationKey] = true; specificationKeyValueMap[specificationKey] = {}; }); }); textAttributes.forEach((textAttribute) => { if (!textAttribute.labelKey || !specificationKeyMap[textAttribute.labelKey]) { return; } if (specificationKeyValueMap[textAttribute.labelKey][textAttribute.labelValue]) { return; } specificationKeyValueMap[textAttribute.labelKey][textAttribute.labelValue] = true; if (result[textAttribute.labelKey]) { result[textAttribute.labelKey].push(textAttribute.labelValue); } else { result[textAttribute.labelKey] = [textAttribute.labelValue]; } }); return result; } function convertFromBiggyCategoriesToCatalogCategories(biggyCategories) { const categoryList = []; const newCategories = []; biggyCategories.forEach((category) => { categoryList.push(category); newCategories.push(`/${categoryList.join('/')}/`); }); return newCategories.reverse(); } function convertFromBiggyTextAttributesToCatalogClustersAndCategories(textAttributes) { const productClusters = {}; const biggyCategories = []; textAttributes.forEach((textAttribute) => { var _a, _b; if (textAttribute.key === 'productclusternames' && (textAttribute.valueId || textAttribute.id)) { const valueId = (_b = (_a = textAttribute.valueId) !== null && _a !== void 0 ? _a : textAttribute.id) !== null && _b !== void 0 ? _b : ''; productClusters[valueId] = textAttribute.labelValue; } else if (textAttribute.key.startsWith('category-')) { biggyCategories.push(textAttribute.labelValue); } }); return { productClusters, categories: convertFromBiggyCategoriesToCatalogCategories(biggyCategories), }; } function convertFromBiggyProductToCatalogApiProduct(product, extraInfo) { var _a; const { domain = '' } = extraInfo; const _b = convertFromBiggySpecificationsToCatalogApiSpecifications(product.specificationGroups, product.textAttributes), { allSpecificationsGroups } = _b, catalogProductSpecifications = __rest(_b, ["allSpecificationsGroups"]); // fooling typescript so it doesn't throw error const { productClusters, categories, } = convertFromBiggyTextAttributesToCatalogClustersAndCategories(product.textAttributes); return Object.assign({ productId: product.id, productName: product.name, brand: product.brand, brandId: parseInt(product.brandId, 10), brandImageUrl: null, linkText: product.link, productReference: (_a = product.reference) !== null && _a !== void 0 ? _a : product.skus[0].reference, categoryId: last(product.categoryIds, ''), productTitle: product.name, description: product.description, metaTagDescription: product.description, releaseDate: getDateStringFromTimestamp(product.release), clusterHighlights: product.clusterHighlights, link: `${domain}${product.url}`, allSpecifications: product.productSpecifications, searchableClusters: {}, skuSpecifications: [], categoriesIds: convertFromBiggyCategoriesToCatalogCategories(product.categoryIds), items: convertFromBiggyProductToCatalogApiItems(product, extraInfo), productClusters, categories, allSpecificationsGroups }, catalogProductSpecifications); } function convertFromBiggyProductsToCatalogApiProducts(products, extraInfo) { if (!products || !Array.isArray(products) || products.length === 0) { return []; } return products.map((product) => convertFromBiggyProductToCatalogApiProduct(product, extraInfo)); } exports.convertFromBiggyProductToCatalogApiProduct = convertFromBiggyProductToCatalogApiProduct; exports.convertFromBiggyProductsToCatalogApiProducts = convertFromBiggyProductsToCatalogApiProducts;