From 89171267c8c04472315ff49f34e0dfa5bc1dd4ed Mon Sep 17 00:00:00 2001 From: Bellangelo Date: Thu, 28 May 2020 14:41:11 +0300 Subject: [PATCH 01/17] Store categories correctly (#2) * Add command option when indexing the categories * Use the command options values to fetch categories * Correct the level value for the category * Use slug for better SEO * Store parent id * Show in the main menu only the parent categories * Remove uneccessary check * Store the correct position * Store the correct level * The category name is necessary * The previous format didn't load the category page * Store category slug Co-authored-by: Aggelos --- cli.js | 4 +++- src/importer/categories.js | 4 ++-- src/templates/category.js | 39 ++++++++++++++++++++++++++------------ src/templates/product.js | 4 +++- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/cli.js b/cli.js index 99d0314..0adcea2 100644 --- a/cli.js +++ b/cli.js @@ -35,7 +35,9 @@ program.command('products') .action((cmd) => { productImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger: logger, page: cmd.page, perPage: cmd.perPage}).importProducts() }) program.command('categories') - .action(cmd => { categoryImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger }).importCategories() }) + .option('--perPage ', 'per page', parseInt) + .option('--page ', 'current page', parseInt) + .action(cmd => { categoryImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger, page: cmd.page, perPage: cmd.perPage }).importCategories() }) program .on('command:*', () => { diff --git a/src/importer/categories.js b/src/importer/categories.js index 9687b14..756c7ae 100644 --- a/src/importer/categories.js +++ b/src/importer/categories.js @@ -1,8 +1,8 @@ const categoryTemplate = require('../templates/category') const sendToElastic = require('../common/sendToElastic') -const importer = ({ config, elasticClient, apiConnector, logger }) => { - apiConnector(config).getAsync('products/categories?order_by=id').then( +const importer = ({ config, elasticClient, apiConnector, logger, page = 1, perPage = 20 }) => { + apiConnector(config).getAsync(`products/categories?order_by=id&page=${page}&per_page=${perPage}`).then( (result) => { let body = result.toJSON().body let array = JSON.parse(body) diff --git a/src/templates/category.js b/src/templates/category.js index e811c17..4ccfd03 100644 --- a/src/templates/category.js +++ b/src/templates/category.js @@ -16,34 +16,39 @@ const connector = () => { }) } -const extractSubcategories = async (parent_id) => { +const extractSubcategories = async (parent_id, level = 3) => { let result = await connector().getAsync(`products/categories?parent=${parent_id}`) let parsed = JSON.parse(result.toJSON().body) let subcats = [] + let position = 0 + if (parsed.length > 0) { for (let child of parsed) { - parsed.parent_id = parsed.parent_id ? parsed.parent_id : 1; + + position++ let childData = { "entity_type_id": 3, "attribute_set_id": 0, - "parent_id": parsed.parent_id, + "parent_id": parent_id, "created_at": "2018-10-12", "updated_at": "2018-10-12", - "position": 1, + "position": position, "level": 2, "children_count": 1, "available_sort_by": null, "include_in_menu": true, "name": entities.decode(child.name), + "slug": child.slug, "id": child.id, - "children_data": child.id !== parent_id && await extractSubcategories(child.id), + "children_data": child.id !== parent_id && await extractSubcategories(child.id, level + 1), "is_anchor": true, "is_active": true, - "path": `1/2/${child.id}`, + "slug": child.slug, + "path": child.slug, "url_key": child.slug, - "url_path": child.id, + "url_path": child.slug, "product_count": 10, } @@ -69,26 +74,36 @@ const fill = async ({ id, } ) => { + let include_in_menu = true + let level = 2 // A higher level will hide it from the main menu + // Check if category is a sub-category + if ( parent > 0 ) { + // Hide sub category from main menu + include_in_menu = false + level = 3 + } + let output = { "entity_type_id": 3, "attribute_set_id": 0, - "parent_id": 0, + "parent_id": parent, "created_at": "2018-10-12", "updated_at": "2018-10-12", "is_active": true, "position": 1, - "level": 2, + "level": level, "children_count": 1, "available_sort_by": null, - "include_in_menu": true, + "include_in_menu": include_in_menu, "name": entities.decode(name), "id": id, "is_anchor": true, - "path": `1/${id}`, + "slug": slug, + "path": slug, "url_key": slug, "url_path": slug, "product_count": 10, - "children_data": await extractSubcategories(parseInt(id)), + "children_data": await extractSubcategories(parseInt(id), level + 1), }; output.children_count = output.children_data.length; diff --git a/src/templates/product.js b/src/templates/product.js index b6f9287..feb9efa 100644 --- a/src/templates/product.js +++ b/src/templates/product.js @@ -7,7 +7,9 @@ const extractCategories = (categories) => { for (let category of categories) { output.push({ - category_id: category.id + category_id: category.id, + name: category.name, + slug: category.slug }) } From 40d477f562ecc247b31c693d5ab1e96b7fd5ddbc Mon Sep 17 00:00:00 2001 From: Bellangelo Date: Thu, 28 May 2020 14:42:49 +0300 Subject: [PATCH 02/17] Store attributes correctly (#1) * Add command option when indexing the categories * Use the command options values to fetch categories * Correct the level value for the category * Use slug for better SEO * Store parent id * Show in the main menu only the parent categories * Remove uneccessary check * Store the correct position * Store the correct level * The category name is necessary * Attribute name (real text) it's bad for field name * Attribute options is an array * apply_to is an array * Store attribute Co-authored-by: Aggelos --- src/templates/attribute.js | 2 +- src/templates/product.js | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/templates/attribute.js b/src/templates/attribute.js index 4ca1c41..b28dc1f 100644 --- a/src/templates/attribute.js +++ b/src/templates/attribute.js @@ -76,7 +76,7 @@ const fill = async (source) => { "used_in_product_listing": 0, "used_for_sort_by": 0, "is_configurable": true, - "apply_to": "simple,grouped,configurable", + "apply_to": ['simple', 'grouped', 'configurable'], "is_visible_in_advanced_search": false, "position": 0, "is_wysiwyg_enabled": false, diff --git a/src/templates/product.js b/src/templates/product.js index feb9efa..66eb19f 100644 --- a/src/templates/product.js +++ b/src/templates/product.js @@ -22,19 +22,22 @@ const appendAttributeOptionsArray = async (attributes, dataToAppend, apiConnecto for (let attribute of attributes) { let options = [] - if (attributeOptionsCache[`${attribute.name.toLowerCase()}_options`]) { + const attributeDetails = dataToAppend.configurable_options + .filter( attr => attr.label == attribute.name )[0] + + if (attributeOptionsCache[`${attributeDetails.attribute_code.toLowerCase()}_options`]) { logger.info(`options array found in cache (attribute id ${attribute.id}`) - options = attributeOptionsCache[`${attribute.name.toLowerCase()}_options`] + options = attributeOptionsCache[`${attributeDetails.attribute_code.toLowerCase()}_options`] } else { logger.info(`options array not cached (attribute id ${attribute.id}`) - dataToAppend[`${attribute.name.toLowerCase()}_options`] = [] + dataToAppend[`${attributeDetails.attribute_code.toLowerCase()}_options`] = [] let termsResponse = await apiConnector.getAsync(`products/attributes/${attribute.id}/terms`) let response = termsResponse.toJSON().body options = JSON.parse(response) } for (let term of options) { - dataToAppend[`${attribute.name.toLowerCase()}_options`].push(term.id) + dataToAppend[`${attributeDetails.attribute_code.toLowerCase()}_options`].push(term.id) } } @@ -46,6 +49,9 @@ const appendAttributeOptions = async (attributes, dataToAppend, apiConnector, lo logger.info(`appending options... ${dataToAppend.sku}`) for (let attribute of attributes) { let termsDetails = [] + const attributeDetails = dataToAppend.configurable_options + .filter( attr => attr.label == attribute.name )[0] + if (optionTermsCache[attribute.id]) { logger.info(`attribute options found in cache (attribute id ${attribute.id}`) termsDetails = optionTermsCache[attribute.id] @@ -57,12 +63,28 @@ const appendAttributeOptions = async (attributes, dataToAppend, apiConnector, lo optionTermsCache[attribute.id] = termsDetails } + dataToAppend[attributeDetails.attribute_code.toLowerCase()] = [] + let optionsArray = [ attribute.option ]; + // Woocommerce REST API documentation says that `options` does not exist. + // But this guard was left just in case. + if ('options' in attribute) { + optionsArray = attribute.options; + } + for (let term of termsDetails) { - if (attribute.option === term.name) { - logger.info(`appending options... ${attribute.name.toLowerCase()}: ${term.name}`) - dataToAppend[attribute.name.toLowerCase()] = term.id + + for (let option of optionsArray) { + + if (option === term.name) { + logger.info(`appending options... ${attribute.name.toLowerCase()}: ${term.name}`) + + dataToAppend[attributeDetails.attribute_code.toLowerCase()].push(term.id) + } + } + } + } return dataToAppend @@ -233,6 +255,7 @@ const fill = async (source, { apiConnector, elasticClient, config, logger }) => } await appendAttributeOptionsArray(attributes, output, apiConnector(config), logger) + await appendAttributeOptions(attributes, output, apiConnector(config), logger) return output; } From ad78cf0f51081ef41d96f58474d3da70eacd60d4 Mon Sep 17 00:00:00 2001 From: Bellangelo Date: Thu, 28 May 2020 17:48:27 +0300 Subject: [PATCH 03/17] Store all the categories the product is part of (#3) * Store all the categories the product is part of * Left there by mistake Co-authored-by: Aggelos --- src/importer/products.js | 1 - src/templates/product.js | 81 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/importer/products.js b/src/importer/products.js index 8a4e9af..731ec6b 100644 --- a/src/importer/products.js +++ b/src/importer/products.js @@ -39,7 +39,6 @@ const importer = ({ config, elasticClient, apiConnector, logger, page = 1, perPa let body = chunk.toJSON().body let products = JSON.parse(body) if (!Array.isArray(products) || products.length===0) { - console.log(products) logger.info(`There are no products on page ${page}`) return; } diff --git a/src/templates/product.js b/src/templates/product.js index 66eb19f..fb85513 100644 --- a/src/templates/product.js +++ b/src/templates/product.js @@ -2,6 +2,8 @@ const attributeCache = [] const attributeOptionsCache = [] const optionTermsCache = [] +const categoriesCache = {} + const extractCategories = (categories) => { let output = [] @@ -90,6 +92,82 @@ const appendAttributeOptions = async (attributes, dataToAppend, apiConnector, lo return dataToAppend } +/** + * Fetch category from Woocommerce REST API by id. + * + * @param string category_id + * @returns object + */ +const fetchCategoryData = async (category_id, connector) => { + const result = await connector.getAsync(`products/categories/${category_id}`) + const parsed = JSON.parse(result.toJSON().body) + + return 'id' in parsed ? parsed : {} + +} + +/** + * Fetches all parent categories + * + * @param object category + * @returns array + */ +const getParentCategories = async (category_id, connector) => { + // Fetch parent category data + let categories = [] + const category = category_id in categoriesCache + ? categoriesCache[ category_id ] + : await fetchCategoryData( category_id, connector ) + // If parent category exists + // If this isn't true the database data might be corrupted + if ( Object.keys(category).length > 0 ) { + categories.push(category) + categoriesCache[ category_id ] = category + } + // Get the parent categories + const parentCategories = 'parent' in category && category.parent > 0 + ? await getParentCategories( category.parent, connector ) : {} + + if ( parentCategories.length > 0 ) { + categories = categories.concat(parentCategories); + } + + return categories; + +} + +/** + * Fetches and returns all the categories. + * + * @param array categories + * @param apiConnector connector + */ +const getAllCategories = async (categories, connector) => { + + let storedCategories = [] + let uniqueCategories = [] + let uniqueCategoriesIds = {} // This is used to remove duplicates + + for (let category of categories) { + const getCategories = await getParentCategories( category.id, connector ) + + if ( getCategories.length > 0 ) { + storedCategories = storedCategories.concat(getCategories) + } + + } + // Remove duplicates + storedCategories.forEach( category => { + if ( !( category.id in uniqueCategoriesIds ) ) { + uniqueCategories.push(category) + uniqueCategoriesIds[ category.id ] = null + } + }); + + return uniqueCategories + +} + const extractConfigurableChildren = async (productId, variations, apiConnector, logger) => { let output = [] logger.info(`processing variations... (${variations.length})`) @@ -179,6 +257,9 @@ const fill = async (source, { apiConnector, elasticClient, config, logger }) => timestamp } = source + // Fetch the parent and sub categories that the product has + categories = await getAllCategories(categories, apiConnector(config)); + let output = { "timestamp": timestamp, "entity_type_id": 4, From f653613558bc65b268a01cc3395fb4a6200398fe Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 17:59:08 +0300 Subject: [PATCH 04/17] Copy attributes importer --- src/importer/tags.js | 49 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/importer/tags.js diff --git a/src/importer/tags.js b/src/importer/tags.js new file mode 100644 index 0000000..d9787b6 --- /dev/null +++ b/src/importer/tags.js @@ -0,0 +1,49 @@ +const config = require('../../config') +const WooCommerceAPI = require('woocommerce-api'); +const attributeTemplate = require('../templates/attribute') +const sendToElastic = require('../common/sendToElastic') +const Throttle = require('promise-parallel-throttle') + +const connector = () => { + let { host, protocol } = config.woo.api; + + return new WooCommerceAPI({ + url: `${protocol}://${host}`, + consumerKey: config.woo.api.auth.consumer_key, + consumerSecret: config.woo.api.auth.consumer_secret, + wpAPI: true, + version: 'wc/v1' + }) +} + +const importer = ({ config, elasticClient, apiConnector, logger }) => { + + connector().getAsync('products/attributes?per_page=100').then( + (result) => { + let body = result.toJSON().body + let attributes = JSON.parse(body) + const convertingQueue = attributes.map(attribute => () => attributeTemplate.fill(attribute)) + + Throttle.all(convertingQueue).then(convertedAttributes => { + const sendingQueue = convertedAttributes.map(attribute => () => sendToElastic(attribute, 'attribute', {config, elasticClient, logger})) + + Throttle.all(sendingQueue).then(result => { + logger.info(result) + logger.info(`${result.filter(success => success).length} attributes were successfully imported`) + }) + } + ) + }).catch(error => logger.info(error)) + + function importAttributes() { + logger.info('attributes are being imported...') + } + + return { + importAttributes + } +} + +module.exports = Object.freeze({ + importer +}) \ No newline at end of file From 16d7ab283e77e42a4d7134645f007a57a06b5b33 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:09:21 +0300 Subject: [PATCH 05/17] Convert tags to attribute options --- src/importer/tags.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/importer/tags.js b/src/importer/tags.js index d9787b6..30be02f 100644 --- a/src/importer/tags.js +++ b/src/importer/tags.js @@ -18,29 +18,27 @@ const connector = () => { const importer = ({ config, elasticClient, apiConnector, logger }) => { - connector().getAsync('products/attributes?per_page=100').then( + connector().getAsync('tags?per_page=100').then( (result) => { let body = result.toJSON().body - let attributes = JSON.parse(body) - const convertingQueue = attributes.map(attribute => () => attributeTemplate.fill(attribute)) - - Throttle.all(convertingQueue).then(convertedAttributes => { - const sendingQueue = convertedAttributes.map(attribute => () => sendToElastic(attribute, 'attribute', {config, elasticClient, logger})) - - Throttle.all(sendingQueue).then(result => { - logger.info(result) - logger.info(`${result.filter(success => success).length} attributes were successfully imported`) - }) - } - ) + let tags = JSON.parse(body) + + const tagsAsAttributeOptions = tags.map( tag => ({ + id: tag.id, + name: tag.name + })); + + const attribute = tagsTemplate.fill(tagsAsAttributeOptions) + await sendToElastic(attribute, 'attribute', {config, elasticClient, logger} + }).catch(error => logger.info(error)) - function importAttributes() { - logger.info('attributes are being imported...') + function importtags() { + logger.info('tags are being imported...') } return { - importAttributes + importtags } } From cc2d6f0861a46c9b67f4afe39b4eaea862408a84 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:12:07 +0300 Subject: [PATCH 06/17] Create tags template --- src/importer/tags.js | 3 +-- src/templates/tags.js | 57 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/templates/tags.js diff --git a/src/importer/tags.js b/src/importer/tags.js index 30be02f..2057797 100644 --- a/src/importer/tags.js +++ b/src/importer/tags.js @@ -1,8 +1,7 @@ const config = require('../../config') const WooCommerceAPI = require('woocommerce-api'); -const attributeTemplate = require('../templates/attribute') +const tagsTemplate = require('../templates/tag') const sendToElastic = require('../common/sendToElastic') -const Throttle = require('promise-parallel-throttle') const connector = () => { let { host, protocol } = config.woo.api; diff --git a/src/templates/tags.js b/src/templates/tags.js new file mode 100644 index 0000000..c20a2ed --- /dev/null +++ b/src/templates/tags.js @@ -0,0 +1,57 @@ + +const fill = async (source) => { + let { + id, + name, + slug, + type + } = source + + let output = { + "entity_type_id": 4, + "attribute_code": slug, + "attribute_model": null, + "backend_model": null, + "backend_type": "int", + "backend_table": null, + "frontend_model": null, + "frontend_input": type, + "frontend_label": name, + "frontend_class": null, + "source_model": "eav/entity_attribute_source_table", + "is_required": false, + "is_user_defined": true, + "default_value": "", + "is_unique": false, + "note": null, + "attribute_id": id, + "frontend_input_renderer": null, + "is_global": true, + "is_visible": true, + "is_searchable": true, + "is_filterable": 1, + "is_comparable": false, + "is_visible_on_front": true, + "is_html_allowed_on_front": true, + "is_used_for_price_rules": false, + "is_filterable_in_search": false, + "used_in_product_listing": 0, + "used_for_sort_by": 0, + "is_configurable": true, + "apply_to": ['simple', 'grouped', 'configurable'], + "is_visible_in_advanced_search": false, + "position": 0, + "is_wysiwyg_enabled": false, + "is_used_for_promo_rules": false, + "search_weight": 1, + "id": id, + "options": await extractOptions(id) + } + + return output + +} + +module.exports = { + fill +} \ No newline at end of file From 88714445932c81921f8b670ac76bd132a0b9faaa Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:17:05 +0300 Subject: [PATCH 07/17] Map the tags data as an attribute --- src/templates/tags.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/templates/tags.js b/src/templates/tags.js index c20a2ed..6b1fd5b 100644 --- a/src/templates/tags.js +++ b/src/templates/tags.js @@ -1,22 +1,18 @@ -const fill = async (source) => { - let { - id, - name, - slug, - type - } = source +const fill = async (options) => { + + const id = Date.now() let output = { "entity_type_id": 4, - "attribute_code": slug, + "attribute_code": 'tags', "attribute_model": null, "backend_model": null, "backend_type": "int", "backend_table": null, "frontend_model": null, - "frontend_input": type, - "frontend_label": name, + "frontend_input": 'select', + "frontend_label": 'tags', "frontend_class": null, "source_model": "eav/entity_attribute_source_table", "is_required": false, @@ -45,7 +41,7 @@ const fill = async (source) => { "is_used_for_promo_rules": false, "search_weight": 1, "id": id, - "options": await extractOptions(id) + "options": options } return output From a90623b050af580d4250ef536462ba876d8ea09e Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:29:55 +0300 Subject: [PATCH 08/17] Add the tags importer as a command in the cli --- cli.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli.js b/cli.js index 0adcea2..229f398 100644 --- a/cli.js +++ b/cli.js @@ -6,6 +6,7 @@ const logger = require('./src/common/logger') const productImporter = require('./src/importer/products') const categoryImporter = require('./src/importer/categories') const attributeImporter = require('./src/importer/attributes') +const tagsImporter = require('./src/importer/tags') const WooCommerceAPI = require('woocommerce-api'); const elasticsearch = require('elasticsearch') @@ -26,6 +27,9 @@ const connector = () => { }) } +program.command('tags').option('-p, --page', 'current page').option('-P, --pages', 'pages') + .action(cmd => { tagsImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger }).importAttributes() }) + program.command('attributes').option('-p, --page', 'current page').option('-P, --pages', 'pages') .action(cmd => { attributeImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger }).importAttributes() }) From 0f098794752edf8a512b4505f2d7b0b9c2b53ee8 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:31:06 +0300 Subject: [PATCH 09/17] How to import tags --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index da88c59..e402736 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,8 @@ In `db` section contained in `config.js` file you should adjust some info about Please execute indexers one by one with: 1. attributes: `nodejs cli.js attributes` 2. categories: `nodejs cli.js categories` -3. products: `nodejs cli.js products` +3. tags: `nodejs cli.js tags` +4. products: `nodejs cli.js products` and that's it. From 2a7e7ab26bdffa4cd5968f3a64a9ba20ce081596 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:37:59 +0300 Subject: [PATCH 10/17] Fix syntax error --- src/importer/tags.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/importer/tags.js b/src/importer/tags.js index 2057797..6d8b3b2 100644 --- a/src/importer/tags.js +++ b/src/importer/tags.js @@ -25,10 +25,10 @@ const importer = ({ config, elasticClient, apiConnector, logger }) => { const tagsAsAttributeOptions = tags.map( tag => ({ id: tag.id, name: tag.name - })); + })) const attribute = tagsTemplate.fill(tagsAsAttributeOptions) - await sendToElastic(attribute, 'attribute', {config, elasticClient, logger} + sendToElastic(attribute, 'attribute', {config, elasticClient, logger}) }).catch(error => logger.info(error)) From 9f70467034816f4ac8168f413591f3227db0f62d Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:38:50 +0300 Subject: [PATCH 11/17] Rename the template based on others --- src/templates/{tags.js => tag.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/templates/{tags.js => tag.js} (100%) diff --git a/src/templates/tags.js b/src/templates/tag.js similarity index 100% rename from src/templates/tags.js rename to src/templates/tag.js From 762cdd796ff84c97e430a3904d567e7c3cd0adb8 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:40:27 +0300 Subject: [PATCH 12/17] Call the correct function --- cli.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli.js b/cli.js index 229f398..82c8c3c 100644 --- a/cli.js +++ b/cli.js @@ -28,7 +28,7 @@ const connector = () => { } program.command('tags').option('-p, --page', 'current page').option('-P, --pages', 'pages') - .action(cmd => { tagsImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger }).importAttributes() }) + .action(cmd => { tagsImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger }).importTags() }) program.command('attributes').option('-p, --page', 'current page').option('-P, --pages', 'pages') .action(cmd => { attributeImporter.importer({ config: config, elasticClient: client, apiConnector: connector, logger }).importAttributes() }) From bd45a981957a5d127bb548ac47d0a4f47673e9a0 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:42:24 +0300 Subject: [PATCH 13/17] Convert function names to camelCase --- src/importer/tags.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/importer/tags.js b/src/importer/tags.js index 6d8b3b2..a36f4ae 100644 --- a/src/importer/tags.js +++ b/src/importer/tags.js @@ -32,12 +32,12 @@ const importer = ({ config, elasticClient, apiConnector, logger }) => { }).catch(error => logger.info(error)) - function importtags() { + function importTags() { logger.info('tags are being imported...') } return { - importtags + importTags } } From 73be98344123710e82370c19241da5238f27226a Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 18:45:39 +0300 Subject: [PATCH 14/17] Correct the REST API URI --- src/importer/tags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/importer/tags.js b/src/importer/tags.js index a36f4ae..be1ce46 100644 --- a/src/importer/tags.js +++ b/src/importer/tags.js @@ -17,7 +17,7 @@ const connector = () => { const importer = ({ config, elasticClient, apiConnector, logger }) => { - connector().getAsync('tags?per_page=100').then( + connector().getAsync('products/tags?per_page=100').then( (result) => { let body = result.toJSON().body let tags = JSON.parse(body) From 61656d39e9442720ebf0f44acb113811a79a2ae8 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 19:05:21 +0300 Subject: [PATCH 15/17] Function is not asynchronous --- src/templates/tag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/templates/tag.js b/src/templates/tag.js index 6b1fd5b..aa822ec 100644 --- a/src/templates/tag.js +++ b/src/templates/tag.js @@ -1,5 +1,5 @@ -const fill = async (options) => { +const fill = (options) => { const id = Date.now() From 56ffca93230f63c98f4a132e920e3b6e4f691823 Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 19:29:59 +0300 Subject: [PATCH 16/17] Correct the options map --- src/importer/tags.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/importer/tags.js b/src/importer/tags.js index be1ce46..8fe0ffb 100644 --- a/src/importer/tags.js +++ b/src/importer/tags.js @@ -23,8 +23,8 @@ const importer = ({ config, elasticClient, apiConnector, logger }) => { let tags = JSON.parse(body) const tagsAsAttributeOptions = tags.map( tag => ({ - id: tag.id, - name: tag.name + value: tag.id, + label: tag.name })) const attribute = tagsTemplate.fill(tagsAsAttributeOptions) From eb32f5063f5e5adc7a70382a001cfbd96fd7ef4f Mon Sep 17 00:00:00 2001 From: Aggelos Date: Thu, 28 May 2020 19:54:49 +0300 Subject: [PATCH 17/17] Append tags as attribute in product --- src/templates/product.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/templates/product.js b/src/templates/product.js index fb85513..a4dd8ca 100644 --- a/src/templates/product.js +++ b/src/templates/product.js @@ -230,6 +230,14 @@ const extractConfigurableOptions = async (attributes, apiConnector, logger) => { return output } +const appendTagsAsAttribute = (tags, output) => { + + const tagsIds = tags.map( tag => tag.id) + output.tags = tagsIds + output.tags_options = tagsIds + +} + const fill = async (source, { apiConnector, elasticClient, config, logger }) => { logger.info(`-------------------------------------------\nStarted processing parent product ${source.id} with sku ${source.sku}`) @@ -254,7 +262,8 @@ const fill = async (source, { apiConnector, elasticClient, config, logger }) => grouped_products, categories, variations, - timestamp + timestamp, + tags } = source // Fetch the parent and sub categories that the product has @@ -337,6 +346,7 @@ const fill = async (source, { apiConnector, elasticClient, config, logger }) => await appendAttributeOptionsArray(attributes, output, apiConnector(config), logger) await appendAttributeOptions(attributes, output, apiConnector(config), logger) + appendTagsAsAttribute(tags, output) return output; }