diff --git a/config/services.yml b/config/services.yml
old mode 100644
new mode 100755
diff --git a/config_it.xml b/config_it.xml
index e313130d31546774123e2ba43390527117a00d3e..740dd887fb4207122549c322adb758eb6b31aaf8 100644
--- a/config_it.xml
+++ b/config_it.xml
@@ -2,10 +2,12 @@
 <module>
     <name>ps_connect_io6</name>
     <displayName><![CDATA[ImporterONE Cloud Connector]]></displayName>
-    <version><![CDATA[1.3.0]]></version>
+    <version><![CDATA[1.4.2]]></version>
     <description><![CDATA[Connette il tuo negozio con ImporterONE Cloud]]></description>
     <author><![CDATA[Imprimis]]></author>
     <tab><![CDATA[quick_bulk_update]]></tab>
+	<confirmUninstall><![CDATA[]]></confirmUninstall>
     <is_configurable>1</is_configurable>
-    <need_instance>1</need_instance>
-</module>
+    <need_instance>0</need_instance>
+	<limited_countries></limited_countries>
+</module>
\ No newline at end of file
diff --git a/controllers/AdminPsConnectIo6ActionsController.php b/controllers/AdminPsConnectIo6ActionsController.php
old mode 100644
new mode 100755
index bacf66ffa714e05a01ba639d7858acf4faa4267d..42fbfb60b152091a6f82c02f45e5e6d27d2d08ab
--- a/controllers/AdminPsConnectIo6ActionsController.php
+++ b/controllers/AdminPsConnectIo6ActionsController.php
@@ -50,7 +50,7 @@ class AdminPsConnectIo6ActionsController extends FrameworkBundleAdminController
         if ($module->active && !empty($io6_id_product)) {
             $res = $module->io6Sync($io6_id_product);
         }
-        
+
         if (version_compare(_PS_VERSION_, '8.1', '>=') && $new_product_page && !empty($res)) {
             echo json_encode($res);
             die();
diff --git a/controllers/front/actions.php b/controllers/front/actions.php
index de1b89a23d96a8a156d0a268dce16bd323efae67..3463dde571ceb6d7b7fb876e50765570e994d98c 100755
--- a/controllers/front/actions.php
+++ b/controllers/front/actions.php
@@ -83,6 +83,153 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
         }
     }
 
+    public function displayAjaxExcludeProducts()
+    {
+        $this->processExcludeProducts();
+    }
+
+    public function processExcludeProducts(){
+        try {
+            $sql = 'INSERT IGNORE INTO '. _DB_PREFIX_ .'importerone6connect_products
+            SELECT 
+            p.id_product,
+            0,
+            NULL,
+            0,
+            \'\',
+            1,
+            NULL,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            \'\',
+            0,
+            NULL
+            FROM '. _DB_PREFIX_ .'product p
+            LEFT JOIN '. _DB_PREFIX_ .'importerone6connect_products ip ON ip.id_product = p.id_product
+            WHERE ip.id_product IS NULL';
+            $res = Db::getInstance()->execute($sql);
+
+            if ($res){
+                echo json_encode(["success" => true, "message" => "Prodotti esclusi correttamente"]);
+            } else {
+                echo json_encode(["success" => false, "message" => "Errore durante lo spostamento dei prodotti"]);
+            }
+        } catch (Exception $e) {
+            echo json_encode(["success" => false, "message" => $e->getMessage()]);
+        }
+    }
+
+    public function displayAjaxIncludeProducts()
+    {
+        $this->processIncludeProducts();
+    }
+
+    public function processIncludeProducts(){
+        try {
+            $sql = 'INSERT IGNORE INTO '. _DB_PREFIX_ .'importerone6connect_products
+            SELECT 
+            p.id_product,
+            0,
+            NULL,
+            0,
+            \'\',
+            0,
+            NULL,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            2,
+            \'\',
+            0,
+            NULL
+            FROM '. _DB_PREFIX_ .'product p
+            LEFT JOIN '. _DB_PREFIX_ .'importerone6connect_products ip ON ip.id_product = p.id_product
+            WHERE ip.id_product IS NULL';
+            $res = Db::getInstance()->execute($sql);
+
+            if ($res){
+                echo json_encode(["success" => true, "message" => "Prodotti inclusi correttamente"]);
+            } else {
+                echo json_encode(["success" => false, "message" => "Errore durante lo spostamento dei prodotti"]);
+            }
+        } catch (Exception $e) {
+            echo json_encode(["success" => false, "message" => $e->getMessage()]);
+        }
+    }
+
+    public function displayAjaxDownloadNotIO6Catalog()
+    {
+        $this->processDownloadNotIO6Catalog();
+    }
+
+    public function processDownloadNotIO6Catalog(){
+        try {
+            $sql = "SELECT DISTINCT p.id_product, p.ean13, p.reference, p.mpn, pl.name FROM ". _DB_PREFIX_ ."product p
+            INNER JOIN ". _DB_PREFIX_ ."product_lang pl ON pl.id_product = p.id_product
+            LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_products ip ON ip.id_product = p.id_product
+            WHERE ip.id_product IS NULL";
+            $productNotInIo6Tables = Db::getInstance()->executeS($sql);
+
+            if(!empty($productNotInIo6Tables)){
+                $this->prepareCSV($productNotInIo6Tables, 'product_not_in_io6_tables');
+            }
+        
+        } catch (Exception $e) {
+            echo json_encode(["success" => false, "message" => $e->getMessage()]);
+        }
+    }
+
+    public function displayAjaxExportCategoriesTree()
+    {
+        $this->processExportCategoriesTree();
+    }
+
+    public function processExportCategoriesTree(){
+        try {
+            $sql = "SELECT DISTINCT c.id_category, c.id_parent, TRIM(cl.name) as name FROM ". _DB_PREFIX_ ."category c
+            INNER JOIN ". _DB_PREFIX_ ."category_lang cl ON cl.id_category = c.id_category
+            WHERE c.active = 1 AND c.level_depth != 0 AND c.is_root_category = 0
+            ORDER BY c.id_parent ASC, c.id_category ASC";
+            $categories_tree = Db::getInstance()->executeS($sql);
+
+            foreach (Shop::getShops() as $shop) {
+                $root_category = Db::getInstance()->getValue("SELECT id_category FROM ". _DB_PREFIX_ ."category c
+                WHERE c.is_root_category = 1 AND c.id_shop_default = ". $shop['id_shop']);
+
+                foreach ($categories_tree as $key => $category) {
+                    if ($category['id_parent'] == $root_category){
+                        $categories_tree[$key]['id_parent'] = 0;
+                    }
+                }
+            }
+
+            if(!empty($categories_tree)){
+                $this->prepareCSV($categories_tree, 'prestashop_categories_tree');
+            }
+        
+        } catch (Exception $e) {
+            echo json_encode(["success" => false, "message" => $e->getMessage()]);
+        }
+    }
+
     public function displayAjaxExpandStatisticInfo()
     {
         $this->processExpandStatisticInfo();
@@ -112,7 +259,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_immagini_da_scaricare');
+                        $this->prepareCSV($result, 'io6_immagini_da_scaricare');
                     }
                 } else {
                     echo json_encode($rows);
@@ -131,7 +278,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_prestashop');
+                        $this->prepareCSV($result, 'io6_prodotti_prestashop');
                     }
                 } else {
                     echo json_encode($rows);
@@ -151,7 +298,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_ImporterONE');
+                        $this->prepareCSV($result, 'io6_prodotti_ImporterONE');
                     }
                 } else {
                     echo json_encode($rows);
@@ -173,7 +320,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_con_immagini');
+                        $this->prepareCSV($result, 'io6_prodotti_con_immagini');
                     }
                 } else {
                     echo json_encode($rows);
@@ -195,7 +342,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_senza_immagini');
+                        $this->prepareCSV($result, 'io6_prodotti_senza_immagini');
                     }
                 } else {
                     echo json_encode($rows);
@@ -215,7 +362,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_senza_margine');
+                        $this->prepareCSV($result, 'io6_prodotti_senza_margine');
                     }
                 } else {
                     echo json_encode($rows);
@@ -227,7 +374,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                         SELECT p2.reference
                         FROM "._DB_PREFIX_."product p
                         INNER JOIN "._DB_PREFIX_."product p2 ON p2.id_product = p.id_product
-                        WHERE p2.reference = p.reference
+                        WHERE p2.reference = p.reference AND p2.reference != '' AND p.reference != ''
                         GROUP BY p2.reference
                         HAVING COUNT(p2.reference) > 1) pf
                         INNER JOIN "._DB_PREFIX_."product p ON p.reference = pf.reference";
@@ -239,7 +386,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_con_stesso_reference');
+                        $this->prepareCSV($result, 'io6_prodotti_con_stesso_reference');
                     }
                 } else {
                     echo json_encode($rows);
@@ -251,7 +398,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                         SELECT p2.mpn
                         FROM "._DB_PREFIX_."product p
                         INNER JOIN "._DB_PREFIX_."product p2 ON p2.id_product = p.id_product
-                        WHERE p2.mpn = p.mpn
+                        WHERE p2.mpn = p.mpn AND p2.mpn != '' AND p.mpn != ''
                         GROUP BY p2.mpn
                         HAVING COUNT(p2.mpn) > 1) pf
                         INNER JOIN "._DB_PREFIX_."product p ON p.mpn = pf.mpn";
@@ -263,7 +410,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_con_stesso_mpn');
+                        $this->prepareCSV($result, 'io6_prodotti_con_stesso_mpn');
                     }
                 } else {
                     echo json_encode($rows);
@@ -275,7 +422,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                         SELECT p2.ean13
                         FROM "._DB_PREFIX_."product p
                         INNER JOIN "._DB_PREFIX_."product p2 ON p2.id_product = p.id_product
-                        WHERE p2.ean13 = p.ean13
+                        WHERE p2.ean13 = p.ean13 AND p2.ean13 != '' AND p.ean13 != ''
                         GROUP BY p2.ean13
                         HAVING COUNT(p2.ean13) > 1) pf
                         INNER JOIN "._DB_PREFIX_."product p ON p.ean13 = pf.ean13";
@@ -287,7 +434,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
                 
                 if($download){
                     if(!empty($result)){
-                        $this->prepareStatisticCSV($result, 'io6_prodotti_con_stesso_ean');
+                        $this->prepareCSV($result, 'io6_prodotti_con_stesso_ean');
                     }
                 } else {
                     echo json_encode($rows);
@@ -297,7 +444,7 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
         
     }
 
-    private function prepareStatisticCSV($result, $filename){
+    private function prepareCSV($result, $filename){
         header('Content-Description: File Transfer');
         header('Content-Type: application/csv');
         header('Content-Disposition: attachment; filename="'.$filename.'.csv"');
@@ -402,4 +549,62 @@ class Ps_Connect_Io6ActionsModuleFrontController extends ModuleFrontController
         return $this->context->smarty->fetch(_PS_MODULE_DIR_ . $this->module->name .'/views/templates/admin/statistic_info.tpl');
     }
 
+    public function displayAjaxDisableProducts()
+    {
+        $this->processDisableProducts();
+    }
+
+    public function processDisableProducts(){
+        try {
+            if (!empty('catalogId')){
+                $result = true;
+                $catalogId = Tools::getValue('catalogId');
+    
+                $sql = 'UPDATE `' . _DB_PREFIX_ . 'product` product
+                                INNER JOIN `' . _DB_PREFIX_ . 'importerone6connect_products` ioprod ON product.id_product = ioprod.id_product
+                                SET product.`active` = 0 
+                                WHERE product.`active` = 1 and ioprod.`sync_exclude` = 0 AND ioprod.io6_id_product > 0 AND ioprod.catalog_id = '.(int)$catalogId.';';
+                $result &= Db::getInstance()->execute($sql);
+    
+                $sql = 'UPDATE `' . _DB_PREFIX_ . 'product_shop` p_shop
+                                            INNER JOIN `' . _DB_PREFIX_ . 'product` p ON p_shop.id_product = p.id_product
+                                            SET p_shop.active = p.active 
+                                            WHERE p_shop.`active` = 1;';
+    
+                $result &= Db::getInstance()->execute($sql);
+
+                echo json_encode(['success' => $result]);
+            } else {
+                echo json_encode(['success' => false]);
+            }
+        } catch (Exception $e) {
+            echo json_encode(['success' => false]);
+        }
+    }
+
+    public function displayAjaxMoveProducts()
+    {
+        $this->processMoveProducts();
+    }
+
+    public function processMoveProducts(){
+        try {
+            if (!empty('catalogId')){
+                $result = true;
+                $oldCatalogId = Tools::getValue('oldCatalogId');
+                $newCatalogId = Tools::getValue('newCatalogId');
+    
+                $sql = "UPDATE ". _DB_PREFIX_ ."importerone6connect_products ip SET ip.catalog_id = " . (int)$newCatalogId ." 
+                WHERE ip.catalog_id = ". (int)$oldCatalogId;
+    
+                $result &= Db::getInstance()->execute($sql);
+
+                echo json_encode(['success' => $result]);
+            } else {
+                echo json_encode(['success' => false]);
+            }
+        } catch (Exception $e) {
+            echo json_encode(['success' => false]);
+        }
+    }
 }
diff --git a/core/src/classes/IO6Catalog.class.php b/core/src/classes/IO6Catalog.class.php
index a907aba342d02155dd3a6954fcb50073ffa620f6..d6a05d577660d82caf5a182b2d05baca5f06c068 100644
--- a/core/src/classes/IO6Catalog.class.php
+++ b/core/src/classes/IO6Catalog.class.php
@@ -10,9 +10,13 @@
 class IO6Catalog {
 	public $id;
 	public $name;
+	public $selected;
+	public $priceLists;
   
 	function __construct($jCatalog) {
 		$this->id = $jCatalog['id'];
 		$this->name = $jCatalog['name'];
+		$this->selected = false;
+		$this->priceLists = [];
 	}
 }
diff --git a/core/src/classes/IO6Category.class.php b/core/src/classes/IO6Category.class.php
index 29ca0e91ff44580a1b9216f45f919708e81cfa05..0bc8d35aaab3abb8bfa47e0564168c9ac61e2b98 100644
--- a/core/src/classes/IO6Category.class.php
+++ b/core/src/classes/IO6Category.class.php
@@ -15,7 +15,7 @@ class IO6Category {
 		$this->parentId = $jCategory['parentId'];
 
 		//TODO: EM20210318 => vedere se fare una get con le IO6API oppure aggiungerlo al json
-		$this->parentCode = !empty($jCategory['parentId']) ? str_pad($jCategory['parentId'], 10, '0', STR_PAD_LEFT) : '';
+		$this->parentCode = !empty($jCategory['parentCode']) ? $jCategory['parentCode'] : '';
 		$this->name = $jCategory['name'];
 		$this->subCategories = $subCategories;
 	}
diff --git a/core/src/classes/IO6ConnectConfiguration.class.php b/core/src/classes/IO6ConnectConfiguration.class.php
index a5fa4667cf9e80dfe0fddc04b9b3a91c0be6e4d3..0add30cb5ce31ffa22bbdfad1987a3187848f1d0 100644
--- a/core/src/classes/IO6ConnectConfiguration.class.php
+++ b/core/src/classes/IO6ConnectConfiguration.class.php
@@ -4,8 +4,8 @@ class IO6ConnectConfiguration
 	public $apiToken;
 	public $apiEndPoint;
 	public $catalogId;
+	public $catalogsData;
 
-	public $priceListId;
 	public $pageSize;
 
 	public $selectedBrandField;
@@ -26,6 +26,7 @@ class IO6ConnectConfiguration
 	public $manageStock;
 	public $manageFeaturesHTML;
 	public $manageTaxRule;
+	public $manageIo6Suppliers;
 	public $concatFeaturesHTML;
 	public $excludeNoImage;
 	public $delayedDownloadsImages;
@@ -44,7 +45,8 @@ class IO6ConnectConfiguration
 		if (isset($configuration) && is_array($configuration) ) {
 			$this->apiToken = array_key_exists('apitoken', $configuration) ? $configuration['apitoken'] : '';
 			$this->apiEndPoint = array_key_exists('apiendpoint', $configuration) ? $configuration['apiendpoint'] : '';
-			$this->catalogId = array_key_exists('catalog', $configuration) ? (int)$configuration['catalog'] : '';
+			$this->catalogId = array_key_exists('catalog', $configuration) ? explode(',', $configuration['catalog']) : '';
+			$this->catalogsData = array_key_exists('catalogs', $configuration) ? unserialize($configuration['catalogs']) : '';
 			$this->languageCode = array_key_exists('languagecode', $configuration) ? $configuration['languagecode'] : '';
 			$this->tempFolder = array_key_exists('tempfolder', $configuration) ? $configuration['tempfolder'] : '';
 			
@@ -52,8 +54,6 @@ class IO6ConnectConfiguration
 			$this->selectedSkuField = array_key_exists('select_sku_field', $configuration) ? $configuration['select_sku_field'] : 'io6_sku_partNumber';
 			$this->selectedEanField = array_key_exists('select_ean_field', $configuration) ? $configuration['select_ean_field'] : 'io6_eancode';
 			$this->selectedPartNumberField = array_key_exists('select_partnumber_field', $configuration) ? $configuration['select_partnumber_field'] : 'io6_partnumber';
-
-			$this->priceListId = array_key_exists('price_list', $configuration) ? (int)$configuration['price_list'] : 0;
 			$this->pageSize = array_key_exists('page_size', $configuration) ? (int)$configuration['page_size'] : 25;
 	
 			$this->manageImages = array_key_exists('manage_images', $configuration) ? $configuration['manage_images'] == 1 : false;
@@ -69,6 +69,7 @@ class IO6ConnectConfiguration
 			$this->manageCategories = array_key_exists('manage_categories', $configuration) ? $configuration['manage_categories'] == 1 : false;
 			$this->manageFeaturesHTML = array_key_exists('manage_features_html', $configuration) ? $configuration['manage_features_html'] == 1 : false;
 			$this->manageTaxRule = array_key_exists('manage_tax_rule', $configuration) ? $configuration['manage_tax_rule'] == 1 : false;
+			$this->manageIo6Suppliers = array_key_exists('manage_io6_suppliers', $configuration) ? $configuration['manage_io6_suppliers'] == 1 : false;
 			$this->concatFeaturesHTML = array_key_exists('concat_features_html', $configuration) ? $configuration['concat_features_html'] == 1 : false;
 			$this->featuresHTMLTemplate = array_key_exists('features_html_template', $configuration) ? $configuration['features_html_template'] : 0;
 			$this->excludeNoImage = array_key_exists('exclude_noimage', $configuration) ? $configuration['exclude_noimage'] == 1 : false;
@@ -84,8 +85,6 @@ class IO6ConnectConfiguration
 			$this->selectedSkuField = 'io6_sku_partNumber';
 			$this->selectedEanField = 'io6_eancode';
 			$this->selectedPartNumberField = 'io6_partnumber';
-
-			$this->priceListId = 0;
 			$this->pageSize = 25;
 	
 			$this->manageImages = true;
@@ -101,6 +100,7 @@ class IO6ConnectConfiguration
 			$this->manageDimensions = true;
 			$this->manageWeight = true;
 			$this->manageTaxRule = true;
+			$this->manageIo6Suppliers = true;
 			$this->concatFeaturesHTML = true;
 			$this->excludeNoImage = true;
 			$this->delayedDownloadsImages = false;
diff --git a/core/src/classes/IO6ConnectEngine.class.php b/core/src/classes/IO6ConnectEngine.class.php
index 52f67fc8e923f6ada01c73ca0d9a14776b94a35d..ddbbc0053765b757d8e74f8f148cd2e496be32a9 100755
--- a/core/src/classes/IO6ConnectEngine.class.php
+++ b/core/src/classes/IO6ConnectEngine.class.php
@@ -51,7 +51,7 @@ class IO6ConnectEngine
 			$jCatalogs = [];
 
 		foreach ($jCatalogs as $jCatalog) {
-			$catalogs[] = new IO6Catalog($jCatalog);
+			$catalogs[$jCatalog['id']] = new IO6Catalog($jCatalog);
 		}
 
 		return $catalogs;
@@ -61,11 +61,11 @@ class IO6ConnectEngine
 	 * Return array of IO6Supplier for current Catalog from API Call
 	 * @return array IO6Supplier
 	 */
-	public function GetIO6Suppliers()
+	public function GetIO6Suppliers($catalogId)
 	{
 		$parameters = [];
 		$parameters['onlyActive'] = 'true';
-		$parameters['personalCatalogId'] = $this->configuration->catalogId;
+		$parameters['personalCatalogId'] = $catalogId;
 		$jSuppliers = $this->callIO6API('suppliers', 'GET', $parameters);
 		$suppliers = [];
 		foreach ($jSuppliers as $jSupplier) {
@@ -82,18 +82,18 @@ class IO6ConnectEngine
 	 * @param int $parentCategoryId ParentCategory to retrieve.
 	 * @return array IO6Category
 	 */
-	public function GetIO6Categories($parentCategoryId = 0)
+	public function GetIO6Categories($catalogId, $parentCategoryId = 0)
 	{
 		$parameters = [];
 		$parameters['parentId'] = $parentCategoryId;
-		$jCategories = $this->callIO6API(sprintf('catalogs/%s/categories/list', $this->configuration->catalogId), 'POST', $parameters);
+		$jCategories = $this->callIO6API(sprintf('catalogs/%s/categories/list', $catalogId), 'POST', $parameters);
 
 		$categories = array();
 
 		foreach ($jCategories['items'] as $jCategory) {
 			$subCategories = [];
 			if ($jCategory['hasChildCategories'] == true)
-				$subCategories =	$this->GetIO6Categories($jCategory['id']);
+				$subCategories =	$this->GetIO6Categories($catalogId, $jCategory['id']);
 
 			$categories[] = new IO6Category($jCategory, $subCategories);
 		}
@@ -101,10 +101,10 @@ class IO6ConnectEngine
 		return $categories;
 	}
 
-	public function GetIO6Brands()
+	public function GetIO6Brands($catalogId)
 	{
 		$parameters = [];
-		$jBrands = $this->callIO6API(sprintf('catalogs/%s/brands/list', $this->configuration->catalogId), 'POST', $parameters);
+		$jBrands = $this->callIO6API(sprintf('catalogs/%s/brands/list', $catalogId), 'POST', $parameters);
 
 		$brands = array();
 
@@ -115,10 +115,8 @@ class IO6ConnectEngine
 		return $brands;
 	}
 
-	public function GetIO6Products($currentPage = 1, $pageSize = 0, $io6_id_product_syngle_sync = 0)
+	public function GetIO6Products($currentPage = 1, $pageSize = 0, $catalogId, $priceListId, $io6_id_product_syngle_sync = 0)
 	{
-		session_start();
-
 		$elementsFounds = isset($_SESSION['elementsfounds']) ? intval($_SESSION['elementsfounds']) : 0;
 		$pages = isset($_SESSION['pages']) ? intval($_SESSION['pages']) : 0;
 		$calculateFoundRows = $currentPage == 1 || $elementsFounds <= 0;
@@ -126,7 +124,7 @@ class IO6ConnectEngine
 
 		$retValue = array();
 		$parameters = [];
-		$parameters['priceListId'] = $this->configuration->priceListId;
+		$parameters['priceListId'] = $priceListId;
 		$parameters['pageSize'] = $pageSize;
 		$parameters['currentPage'] = $currentPage;
 		$parameters['imagelimit'] = $this->configuration->imageLimit;
@@ -138,10 +136,11 @@ class IO6ConnectEngine
 		$parameters['isActive'] = 1;
 		$parameters['isObsolete'] = 0;
 
+		//$parameters['ean'] = '4242004259015';
 		if (!empty($io6_id_product_syngle_sync))
 			$parameters['productIds'] = [$io6_id_product_syngle_sync];
 
-		$results = $this->callIO6API(sprintf('catalogs/%s/products/search', $this->configuration->catalogId), 'POST', $parameters);
+		$results = $this->callIO6API(sprintf('catalogs/%s/products/search', $catalogId), 'POST', $parameters);
 
 		$products = array();
 
@@ -163,15 +162,14 @@ class IO6ConnectEngine
 		if($currentPage == $pages){
 			$_SESSION['elementsfounds'] = 0;
 			$_SESSION['pages'] = 0;
-			//session_destroy();
 		}
 		return $retValue;
 	}
 
-	public function GetIO6PriceLists()
+	public function GetIO6PriceLists($catalogId)
 	{
 		$parameters = [];
-		$jPriceLists = $this->callIO6API(sprintf('catalogs/%s/pricelists', $this->configuration->catalogId), 'GET', $parameters);
+			$jPriceLists = $this->callIO6API(sprintf('catalogs/%s/pricelists', $catalogId), 'GET', $parameters);
 
 		// if(empty($jPriceLists))
 		// 	$jPriceLists = [];
diff --git a/core/src/classes/IO6PriceList.class.php b/core/src/classes/IO6PriceList.class.php
index 7587f7909d64a451f4b44f95ab0fba1869e928d1..2620bcd3689bef22bda63933928f3641791c3b7a 100644
--- a/core/src/classes/IO6PriceList.class.php
+++ b/core/src/classes/IO6PriceList.class.php
@@ -4,11 +4,13 @@
 class IO6PriceList {
   public $id;
   public $name;
+  public $selected;
 
 
     function __construct($jPriceList) {
 		$this->id = $jPriceList['id'];
 		$this->name = $jPriceList['name'];
+    $this->selected = false;
 	}
 
 }
diff --git a/core/src/classes/IO6Product.class.php b/core/src/classes/IO6Product.class.php
old mode 100644
new mode 100755
diff --git a/cron.php b/cron.php
index 51f900413e3b91f400583f3940e1afe7e30a1af8..65b7b293c53bbdfd71aa3e4d9f85f9eb3c222570 100644
--- a/cron.php
+++ b/cron.php
@@ -1,4 +1,4 @@
-<?php 
+<?php
 
 //echo("OK...");
 //die();
@@ -16,34 +16,36 @@ if (Tools::isPHPCLI()) {
     error_reporting(E_ERROR | E_WARNING | E_PARSE);
 }
 
-$currentPage = 1;
-$totalPages = 1;
-
-$totalRows = -1;
 
 $actionUrl = isset($argv) && count($argv) > 1 ? $argv[1] : '';
-
+$catalogsSelected = unserialize(Configuration::get('IMPORTERONE6CONNECT_CATALOGS', []));
 
 if($actionUrl != '') {
-  $contents = '';
-
-  while ($currentPage <= $totalPages) {
-    try { 
-			$callUrl = $actionUrl . '&page=' . $currentPage;
-			$results = get_web_page($callUrl);    
-			
-			$totalPages = $results['pages'];
-			
-			echo sprintf('Totale prodotti: %s. Pagine: %s di %s'. PHP_EOL, $results['elementsFounds'], $currentPage , $totalPages);
-			$currentPage++;
-			
-		}
-		catch(Exception $e) {
-			$totalPages=-1;
-            echo($e->getMessage() . PHP_EOL);
-		}
-  } 
-	die('Update from ImporterONE Cloud terminata');
+
+    foreach ($catalogsSelected as $catalog) {
+        $contents = '';
+
+        $currentPage = 1;
+        $totalPages = 1;
+
+        while ($currentPage <= $totalPages) {
+            try {
+                    $callUrl = $actionUrl . '&catalogId='.$catalog['catalog_id'].'&page=' . $currentPage;
+                    $results = get_web_page($callUrl);
+
+                    $totalPages = $results['pages'];
+
+                    echo sprintf('Catalogo "'.$catalog['catalog_id'].'", Totale prodotti: %s. Pagine: %s di %s'. PHP_EOL, $results['elementsFounds'], $currentPage , $totalPages);
+                    $currentPage++;
+
+                }
+                catch(Exception $e) {
+                    $totalPages=-1;
+                    echo($e->getMessage() . PHP_EOL);
+                }
+        }
+        echo('Update Catalogo-'.$catalog['catalog_id'].' from ImporterONE Cloud terminata'. PHP_EOL);
+    }
 }
 else
   die('Parametro Url plugin non impostato!');
diff --git a/override/classes/Product.php b/override/classes/Product.php
index e300038906c51fd6dae6b8f7bbed03ce39cf65a1..920c230293b6a7d72c6c9481ef91f9517df816b8 100755
--- a/override/classes/Product.php
+++ b/override/classes/Product.php
@@ -27,6 +27,8 @@ class Product extends ProductCore
 			$delayedDownloadsImages = Configuration::get('IMPORTERONE6CONNECT_DELAYED_DOWNLOADS_IMAGES');
 			if ((int)$delayedDownloadsImages == 1) {
 				if($context->controller->controller_type == 'admin'){
+				
+					
 					Product::getIO6DelayedImages($id_product, 0); //Limit 1 = solo una immagine
 				} else {
 					Product::getIO6DelayedImages($id_product, 1); //Limit 1 = solo una immagine
@@ -60,7 +62,6 @@ class Product extends ProductCore
 			$io6ConnectGallery = Db::getInstance()->ExecuteS($sql);
 			if (is_array($io6ConnectGallery) && count($io6ConnectGallery)) {
 				$importerone6connectModule = Module::getInstanceByName("ps_connect_io6");
-
 				foreach ($io6ConnectGallery as $k => $io6image) {
 					try {
 						if (function_exists('curl_version')){
@@ -68,14 +69,21 @@ class Product extends ProductCore
 							curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 							curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
 							$image_data = curl_exec($ch);
-						} 
-						
+						}
+
 						if (!function_exists('curl_version')) {
 							$image_data     = @file_get_contents($io6image['image_uri']); // Get image data
 						}
 
 						if (!isset($image_data) || empty($image_data)) continue;
 
+						$finfo = new finfo(FILEINFO_MIME_TYPE);
+						$image_mime_type = $finfo->buffer($image_data);
+
+						if (!str_contains($image_mime_type, 'image')) continue;
+						
+						if (str_contains($image_mime_type, 'bmp')) continue;
+
 						$image_filename = date('YmdHis') . '_' . basename($io6image['image_uri']);
 						$image_filepath = IO6_IMAGES_DIRPATH . $image_filename;
 
diff --git a/ps_connect_io6.php b/ps_connect_io6.php
index 6a85dc3c1ad8148ebb1fade1778d4eb8fa92ede2..91f6ab77f7052df0be2d1dab0419209a41c56830 100755
--- a/ps_connect_io6.php
+++ b/ps_connect_io6.php
@@ -41,11 +41,12 @@ define('IO6_IMAGES_DIRPATH', _PS_UPLOAD_DIR_ . 'io6-images' . DIRECTORY_SEPARATO
 
 
 define('IO6_PHP_MIN', '7.4.13');
-define('IO6_PHP_MAX', '8.1.30');
+define('IO6_PHP_MAX', '8.1.31');
 define('IO6_MAX_EXECUTION_TIME', 300);
 define('IO6_MEMORY_LIMIT', 512);
 define('IO6_PS_VERSION_MIN', '1.7.8.0');
-define('IO6_PS_VERSION_MAX', '8.2.0.0');
+define('IO6_PS_VERSION_MAX', '8.2.0');
+define('IO6_SESSION_ID', 'IO6SESSION');
 
 require_once('core/src/classes/IO6ConnectEngine.class.php');
 
@@ -81,7 +82,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
     {
         $this->name = 'ps_connect_io6';
         $this->tab = 'quick_bulk_update';
-        $this->version = '1.4.4';
+        $this->version = '2.0.0';
         $this->author = 'Imprimis';
         $this->need_instance = 0;
 
@@ -141,12 +142,15 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         Configuration::updateValue('IMPORTERONE6CONNECT_MANAGE_HTMLFEATURES', 1);
         Configuration::updateValue('IMPORTERONE6CONNECT_TEMPLATE_HTMLFEATURES', 0);
         Configuration::updateValue('IMPORTERONE6CONNECT_MANAGE_TAX_RULE_DEFAULT', 0);
+        Configuration::updateValue('IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS', 1);
         Configuration::updateValue('IMPORTERONE6CONNECT_TAX_RULE_DEFAULT', 0);
         Configuration::updateValue('IMPORTERONE6CONNECT_CONCAT_HTMLFEATURES', 1);
         Configuration::updateValue('IMPORTERONE6CONNECT_EXCLUDE_NOIMAGE', 1);
         Configuration::updateValue('IMPORTERONE6CONNECT_MANAGE_FACETEDSEARCH_MODELS', 0);
         Configuration::updateValue('IMPORTERONE6CONNECT_EXCLUDE_AVAILLESSTHAN', 0);
         Configuration::updateValue('IMPORTERONE6CONNECT_EXCLUDE_AVAILTYPE', 0);
+        Configuration::updateValue('IMPORTERONE6CONNECT_CATALOGS', serialize([]));
+
 
         return parent::install() &&
             $this->registerHook('displayFooterProduct') &&
@@ -156,7 +160,15 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             $this->registerHook('displayAdminProductsExtra') &&
             $this->registerHook('displayAdminProductsMainStepLeftColumnMiddle') &&
             $this->registerHook('displayAdminProductsPriceStepBottom') &&
-            $this->registerHook('actionProductFormBuilderModifier');
+            $this->registerHook('actionProductFormBuilderModifier') &&
+            $this->registerHook('actionIO6ProductSaveBefore') &&
+            $this->registerHook('actionIO6ProductSaveAfter') &&
+            $this->registerHook('actionIO6CategorySaveBefore') &&
+            $this->registerHook('actionIO6CategorySaveAfter') &&
+            $this->registerHook('actionIO6BrandSaveBefore') &&
+            $this->registerHook('actionIO6BrandSaveAfter') &&
+            $this->registerHook('actionIO6SupplierSaveBefore') &&
+            $this->registerHook('actionIO6SupplierSaveAfter');
         //TODO Aggiungere Hook actionCategoryDelete per pulire tabella ps_importerone6connect_category e anche per altre entità
 
     }
@@ -181,12 +193,14 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         Configuration::deleteByName('IMPORTERONE6CONNECT_MANAGE_HTMLFEATURES');
         Configuration::deleteByName('IMPORTERONE6CONNECT_TEMPLATE_HTMLFEATURES');
         Configuration::deleteByName('IMPORTERONE6CONNECT_MANAGE_TAX_RULE_DEFAULT');
+        Configuration::deleteByName('IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS');
         Configuration::deleteByName('IMPORTERONE6CONNECT_TAX_RULE_DEFAULT');
         Configuration::deleteByName('IMPORTERONE6CONNECT_CONCAT_HTMLFEATURES');
         Configuration::deleteByName('IMPORTERONE6CONNECT_EXCLUDE_NOIMAGE');
         Configuration::deleteByName('IMPORTERONE6CONNECT_MANAGE_FACETEDSEARCH_MODELS');
         Configuration::deleteByName('IMPORTERONE6CONNECT_EXCLUDE_AVAILLESSTHAN');
         Configuration::deleteByName('IMPORTERONE6CONNECT_EXCLUDE_AVAILTYPE');
+        Configuration::deleteByName('IMPORTERONE6CONNECT_CATALOGS');
 
         include(dirname(__FILE__) . '/sql/uninstall.php');
 
@@ -217,10 +231,11 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         $configuration['apitoken'] = Configuration::get('IMPORTERONE6CONNECT_API_TOKEN');
         $configuration['apiendpoint'] = Configuration::get('IMPORTERONE6CONNECT_API_ENDPOINT');
         $configuration['catalog'] = Configuration::get('IMPORTERONE6CONNECT_CATALOG');
+        $configuration['catalogs'] = Configuration::get('IMPORTERONE6CONNECT_CATALOGS');
         //$configuration['languagecode'] : ''; //CHIEDERE
         //$configuration['tempfolder'] : ''; //CHIEDERE
 
-        $configuration['price_list'] =  Configuration::get('IMPORTERONE6CONNECT_PRICE_LIST');
+        $configuration['price_lists'] =  Configuration::get('IMPORTERONE6CONNECT_PRICE_LISTS');
         $configuration['page_size'] = Configuration::get('IMPORTERONE6CONNECT_PAGESIZE');
         $configuration['image_limit'] = Configuration::get('IMPORTERONE6CONNECT_IMAGELIMIT');
 
@@ -244,6 +259,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         $configuration['manage_categories'] = Configuration::get('IMPORTERONE6CONNECT_MANAGE_CATEGORIES');
         $configuration['manage_excerpt'] = Configuration::get('IMPORTERONE6CONNECT_MANAGE_SHORTDESCRIPTION');
         $configuration['manage_tax_rule'] = Configuration::get('IMPORTERONE6CONNECT_MANAGE_TAX_RULE_DEFAULT');
+        $configuration['manage_io6_suppliers'] = Configuration::get('IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS');
         $configuration['manage_features_html'] = Configuration::get('IMPORTERONE6CONNECT_MANAGE_HTMLFEATURES');
         $configuration['concat_features_html'] = Configuration::get('IMPORTERONE6CONNECT_CONCAT_HTMLFEATURES');
         $configuration['features_html_template'] = Configuration::get('IMPORTERONE6CONNECT_TEMPLATE_HTMLFEATURES');
@@ -275,9 +291,14 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
      */
     public function io6Sync($io6_id_product = 0)
     {
+        session_id(IO6_SESSION_ID);
+        session_start();
+
         $io6_configuration = new IO6ConnectConfiguration($this->getIO6ConnectConfiguration());
         $io6Engine = new IO6ConnectEngine($io6_configuration);
+        $io6_catalogs = unserialize(Configuration::get('IMPORTERONE6CONNECT_CATALOGS'));
 
+        $catalogId = intval(Tools::getValue('catalogId', 0));
         $currentPage = intval(Tools::getValue('page', 1));
         $pageSize = intval(Tools::getValue('page_size', $io6_configuration->pageSize));
         $syncFast = intval(Tools::getValue('fast', 0));
@@ -288,30 +309,54 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         // QUINDI SE ATTIVO LA SYNCRESUME E TUTTI I PRODOTTI HANNO SYNC_STATUS VALORIZZATO ALLORA DISATTIVO LA SYNCRESUME PERCHÈ NON NECESSARIA
         if ($currentPage == 1 && $syncResume){
             $sql = "SELECT COUNT(id_product) FROM ". _DB_PREFIX_ ."importerone6connect_products iop
-            WHERE iop.sync_status = 0 OR iop.sync_status IS NULL";
+            WHERE iop.sync_status = 0 AND iop.sync_exclude = 0";
             $product_not_synced = Db::getInstance()->getValue($sql);
 
             if($product_not_synced == 0)
                 $syncResume = false;
         }
 
-        if ($currentPage == 1 && empty($io6_id_product) && !$syncResume) {
-            $this->cleanImporterone6connectTable();
+        if(!isset($io6_catalogs[$catalogId])){
+            //RITORNA MESSAGGIO DI ERRORE.
+        }
+
+        if ($currentPage == 1){
+            $_SESSION['categories_cache'] = [];
+			$_SESSION['brands_cache'] = [];
+			$_SESSION['suppliers_cache'] = [];
+			$_SESSION['products_cache'] = [];
+        }
 
-            if (!$syncFast) {
-                $this->syncCategories($io6Engine);
-                Category::regenerateEntireNtree();
+        if (!empty($io6_id_product))
+        {
+            $_SESSION['categories_cache'] = $this->preloadImporteroneCategories();
+			$_SESSION['brands_cache'] = $this->preloadImporteroneManufacturers();
+			$_SESSION['suppliers_cache'] = $this->preloadImporteroneSuppliers();
+			$_SESSION['products_cache'] = $this->preloadImporteroneProducts();
+        }
 
-                $this->syncBrands($io6Engine);
+        if(!empty($io6_catalogs) && isset($io6_catalogs[$catalogId])){
+            $catalog = $io6_catalogs[$catalogId];
+            if ($currentPage == 1 && empty($io6_id_product) && !$syncResume) {
+                $this->cleanImporterone6connectTable();
+    
+                if (!$syncFast) {
+                    $this->syncCategories($io6Engine, $catalogId);
+                    Category::regenerateEntireNtree();
+    
+                    $this->syncBrands($io6Engine, $catalogId);
+                }
+    
+                $this->syncSuppliers($io6Engine, $catalogId);
             }
 
-            $this->syncSuppliers($io6Engine);
+            //PASSA CATALOGID e PRICELISTID SEPARATI
+            //$this->io6_write_log(date('Y-m-d H:i:s') . " SyncProduct inizio", IO6_LOG_WARNING);
+            $results = $this->syncProducts($io6Engine, $io6_configuration, $catalogId, $catalog['price_list_id'], $currentPage, $pageSize, $syncFast, $syncResume, $io6_id_product);
+            //$this->io6_write_log(date('Y-m-d H:i:s') . " SyncProduct fine", IO6_LOG_WARNING);
         }
 
-        //$this->io6_write_log(date('Y-m-d H:i:s') . " SyncProduct inizio", IO6_LOG_WARNING);
-        $results = $this->syncProducts($io6Engine, $io6_configuration, $currentPage, $pageSize, $syncFast, $syncResume, $io6_id_product);
-        //$this->io6_write_log(date('Y-m-d H:i:s') . " SyncProduct fine", IO6_LOG_WARNING);
-        if (!empty($io6_id_product)){
+       if (!empty($io6_id_product)){
             return $results;
         } else {
             echo isset($results) ? json_encode($results) : '{}';
@@ -319,7 +364,6 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         }
     }
 
-
     public function cleanImporterone6connectTable()
     {
         //Pulisco eventuali righe orfane senza corrispondenza nella tabella delle Catagorie Prestashop
@@ -417,12 +461,15 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         return $retVal;
     }
 
-    private function preloadImporteroneProducts()
+    private function preloadImporteroneProducts($catalogId = 0)
     {
         //TODO 20210508 Valutare se in caso di cataloghi da diverse migliaia se può degradare le prestazioni (viene ricaricata ad ogni paginazione)
         $retVal = [];
         //$this->io6_write_log(date('Y-m-d H:i:s') . " Preload select inizio", IO6_LOG_WARNING);
-        $sql = 'SELECT io6_id_product, id_product FROM ' . _DB_PREFIX_ . 'importerone6connect_products WHERE io6_id_product > 0';
+        $sql = 'SELECT io6_id_product, id_product FROM ' . _DB_PREFIX_ . 'importerone6connect_products WHERE io6_id_product > 0 ';
+
+        if($catalogId > 0)
+            $sql .= " AND (catalog_id = ". $catalogId ." OR catalog_id IS NULL OR catalog_id = 0)";
 
         $results = DB::getInstance()->executeS($sql);
         //$this->io6_write_log(date('Y-m-d H:i:s') . " Preload select fine", IO6_LOG_WARNING);
@@ -473,23 +520,27 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
 			$ps_category->id_shop_default = (int)Context::getContext()->shop->id;
 		}
 
-
-        if (empty($id_category)) {
-            $ps_category->date_add = date('Y-m-d H:i:s');
-            $res = $ps_category->add();
-            //$this->io6_write_log(date('Y-m-d H:i:s') . " Category add", IO6_LOG_WARNING);
-        } else
-            $res = !$categoryChanged || $ps_category->update();
-
-        //$this->io6_write_log(date('Y-m-d H:i:s') . " Category res after add/update: " . $res , IO6_LOG_WARNING);
-
-        if ($res) {
-            $sql = "REPLACE INTO " . _DB_PREFIX_ . "importerone6connect_categories (id_category, io6_category_code)
-                VALUES (" . $ps_category->id . ",'" . pSQL($io6_category_code) . "')";
-            DB::getInstance()->execute($sql);
-
-            $this->ps_categories_cache[$io6_category_code] = $ps_category->id;
+        $hookReturn = true;
+        Hook::exec('actionIO6CategorySaveBefore', ['ps_category' => &$ps_category, 'hookReturn' => &$hookReturn]);
+        if ($hookReturn){
+            if (empty($id_category)) {
+                $ps_category->date_add = date('Y-m-d H:i:s');
+                $res = $ps_category->add();
+                //$this->io6_write_log(date('Y-m-d H:i:s') . " Category add", IO6_LOG_WARNING);
+            } else
+                $res = !$categoryChanged || $ps_category->update();
+    
+            //$this->io6_write_log(date('Y-m-d H:i:s') . " Category res after add/update: " . $res , IO6_LOG_WARNING);
+    
+            if ($res) {
+                $sql = "REPLACE INTO " . _DB_PREFIX_ . "importerone6connect_categories (id_category, io6_category_code)
+                    VALUES (" . $ps_category->id . ",'" . pSQL($io6_category_code) . "')";
+                DB::getInstance()->execute($sql);
+    
+                $_SESSION['categories_cache'][$io6_category_code] = $ps_category->id;
+            }
         }
+        Hook::exec('actionIO6CategorySaveAfter', ['ps_category' => &$ps_category]);
 
         return $res ? $ps_category : false;
     }
@@ -517,34 +568,42 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             $ps_manufacturer->active = 1;
         }
 
-        if (empty($id_manufacturer)) {
-            $ps_manufacturer->date_add = date('Y-m-d H:i:s');
-            $res = $ps_manufacturer->add();
-            //$this->io6_write_log(date('Y-m-d H:i:s') . " Manufatcuter add" , IO6_LOG_WARNING);
-        } else
-            $res = !$brandChanged || $ps_manufacturer->update();
-
-        //$this->io6_write_log(date('Y-m-d H:i:s') . " Manufatcuter res after add/update: " . $res , IO6_LOG_WARNING);
-
-        if ($res) {
-            $sql = "REPLACE INTO " . _DB_PREFIX_ . "importerone6connect_manufacturers (id_manufacturer, io6_brand_code)
-                VALUES (" . $ps_manufacturer->id . ",'" . pSQL($io6_brand_code) . "')";
-            DB::getInstance()->execute($sql);
-
-            $this->ps_brands_cache[$io6_brand_code] = $ps_manufacturer->id;
-        }
-
-
-        $sql = "SELECT logo FROM " . _DB_PREFIX_ . "importerone6connect_manufacturers WHERE id_manufacturer = " . (int)$ps_manufacturer->id;
-        $old_logo = DB::getInstance()->getValue($sql);
-        if (!empty($logo) && $old_logo != $logo) {
-            if (@$this->generateImgIntoCms($ps_manufacturer->id, $logo, null, 'manufacturers')) {
-                $sql = "UPDATE  " . _DB_PREFIX_ . "importerone6connect_manufacturers SET logo='" . pSQL($logo) . "' WHERE id_manufacturer = " . (int)$ps_manufacturer->id;
+        $hookReturn = true;
+        Hook::exec('actionIO6BrandSaveBefore', ['ps_manufacturer' => &$ps_manufacturer, 'hookReturn' => &$hookReturn]);
+        if ($hookReturn){
+            if (empty($id_manufacturer)) {
+                $ps_manufacturer->date_add = date('Y-m-d H:i:s');
+                $res = $ps_manufacturer->add();
+                //$this->io6_write_log(date('Y-m-d H:i:s') . " Manufatcuter add" , IO6_LOG_WARNING);
+            } else
+                $res = !$brandChanged || $ps_manufacturer->update();
+    
+            //$this->io6_write_log(date('Y-m-d H:i:s') . " Manufatcuter res after add/update: " . $res , IO6_LOG_WARNING);
+    
+            if ($res) {
+                $sql = "REPLACE INTO " . _DB_PREFIX_ . "importerone6connect_manufacturers (id_manufacturer, io6_brand_code)
+                    VALUES (" . $ps_manufacturer->id . ",'" . pSQL($io6_brand_code) . "')";
                 DB::getInstance()->execute($sql);
-            } else {
-                $this->io6_write_log("Logo Manufacturer non salvato. logo: " . $logo, IO6_LOG_WARNING);
+    
+                $_SESSION['brands_cache'][$io6_brand_code] = $ps_manufacturer->id;
+            }
+    
+    
+            $sql = "SELECT logo FROM " . _DB_PREFIX_ . "importerone6connect_manufacturers WHERE id_manufacturer = " . (int)$ps_manufacturer->id;
+            $old_logo = DB::getInstance()->getValue($sql);
+            if (!empty($logo) && $old_logo != $logo) {
+                if (@$this->generateImgIntoCms($ps_manufacturer->id, $logo, null, 'manufacturers')) {
+                    $sql = "UPDATE  " . _DB_PREFIX_ . "importerone6connect_manufacturers SET logo='" . pSQL($logo) . "' WHERE id_manufacturer = " . (int)$ps_manufacturer->id;
+                    DB::getInstance()->execute($sql);
+                } else {
+                    $this->io6_write_log("Logo Manufacturer non salvato. logo: " . $logo, IO6_LOG_WARNING);
+                }
             }
+    
         }
+        
+        Hook::exec('actionIO6BrandSaveAfter', ['ps_manufacturer' => &$ps_manufacturer]);
+        
 
         return $res ? $ps_manufacturer : false;
     }
@@ -573,34 +632,39 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             $ps_supplier->active = 1;
         }
 
-        if (empty($id_supplier)) {
-            $ps_supplier->date_add = date('Y-m-d H:i:s');
-            $res = $ps_supplier->add();
-            //$this->io6_write_log(date('Y-m-d H:i:s') . " Supplier add" , IO6_LOG_WARNING);
-        } else
-            $res = !$supplierChanged || $ps_supplier->update();
-
-        //$this->io6_write_log(date('Y-m-d H:i:s') . " Supplier res after add/update" . $res , IO6_LOG_WARNING);
-
-        if ($res) {
-            $sql = "REPLACE INTO " . _DB_PREFIX_ . "importerone6connect_suppliers (id_supplier, io6_id_supplier)
-                VALUES (" . (int)$ps_supplier->id . "," . (int)$io6_id_supplier . ")";
-            DB::getInstance()->execute($sql);
-
-            $this->ps_suppliers_cache[$io6_id_supplier] = $ps_supplier->id;
+        $hookReturn = true;
+        Hook::exec('actionIO6SupplierSaveBefore', ['ps_supplier' => &$ps_supplier, 'hookReturn' => &$hookReturn]);
+        if($hookReturn){
+            if (empty($id_supplier)) {
+                $ps_supplier->date_add = date('Y-m-d H:i:s');
+                $res = $ps_supplier->add();
+                //$this->io6_write_log(date('Y-m-d H:i:s') . " Supplier add" , IO6_LOG_WARNING);
+            } else
+                $res = !$supplierChanged || $ps_supplier->update();
+    
+            //$this->io6_write_log(date('Y-m-d H:i:s') . " Supplier res after add/update" . $res , IO6_LOG_WARNING);
+    
+            if ($res) {
+                $sql = "REPLACE INTO " . _DB_PREFIX_ . "importerone6connect_suppliers (id_supplier, io6_id_supplier)
+                    VALUES (" . (int)$ps_supplier->id . "," . (int)$io6_id_supplier . ")";
+                DB::getInstance()->execute($sql);
+    
+                $_SESSION['suppliers_cache'][$io6_id_supplier] = $ps_supplier->id;
+            }
         }
+        Hook::exec('actionIO6SupplierSaveAfter', ['ps_supplier' => &$ps_supplier]);
 
         return $res ? $ps_supplier : false;
     }
 
-    public function syncCategories(IO6ConnectEngine $io6Engine,  $categories = null)
+    public function syncCategories(IO6ConnectEngine $io6Engine, $catalogId,  $categories = null)
     {
         $default_language = Configuration::get('PS_LANG_DEFAULT');
 
         if (!isset($categories)) {
-            $categories = $io6Engine->GetIO6Categories();
+            $categories = $io6Engine->GetIO6Categories($catalogId);
             //Precarico in array tutto l'elenco delle categorie associate ad ImpoterONE
-            $this->ps_categories_cache = $this->preloadImporteroneCategories();
+            $_SESSION['categories_cache'] = $this->preloadImporteroneCategories();
 
             $this->shopRootCategory = Context::getContext()->shop->getCategory();
         }
@@ -617,14 +681,14 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
 
             if (empty($category->parentCode)) //Se Vuoto o 0, imposto nella root
                 $ps_category_id_parent = $this->shopRootCategory;
-            else if (isset($this->ps_categories_cache[$category->parentCode])) {
-                $ps_category_id_parent = (int)$this->ps_categories_cache[$category->parentCode];
+            else if (isset($_SESSION['categories_cache'][$category->parentCode])) {
+                $ps_category_id_parent = (int)$_SESSION['categories_cache'][$category->parentCode];
             } else {
                 //TODO: EM20210319 => almeno fare log. capire se saltare la categoria.
             }
 
             //Cerca Categoria tramite Codice IO6
-            $ps_categoryId = !empty($this->ps_categories_cache[$category->code]) ? $this->ps_categories_cache[$category->code] : 0;
+            $ps_categoryId = !empty($_SESSION['categories_cache'][$category->code]) ? $_SESSION['categories_cache'][$category->code] : 0;
 
             if (empty($ps_categoryId)) { //Cerco per nome categoria
                 $categoryFounded = Category::searchByNameAndParentCategoryId($default_language, $category->name, $ps_category_id_parent);
@@ -644,16 +708,16 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             }
 
             if (count($category->subCategories) > 0)
-                $this->syncCategories($io6Engine, $category->subCategories);
+                $this->syncCategories($io6Engine, $catalogId, $category->subCategories);
 
         }
     }
 
-    public function syncBrands(IO6ConnectEngine $io6Engine)
+    public function syncBrands(IO6ConnectEngine $io6Engine, $catalogId)
     {
-        $brands = $io6Engine->GetIO6Brands();
+        $brands = $io6Engine->GetIO6Brands($catalogId);
         //Precarico in array tutto l'elenco dei brand associati ad ImpoterONE
-        $this->ps_brands_cache = $this->preloadImporteroneManufacturers();
+        $_SESSION['brands_cache'] = $this->preloadImporteroneManufacturers();
 
         foreach ($brands as $brand) {
             $brand->name = preg_replace_callback("/(&#[0-9]+;)/", function ($m) {
@@ -663,7 +727,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
 
 
             //Cerca Categoria tramite Codice IO6
-            $ps_brandId = !empty($this->ps_brands_cache[$brand->code]) ? $this->ps_brands_cache[$brand->code] : 0;
+            $ps_brandId = !empty($_SESSION['brands_cache'][$brand->code]) ? $_SESSION['brands_cache'][$brand->code] : 0;
 
 
             if (empty($ps_brandId))
@@ -681,11 +745,11 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         }
     }
 
-    public function syncSuppliers(IO6ConnectEngine $io6Engine)
+    public function syncSuppliers(IO6ConnectEngine $io6Engine, $catalogId)
     {
-        $suppliers = $io6Engine->GetIO6Suppliers();
+        $suppliers = $io6Engine->GetIO6Suppliers($catalogId);
         //Precarico in array tutto l'elenco dei suppliers associati ad ImpoterONE
-        $this->ps_suppliers_cache = $this->preloadImporteroneSuppliers();
+        $_SESSION['suppliers_cache'] = $this->preloadImporteroneSuppliers();
 
         foreach ($suppliers as $supplier) {
             $supplier->name = preg_replace_callback("/(&#[0-9]+;)/", function ($m) {
@@ -694,7 +758,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             $supplier->name =  substr(preg_replace('/[<>;=#{}]/', '', $supplier->name), 0, 64);
 
             //Cerca Categoria tramite Codice IO6
-            $ps_supplierId = !empty($this->ps_suppliers_cache[$supplier->id]) ? $this->ps_suppliers_cache[$supplier->id] : 0;
+            $ps_supplierId = !empty($_SESSION['suppliers_cache'][$supplier->id]) ? $_SESSION['suppliers_cache'][$supplier->id] : 0;
 
             if (empty($ps_supplierId))
                 $ps_supplierId = Supplier::getIdByName($supplier->name);
@@ -708,7 +772,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         }
     }
 
-    function syncProducts(IO6ConnectEngine $io6Engine, IO6ConnectConfiguration $io6_configuration, $currentPage = 1, $pageSize = 0, $fastSync = 0, $syncResume = 0, $io6_id_product_syngle_sync = 0)
+    function syncProducts(IO6ConnectEngine $io6Engine, IO6ConnectConfiguration $io6_configuration, $catalogId, $priceListId, $currentPage = 1, $pageSize = 0, $fastSync = 0, $syncResume = 0, $io6_id_product_syngle_sync = 0)
     {
         $this->io6_write_log("PRODUCT PAGE ". $currentPage ." BEGIN" ,  $fastSync ? "FAST" : "NOT FAST");
         if (Shop::isFeatureActive())
@@ -716,31 +780,33 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         else
             Shop::setContext(Shop::CONTEXT_SHOP, (int) Context::getContext()->shop->id);
 
-
         if ($currentPage == 1 && !$syncResume && empty($io6_id_product_syngle_sync)) {
-            //Resettare sync_date per individuare successivamente solo i prodotti sincronizzati in questa sincro
-            //Se sincro di Resume allora non resetto le sync_date altrimenti tutti i prodotti già importati perderebbero la data di sincronizzazione
-            Db::getInstance()->execute('UPDATE `' . _DB_PREFIX_ . 'importerone6connect_products`
-                                SET `' . _DB_PREFIX_ . 'importerone6connect_products`.`sync_date` = NULL;');
-                                
-            Db::getInstance()->execute('UPDATE `' . _DB_PREFIX_ . 'importerone6connect_products` SET sync_status = 0');
-        }
+            //Resettare sync_status per individuare successivamente solo i prodotti sincronizzati in questa sincro
 
+            Db::getInstance()->execute('UPDATE `' . _DB_PREFIX_ . 'importerone6connect_products` SET sync_status = 0
+            WHERE `' . _DB_PREFIX_ . 'importerone6connect_products`.catalog_id = '. $catalogId);
+        }
 
         $default_language = Configuration::get('PS_LANG_DEFAULT');
-
         $skuField = $io6_configuration->selectedSkuField;
         $skuProp = str_replace('io6_sku_', '', $skuField);
         $eanField = 'ean13'; //$io6_configuration->selectedEanField;
         $partNumberField = 'mpn'; //$io6_configuration->selectedPartNumberField;
         $brandField = 'id_manufacturer'; // $io6_configuration->selectedBrandField;
 
-        //$ean_product_to_sync = !empty($io6_id_product_syngle_sync) ? (new Product($io6_id_product_syngle_sync))->ean13 : 0;
-
-        $io6_results = $io6Engine->GetIO6Products($currentPage, $pageSize, $io6_id_product_syngle_sync);
-        $this->ps_products_cache = $this->preloadImporteroneProducts();
+        $io6_results = $io6Engine->GetIO6Products($currentPage, $pageSize, $catalogId, $priceListId, $io6_id_product_syngle_sync);
+        
+        if ($currentPage == 1 && empty($io6_id_product_syngle_sync))
+            $_SESSION['products_cache'] = $this->preloadImporteroneProducts($catalogId);
+        
+        // Chiamata per conoscere i supplier agganciati a questo catalogo
+        if ($io6_configuration->manageIo6Suppliers) {
+            $catalog_suppliers = $io6Engine->GetIO6Suppliers($catalogId);
+            $catalog_suppliers = implode(',',array_map(function($supplier){
+                return $supplier->id;
+            }, $catalog_suppliers));
 
-        //TODO: EM20210330 => se il prodotto è obsoleto e nn esiste nemmeno lo creo, stessa cosa se con tutti i flag filtro risulta disattivato
+        }
 
         $categories_to_clean = [];
 
@@ -748,6 +814,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         $syncResults['pages'] = $io6_results['pages'];
         $syncResults['elementsFounds'] = $io6_results['elementsFounds'];
         $syncResults['products'] = array();
+
         foreach ($io6_results['products'] as $io6product) {
             //$this->io6_write_log(date('Y-m-d H:i:s') . " product inizio", IO6_LOG_WARNING); //TODO CT 20210511 Se gli passo $e va in errore di memory limit
             //Carico flag con valori di default del modulo
@@ -767,15 +834,14 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             $concat_features_html = $io6_configuration->concatFeaturesHTML; //TODO CT 20211016 Verificare, se non viene usato rimuovere anche da configuration
             //$excludeNoImage = $io6_configuration->excludeNoImage;
             $update_tax_rule = $io6_configuration->manageTaxRule;
+            $manage_io6_suppliers = $io6_configuration->manageIo6Suppliers;
 
             $manage_facetedsearch_models = Configuration::get('IMPORTERONE6CONNECT_MANAGE_FACETEDSEARCH_MODELS') == 1 && !$fastSync;
 
-            $retProduct = array('io6_id' => $io6product->id, 'ean' => $io6product->ean, 'partnumber' => $io6product->partNumber);
+            $retProduct = array('catalog_id' => $catalogId, 'io6_id' => $io6product->id, 'ps_product_id' => 0, 'ean' => $io6product->ean, 'partnumber' => $io6product->partNumber);
 
             $activeState = $io6product->isActive && $io6product->statusCode != 99;
 
-
-
             try {
                 if (!$activeState) {
                     $this->io6_write_log("Prodotto escluso perchè non attivo in ImporterONE. IO6 Product Id: " . $io6product->id, IO6_LOG_INFO);
@@ -786,15 +852,13 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                     // continue;
                 }
 
-                $ps_product_id = isset($this->ps_products_cache[$io6product->id]) ? $this->ps_products_cache[$io6product->id] : 0;
-                $ps_brand_id =    isset($this->ps_brands_cache[$io6product->brandCode]) ? $this->ps_brands_cache[$io6product->brandCode] : 0;
-                $ps_supplier_id =    isset($this->ps_suppliers_cache[$io6product->supplierId]) ? $this->ps_suppliers_cache[$io6product->supplierId] : 0;
-                $ps_category_id = isset($this->ps_categories_cache[$io6product->categoryCode]) ? $this->ps_categories_cache[$io6product->categoryCode] : 0;
-
+                $ps_product_id = isset($_SESSION['products_cache'][$io6product->id]) ? $_SESSION['products_cache'][$io6product->id] : 0;
+                $ps_brand_id =    isset($_SESSION['brands_cache'][$io6product->brandCode]) ? $_SESSION['brands_cache'][$io6product->brandCode] : 0;
+                $ps_supplier_id =    isset($_SESSION['suppliers_cache'][$io6product->supplierId]) ? $_SESSION['suppliers_cache'][$io6product->supplierId] : 0;
+                $ps_category_id = isset($_SESSION['categories_cache'][$io6product->categoryCode]) ? $_SESSION['categories_cache'][$io6product->categoryCode] : 0;
                 $ps_brand = null;
                 $ps_category = null;
 
-
                 if ($ps_product_id == 0) {
                     if ($fastSync) {
                         throw new Exception("Prodotto non aggiornabile con sincro VELOCE perchè non presente in Prestashop o non abbinato ad ImporterONE.");
@@ -808,41 +872,72 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                     //     $ps_product_id = $results[0]->post_id;
                     // }
 
+                    
+
                     if ($ps_product_id == 0 && !empty($io6product->$skuProp)) {
-												
-                        $sql = "SELECT id_product FROM " . _DB_PREFIX_ . "product p 
-																WHERE p.reference = '" . pSQL($io6product->$skuProp) . "'";
+                                                
+                        $sql = "SELECT p.id_product FROM " . _DB_PREFIX_ . "product p 
+                                LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_products ip ON ip.id_product = p.id_product
+                                LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_suppliers s ON s.id_supplier = p.id_supplier
+                                WHERE p.reference = '" . pSQL($io6product->$skuProp) . "' AND (ip.catalog_id IS NULL OR ip.catalog_id = 0 OR ip.catalog_id = " . (int)$catalogId. ")";
 
                         if ($skuProp == 'partNumber')
-														$sql .= " AND id_manufacturer = " . (int)$ps_brand_id;
+                            $sql .= " AND p.id_manufacturer = " . (int)$ps_brand_id;
 
-                        $results = DB::getInstance()->getValue($sql);
+                        if ($manage_io6_suppliers)
+                            $sql .= " AND s.io6_id_supplier IN(".$catalog_suppliers.")";
+
+                        //$this->io6_write_log("QUERY REFERENCE: " . $sql . " per io6product: " . $io6product->id, IO6_LOG_INFO);
+
+                        $results = Db::getInstance()->getValue($sql);
                         if ($results !== false) {
                             $ps_product_id = (int)$results;
                         }
                     }
 
                     if ($ps_product_id == 0 && !empty($io6product->ean)) {
-                        $sql = "SELECT id_product FROM " . _DB_PREFIX_ . "product WHERE " . pSQL($eanField) . " = '" . pSQL($io6product->ean) . "'";
-                        $results = DB::getInstance()->getValue($sql);
+                        $sql = "SELECT p.id_product FROM " . _DB_PREFIX_ . "product p
+                            LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_products ip ON ip.id_product = p.id_product 
+                            LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_suppliers s ON s.id_supplier = p.id_supplier
+                            WHERE p." . pSQL($eanField) . " = '" . pSQL($io6product->ean) . "' AND (ip.catalog_id IS NULL OR ip.catalog_id = 0 OR ip.catalog_id = " . (int)$catalogId. ")";
+                        
+                        if ($manage_io6_suppliers)
+                            $sql .= " AND s.io6_id_supplier IN(".$catalog_suppliers.")";
+
+                        //$this->io6_write_log("QUERY EAN: " . $sql . " per io6product: " . $io6product->id, IO6_LOG_INFO);
+
+                        $results = Db::getInstance()->getValue($sql);
+
                         if ($results !== false) {
                             $ps_product_id = (int)$results;
                         }
+                        //$this->io6_write_log("QUERY EAN RESULT: " . $ps_product_id . " per io6product: " . $io6product->id, IO6_LOG_INFO);
                     }
-										
-										
+                                        
+                                        
                     if (version_compare(_PS_VERSION_, '1.7.7', '>=')) {
                         if ($ps_product_id == 0 && !empty($io6product->partNumber)) {
-                            $sql = "SELECT id_product FROM " . _DB_PREFIX_ . "product WHERE " . pSQL($partNumberField) . " = '" . pSQL($io6product->partNumber) . "' AND id_manufacturer = " . (int)$ps_brand_id;
-                            $results = DB::getInstance()->getValue($sql);
+                            $sql = "SELECT p.id_product FROM " . _DB_PREFIX_ . "product p
+                            LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_products ip ON ip.id_product = p.id_product 
+                            LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_suppliers s ON s.id_supplier = p.id_supplier
+                            WHERE p." . pSQL($partNumberField) . " = '" . pSQL($io6product->partNumber) . "' AND p.id_manufacturer = " . (int)$ps_brand_id . " 
+                            AND (ip.catalog_id IS NULL OR ip.catalog_id = 0 OR ip.catalog_id = " . (int)$catalogId. ")";
+
+                            if ($manage_io6_suppliers)
+                                $sql .= " AND s.io6_id_supplier IN(".$catalog_suppliers.")";
+
+                            //$this->io6_write_log("QUERY MPN: " . $sql . " per io6product: " . $io6product->id, IO6_LOG_INFO);
+
+                            $results = Db::getInstance()->getValue($sql);
+
                             if ($results !== false) {
                                 $ps_product_id = (int)$results;
                             }
+                            //$this->io6_write_log("QUERY MPN RESULT: " . $ps_product_id . " per io6product: " . $io6product->id, IO6_LOG_INFO);
                         }
                     }
                 }
 
-
                 //TODO: EM20210330 => verifica isactive, statuscode e altri filtri. Se condizione è false disattiva il prodotto.
                 //SE nn esiste nn lo crea, se esiste nn lo aggiorna e mette qta = 0
 
@@ -853,7 +948,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                         $results = DB::getInstance()->getValue($sql);
                         if ($results !== false) {
                             $ps_brand_id = (int)$results;
-                            $this->ps_brands_cache[$io6product->brandCode] = $ps_brand_id;
+                            $_SESSION['brands_cache'][$io6product->brandCode] = $ps_brand_id;
                         }
                     }
 
@@ -862,7 +957,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                         $results = DB::getInstance()->getValue($sql);
                         if ($results !== false) {
                             $ps_supplier_id = (int)$results;
-                            $this->ps_suppliers_cache[$io6product->supplierId] = $ps_supplier_id;
+                            $_SESSION['suppliers_cache'][$io6product->supplierId] = $ps_supplier_id;
                         }
                     }
 
@@ -871,7 +966,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                         $results = DB::getInstance()->getValue($sql);
                         if ($results !== false) {
                             $ps_category_id = (int)$results;
-                            $this->ps_categories_cache[$io6product->categoryCode] = $ps_category_id;
+                            $_SESSION['categories_cache'][$io6product->categoryCode] = $ps_category_id;
                         }
                     }
 
@@ -885,6 +980,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                 $isNewProduct = false;
                 $has_cms_images = false;
                 if ($ps_product_id) {
+                    $retProduct['ps_product_id'] = $ps_product_id;
                     $io6ConfigProduct = $this->getImporteroneConnectProduct($ps_product_id);
 
                     if ($syncResume && !empty($io6ConfigProduct['sync_status'])) {
@@ -895,7 +991,6 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                         continue;
                     }
 
-
                     if (!isset($io6ConfigProduct['sync_exclude']) || intval($io6ConfigProduct['sync_exclude']) == 1) {
                         throw new Exception("Product $ps_product_id is not managed by " . $this->displayName);
                     }
@@ -914,6 +1009,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                     $manage_facetedsearch_models = $update_features ? $manage_facetedsearch_models : false;
                     $update_features_html = isset($io6ConfigProduct['manage_htmlfeatures']) && intval($io6ConfigProduct['manage_htmlfeatures']) != 2 ? intval($io6ConfigProduct['manage_htmlfeatures']) : $update_features_html;
                     $update_tax_rule = isset($io6ConfigProduct['manage_tax_rule']) && intval($io6ConfigProduct['manage_tax_rule']) != 2 ? intval($io6ConfigProduct['manage_tax_rule']) : $update_tax_rule;
+                    $manage_io6_suppliers = isset($io6ConfigProduct['manage_io6_suppliers']) && intval($io6ConfigProduct['manage_io6_suppliers']) != 2 ? intval($io6ConfigProduct['manage_io6_suppliers']) : $manage_io6_suppliers;
 
                     $ps_product = new Product($ps_product_id, false);
                     $has_cms_images = (Product::getCover($ps_product_id) !== false);
@@ -964,6 +1060,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                 //     // //TODO CT 20210521 Non va bene fare la continue, andrebbe aggiornata almeno la tabella ps_importerone6connect_products con lo sync_status e sync_message
                 //     // continue;
                 // }
+                
                 $ps_product->active = $activeState;
 
                 if (!$fastSync) {
@@ -1106,375 +1203,395 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                     throw new Exception("Product fields value not valid: " . $validateFields . "-" . $validateFieldsLang);
                 }
 
-                if ($isNewProduct) {
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product add inizio", IO6_LOG_WARNING);
-                    $res = @$ps_product->add();
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product add fine", IO6_LOG_WARNING);
-                } else {
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product update inizio", IO6_LOG_WARNING);
-                    $res = @$ps_product->update();
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product update fine", IO6_LOG_WARNING);
-                }
-                if (!$res) {
-                    throw new Exception("Product Save not completed");
-                }
-
-                if ($update_categories && $categoryChanged) {
-                    //Assegna prodotto a tutto albero delle categorie
-                    $ps_category = new Category($ps_category_id); //TODO: 20210511 CT Per ottimizzare si potrebbe salvare le categorie già istanziate in un dictionary per evitare ogni volta questa query.
-                    $tmp_id_categories = [];
-                    if (is_array($parentsCats = $ps_category->getParentsCategories()) && count($parentsCats) > 0) {
-                        foreach ($parentsCats as $a_p)
-                            $tmp_id_categories[] = $a_p['id_category'];
-                    }
-
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories select inizio", IO6_LOG_WARNING);
-                    $result = Db::getInstance()->executeS(
-                        'SELECT c.`id_category`, cp.position
-                        FROM `' . _DB_PREFIX_ . 'category_product` cp
-                        LEFT JOIN `' . _DB_PREFIX_ . 'category` c ON (c.`id_category` = cp.`id_category`)
-                        ' . Shop::addSqlAssociation('category', 'c', true, null, true) . '
-                        WHERE cp.`id_category` NOT IN (' . implode(',', array_map('intval', $tmp_id_categories)) . ')
-                        AND cp.id_product = ' . (int) $ps_product->id
-                    );
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories select fine", IO6_LOG_WARNING);
-
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories delete inizio", IO6_LOG_WARNING);
-                    foreach ($result as $cat) {
-                        $return = Db::getInstance()->delete('category_product', 'id_product = ' . (int) $ps_product->id . ' AND id_category = ' . (int)$cat['id_category']);
-                        $categories_to_clean[$cat['id_category']] = $cat;
-                        //$ps_product->deleteCategory($cat['id_category']);
+                $hookReturn = true;
+                Hook::exec('actionIO6ProductSaveBefore', ['io6_product' => &$io6product, 'ps_product' => &$ps_product, 'hookReturn' => &$hookReturn]);
+                //Se nessun modulo si collega all'hook e quindi non viene chiamata nessuna funzione l'hook restituisce "null" quindi assegno a retVal solo se diverso da "null"
+                if ($hookReturn) {
+                    if ($isNewProduct) {
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product add inizio", IO6_LOG_WARNING);
+                        $res = @$ps_product->add();
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product add fine", IO6_LOG_WARNING);
+                    } else {
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product update inizio", IO6_LOG_WARNING);
+                        $res = @$ps_product->update();
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product update fine", IO6_LOG_WARNING);
                     }
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories delete fine", IO6_LOG_WARNING);
-
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product add categories inizio", IO6_LOG_WARNING);
-                    if (!$ps_product->addToCategories($tmp_id_categories)) {
-                        throw new Exception("Errore nell'assegnazione delle categorie al prodotto " . $io6product->code);
+                    if (!$res) {
+                        throw new Exception("Product Save not completed");
                     }
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product add categories fine", IO6_LOG_WARNING);
-
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific rules inizio", IO6_LOG_WARNING);
-                    SpecificPriceRule::applyAllRules([(int) $ps_product->id]);
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific rules fine", IO6_LOG_WARNING);
-
-                    //$ps_product->updateCategories($tmp_id_categories);
-                }
-
-                if (!empty($ps_supplier_id)) {
-                    if (!$isNewProduct) {
-                        //Rimuovo vecchi supplier associati
-                        $product_supplier_del = new ProductSupplier();
-                        $product_supplier_del->id_product = $ps_product->id;
-                        $product_supplier_del->id_product_attribute = 0;
-                        $product_supplier_del->delete();
+    
+                    if ($update_categories && $categoryChanged) {
+                        //Assegna prodotto a tutto albero delle categorie
+                        $ps_category = new Category($ps_category_id); //TODO: 20210511 CT Per ottimizzare si potrebbe salvare le categorie già istanziate in un dictionary per evitare ogni volta questa query.
+                        $tmp_id_categories = [];
+                        if (is_array($parentsCats = $ps_category->getParentsCategories()) && count($parentsCats) > 0) {
+                            foreach ($parentsCats as $a_p)
+                                $tmp_id_categories[] = $a_p['id_category'];
+                        }
+    
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories select inizio", IO6_LOG_WARNING);
+                        $result = Db::getInstance()->executeS(
+                            'SELECT c.`id_category`, cp.position
+                            FROM `' . _DB_PREFIX_ . 'category_product` cp
+                            LEFT JOIN `' . _DB_PREFIX_ . 'category` c ON (c.`id_category` = cp.`id_category`)
+                            ' . Shop::addSqlAssociation('category', 'c', true, null, true) . '
+                            WHERE cp.`id_category` NOT IN (' . implode(',', array_map('intval', $tmp_id_categories)) . ')
+                            AND cp.id_product = ' . (int) $ps_product->id
+                        );
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories select fine", IO6_LOG_WARNING);
+    
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories delete inizio", IO6_LOG_WARNING);
+                        foreach ($result as $cat) {
+                            $return = Db::getInstance()->delete('category_product', 'id_product = ' . (int) $ps_product->id . ' AND id_category = ' . (int)$cat['id_category']);
+                            $categories_to_clean[$cat['id_category']] = $cat;
+                            //$ps_product->deleteCategory($cat['id_category']);
+                        }
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product categories delete fine", IO6_LOG_WARNING);
+    
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product add categories inizio", IO6_LOG_WARNING);
+                        if (!$ps_product->addToCategories($tmp_id_categories)) {
+                            throw new Exception("Errore nell'assegnazione delle categorie al prodotto " . $io6product->code);
+                        }
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product add categories fine", IO6_LOG_WARNING);
+    
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific rules inizio", IO6_LOG_WARNING);
+                        SpecificPriceRule::applyAllRules([(int) $ps_product->id]);
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific rules fine", IO6_LOG_WARNING);
+    
+                        //$ps_product->updateCategories($tmp_id_categories);
                     }
-                    $ps_product->addSupplierReference($ps_supplier_id, 0, $io6product->code, ($io6product->promoPrice > 0 && $io6product->promoPrice < $io6product->dealerPrice) ? $io6product->promoPrice + $io6product->siaeAmount : $io6product->dealerPrice + $io6product->siaeAmount);
-                }
-                //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific price start", IO6_LOG_WARNING);
-                if ($update_prices && $update_specific_prices) { //Prezzi specifici, prezzi custom
-                    $specificPricesNotImporterONE = [];
-                    if (!$isNewProduct) {
-                        //azzera eventuali prezzi speciale precedentemente impostati da IO6
-                        $specificPricesByImporterONE = $this->getSpecificPricesByImporterONE($ps_product->id);
-                        foreach ($specificPricesByImporterONE as $id_specific_price) {
-                            $specific_price = new SpecificPrice($id_specific_price);
-                            $specific_price->delete();
+    
+                    if (!empty($ps_supplier_id)) {
+                        if (!$isNewProduct) {
+                            //Rimuovo vecchi supplier associati
+                            $product_supplier_del = new ProductSupplier();
+                            $product_supplier_del->id_product = $ps_product->id;
+                            $product_supplier_del->id_product_attribute = 0;
+                            $product_supplier_del->delete();
                         }
-
-                        $specificPricesNotImporterONE = $this->getSpecificPricesCmsAll($ps_product->id); //CT Ho già rimosso quelli i IO6; $this->getSpecificPricesNotImporterONE($ps_product->id);
+                        $ps_product->addSupplierReference($ps_supplier_id, 0, $io6product->code, ($io6product->promoPrice > 0 && $io6product->promoPrice < $io6product->dealerPrice) ? $io6product->promoPrice + $io6product->siaeAmount : $io6product->dealerPrice + $io6product->siaeAmount);
                     }
+                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific price start", IO6_LOG_WARNING);
+                    if ($update_prices && $update_specific_prices) { //Prezzi specifici, prezzi custom
+                        $specificPricesNotImporterONE = [];
+                        if (!$isNewProduct) {
+                            //azzera eventuali prezzi speciale precedentemente impostati da IO6
+                            $specificPricesByImporterONE = $this->getSpecificPricesByImporterONE($ps_product->id);
+                            foreach ($specificPricesByImporterONE as $id_specific_price) {
+                                $specific_price = new SpecificPrice($id_specific_price);
+                                $specific_price->delete();
+                            }
 
-                    if ($io6product->sellingCustomPrice > 0 && $io6product->sellingCustomPrice < $io6product->sellingPrice) { //TODO CT 20210517 Va aggiunta anche la verifica sulle date della promo
-                        $sellingPrice = $io6product->sellingPrice + $io6product->siaeAmount;
-                        $sellingCustomPrice = $io6product->sellingCustomPrice + $io6product->siaeAmount;
-
-                        $sellingCustomPriceUntil = '0000-00-00 00:00:00';
-                        // $this->io6_write_log("io6product->sellingCustomPriceUntil: ". $io6product->sellingCustomPriceUntil, IO6_LOG_INFO);
-                        if (strtotime($io6product->sellingCustomPriceUntil) !== false) {
-                            $sellingCustomPriceUntil = date("Y-m-d H:i:s", strtotime($io6product->sellingCustomPriceUntil));
-                            // $this->io6_write_log("sellingCustomPriceUntil: ". $sellingCustomPriceUntil, IO6_LOG_INFO);
-                            $sellingCustomPriceUntil = Validate::isDate($sellingCustomPriceUntil)  ? $sellingCustomPriceUntil : '0000-00-00 00:00:00';
-                            // $this->io6_write_log("sellingCustomPriceUntil: ". $sellingCustomPriceUntil, IO6_LOG_INFO);
-                        } else {
-                            $this->io6_write_log("sellingCustomPriceUntil: " . $io6product->sellingCustomPriceUntil . " NON valida per io6product: " . $io6product->id, IO6_LOG_INFO);
+                            $specificPricesNotImporterONE = $this->getSpecificPricesCmsAll($ps_product->id); //CT Ho già rimosso quelli i IO6; $this->getSpecificPricesNotImporterONE($ps_product->id);
                         }
-
-                        $id_shop_list = Shop::getShops(true, null, true);
-                        foreach ($id_shop_list as $id_shop) {
-                            //$this->echoDebug("updating reduction_price=" . $info['reduction_price'] . " - id product=" . $id . " in shop: " . $id_shop, IO_LEVEL_DEBUG);
-
-                            // $specific_price = SpecificPrice::getSpecificPrice($id, $id_shop, 0, 0, 0, 1, 0, 0, 0, 0);
-                            // if (is_array($specific_price) && isset($specific_price['id_specific_price']))
-                            // $specific_price = new SpecificPrice((int)$specific_price['id_specific_price']);
-                            // else
-                            $specific_price = new SpecificPrice();
-                            $specific_price->id_product = (int)$ps_product->id;
-                            $specific_price->id_specific_price_rule = 0;
-                            $specific_price->id_shop = $id_shop;
-                            $specific_price->id_currency = 0;
-                            $specific_price->id_country = 0;
-                            $specific_price->id_group = 0;
-                            $specific_price->id_customer = 0;
-                            $specific_price->from_quantity = 1;
-
-                            // //Riduzione in percentuale
-                            // $specific_price->price = -1;
-                            // $specific_price->reduction = round(((isset($info['reduction_price']) AND $info['reduction_price']) ? (1-($info['reduction_price']/$info['price'])): 0), 6);
-                            // $specific_price->reduction_type = 'percentage';
-                            //Riduzione con sottrazione fissa
-                            $specific_price->price = -1;
-                            $specific_price->reduction = round(($sellingPrice - $sellingCustomPrice), 6);
-                            $specific_price->reduction_type = 'amount';
-                            $specific_price->reduction_tax = 0;
-
-                            //$specific_price->from = (isset($info['reduction_from']) && ($info['reduction_from'] != '0001-01-01') && Validate::isDate($info['reduction_from'])) ? $info['reduction_from'] : '0000-00-00 00:00:00';
-                            $specific_price->from = '0000-00-00 00:00:00';
-                            $specific_price->to = $sellingCustomPriceUntil;
-
-                            if (!$specific_price->add()) {
-                                // $this->echoDebug("error updating reduction_price=" . $info['reduction_price'] . " - reduction_from=" . $info['reduction_from'] . " - reduction_to=" . $info['reduction_to'] . " id product=" . $id . " in shop: " . $id_shop, IO_LEVEL_WARNING);
+    
+                        if ($io6product->sellingCustomPrice > 0 && $io6product->sellingCustomPrice < $io6product->sellingPrice) { //TODO CT 20210517 Va aggiunta anche la verifica sulle date della promo
+                            $sellingPrice = $io6product->sellingPrice + $io6product->siaeAmount;
+                            $sellingCustomPrice = $io6product->sellingCustomPrice + $io6product->siaeAmount;
+    
+                            $sellingCustomPriceUntil = '0000-00-00 00:00:00';
+                            // $this->io6_write_log("io6product->sellingCustomPriceUntil: ". $io6product->sellingCustomPriceUntil, IO6_LOG_INFO);
+                            if (strtotime($io6product->sellingCustomPriceUntil) !== false) {
+                                $sellingCustomPriceUntil = date("Y-m-d H:i:s", strtotime($io6product->sellingCustomPriceUntil));
+                                // $this->io6_write_log("sellingCustomPriceUntil: ". $sellingCustomPriceUntil, IO6_LOG_INFO);
+                                $sellingCustomPriceUntil = Validate::isDate($sellingCustomPriceUntil)  ? $sellingCustomPriceUntil : '0000-00-00 00:00:00';
+                                // $this->io6_write_log("sellingCustomPriceUntil: ". $sellingCustomPriceUntil, IO6_LOG_INFO);
+                            } else {
+                                $this->io6_write_log("sellingCustomPriceUntil: " . $io6product->sellingCustomPriceUntil . " NON valida per io6product: " . $io6product->id, IO6_LOG_INFO);
+                            }
+    
+                            $id_shop_list = Shop::getShops(true, null, true);
+                            foreach ($id_shop_list as $id_shop) {
+                                //$this->echoDebug("updating reduction_price=" . $info['reduction_price'] . " - id product=" . $id . " in shop: " . $id_shop, IO_LEVEL_DEBUG);
+    
+                                // $specific_price = SpecificPrice::getSpecificPrice($id, $id_shop, 0, 0, 0, 1, 0, 0, 0, 0);
+                                // if (is_array($specific_price) && isset($specific_price['id_specific_price']))
+                                // $specific_price = new SpecificPrice((int)$specific_price['id_specific_price']);
+                                // else
+                                $specific_price = new SpecificPrice();
+                                $specific_price->id_product = (int)$ps_product->id;
+                                $specific_price->id_specific_price_rule = 0;
+                                $specific_price->id_shop = $id_shop;
+                                $specific_price->id_currency = 0;
+                                $specific_price->id_country = 0;
+                                $specific_price->id_group = 0;
+                                $specific_price->id_customer = 0;
+                                $specific_price->from_quantity = 1;
+    
+                                // //Riduzione in percentuale
+                                // $specific_price->price = -1;
+                                // $specific_price->reduction = round(((isset($info['reduction_price']) AND $info['reduction_price']) ? (1-($info['reduction_price']/$info['price'])): 0), 6);
+                                // $specific_price->reduction_type = 'percentage';
+                                //Riduzione con sottrazione fissa
+                                $specific_price->price = -1;
+                                $specific_price->reduction = round(($sellingPrice - $sellingCustomPrice), 6);
+                                $specific_price->reduction_type = 'amount';
+                                $specific_price->reduction_tax = 0;
+    
+                                //$specific_price->from = (isset($info['reduction_from']) && ($info['reduction_from'] != '0001-01-01') && Validate::isDate($info['reduction_from'])) ? $info['reduction_from'] : '0000-00-00 00:00:00';
+                                $specific_price->from = '0000-00-00 00:00:00';
+                                $specific_price->to = $sellingCustomPriceUntil;
+    
+                                if (!$specific_price->add()) {
+                                    // $this->echoDebug("error updating reduction_price=" . $info['reduction_price'] . " - reduction_from=" . $info['reduction_from'] . " - reduction_to=" . $info['reduction_to'] . " id product=" . $id . " in shop: " . $id_shop, IO_LEVEL_WARNING);
+                                }
                             }
                         }
+    
+                        //Memorizzo specific_price inviati da ImpoterONE
+                        $specificPricesAll = $this->getSpecificPricesCmsAll($ps_product->id); //Recupero nuovamente tutti i prezzi specifici dopo gli eventuali inserimenti fatti da IO6
+                        $specificPricesByImporterONENew = array_diff($specificPricesAll, $specificPricesNotImporterONE); //La differenza mi restituisce solo quelli appena inseriti da IO6
+                        $this->saveSpecificPricecsByImporterONE($ps_product->id, $specificPricesByImporterONENew);
                     }
-
-                    //Memorizzo specific_price inviati da ImpoterONE
-                    $specificPricesAll = $this->getSpecificPricesCmsAll($ps_product->id); //Recupero nuovamente tutti i prezzi specifici dopo gli eventuali inserimenti fatti da IO6
-                    $specificPricesByImporterONENew = array_diff($specificPricesAll, $specificPricesNotImporterONE); //La differenza mi restituisce solo quelli appena inseriti da IO6
-                    $this->saveSpecificPricecsByImporterONE($ps_product->id, $specificPricesByImporterONENew);
-                }
-                //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific price fine", IO6_LOG_WARNING);
-
-                //StockAvailable::setQuantity($ps_product->id, 0, (int)$io6product->avail, (int)Context::getContext()->shop->id);
-                if($update_stock){
-                    $id_shop_list = Shop::getContextListShopID();
-                    
-                    foreach ($id_shop_list as $id_shop) {
-                        Shop::setContext(Shop::CONTEXT_SHOP, (int) $id_shop); //StockAvailable::setQuantity NECESSITA che il context sia un id_shop singolo
-                        StockAvailable::setQuantity($ps_product->id, 0, (int)$io6product->avail, (int)$id_shop);
+                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product specific price fine", IO6_LOG_WARNING);
+    
+                    //StockAvailable::setQuantity($ps_product->id, 0, (int)$io6product->avail, (int)Context::getContext()->shop->id);
+                    if($update_stock){
+                        $id_shop_list = Shop::getContextListShopID();
+                        
+                        foreach ($id_shop_list as $id_shop) {
+                            Shop::setContext(Shop::CONTEXT_SHOP, (int) $id_shop); //StockAvailable::setQuantity NECESSITA che il context sia un id_shop singolo
+                            StockAvailable::setQuantity($ps_product->id, 0, (int)$io6product->avail, (int)$id_shop);
+                        }
+                        
+                        if (Shop::isFeatureActive()) //Se necessario ripristino il CONTEXT_ALL
+                            Context::getContext()->shop->setContext(Shop::CONTEXT_ALL);
+                        else
+                            Shop::setContext(Shop::CONTEXT_SHOP, (int) Context::getContext()->shop->id);
                     }
                     
-                    if (Shop::isFeatureActive()) //Se necessario ripristino il CONTEXT_ALL
-                        Context::getContext()->shop->setContext(Shop::CONTEXT_ALL);
-                    else
-                        Shop::setContext(Shop::CONTEXT_SHOP, (int) Context::getContext()->shop->id);
-                }
-
-                if ($update_images) {
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product images start", IO6_LOG_WARNING);
-                    $io6ConnectGallery = [];
-
-                    if (!$isNewProduct) {
-                        $sql = 'SELECT id_product, id_image, image_uri, orderindex, lastupdate FROM ' . _DB_PREFIX_ . 'importerone6connect_images WHERE id_product = ' . (int)$ps_product->id;
-                        $io6ConnectGallery = DB::getInstance()->executeS($sql);
-                    }
-                    foreach ($io6product->images as $key => $io6image) {
-                        $to_download = true;
-
+                    if ($update_images) {
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product images start", IO6_LOG_WARNING);
+                        $io6ConnectGallery = [];
+    
                         if (!$isNewProduct) {
-
-                            $imageRows = array_filter(
-                                $io6ConnectGallery,
-                                function ($io6ConnectImage) use ($io6image) {
-                                    return $io6ConnectImage['image_uri'] == $io6image->imageUri;
-                                }
-                            );
-
-
-                            $imageRowExists = !empty($imageRows);
-
-                            if ($imageRowExists) {
-                                $ps_image = reset($imageRows);
-                                if ($io6image->lastUpdate > $ps_image['lastupdate']) { //immagine ricevuta più recente di quella caricata precedentemente, quindi aggiornare
-                                    //Controlla se id_image > 0, altrimenti vuol dire che non non è stata ancora scaricata e inserita in prestashop (postdownload), quindi non è necessario cancellare da prestashop
-                                    if ($ps_image['id_image'] > 0) {
-                                        //$this->echoDebug("Immagine inviata più recente di quella caricata in Prestashop, quindi rimuovo immagine precedente da Prestashop", IO_LEVEL_DEBUG);
-                                        $imageToDel = new Image((int)$ps_image['id_image']);
-                                        $resDel = $imageToDel->delete();
-                                        //$this->echoDebug("Immagine precedente eliminata - res: " . $resDel, IO_LEVEL_DEBUG);
-                                        unset($imageToDel);
+                            $sql = 'SELECT id_product, id_image, image_uri, orderindex, lastupdate FROM ' . _DB_PREFIX_ . 'importerone6connect_images WHERE id_product = ' . (int)$ps_product->id;
+                            $io6ConnectGallery = DB::getInstance()->executeS($sql);
+                        }
+                        foreach ($io6product->images as $key => $io6image) {
+                            $to_download = true;
+    
+                            if (!$isNewProduct) {
+    
+                                $imageRows = array_filter(
+                                    $io6ConnectGallery,
+                                    function ($io6ConnectImage) use ($io6image) {
+                                        return $io6ConnectImage['image_uri'] == $io6image->imageUri;
+                                    }
+                                );
+    
+    
+                                $imageRowExists = !empty($imageRows);
+    
+                                if ($imageRowExists) {
+                                    $ps_image = reset($imageRows);
+                                    if ($io6image->lastUpdate > $ps_image['lastupdate']) { //immagine ricevuta più recente di quella caricata precedentemente, quindi aggiornare
+                                        //Controlla se id_image > 0, altrimenti vuol dire che non non è stata ancora scaricata e inserita in prestashop (postdownload), quindi non è necessario cancellare da prestashop
+                                        if ($ps_image['id_image'] > 0) {
+                                            //$this->echoDebug("Immagine inviata più recente di quella caricata in Prestashop, quindi rimuovo immagine precedente da Prestashop", IO_LEVEL_DEBUG);
+                                            $imageToDel = new Image((int)$ps_image['id_image']);
+                                            $resDel = $imageToDel->delete();
+                                            //$this->echoDebug("Immagine precedente eliminata - res: " . $resDel, IO_LEVEL_DEBUG);
+                                            unset($imageToDel);
+                                        }
+    
+                                        //Elimino riga da tabella importerone6connect_images
+                                        $res = Db::getInstance()->Execute('DELETE FROM `' . _DB_PREFIX_ . 'importerone6connect_images` 
+                                                                        WHERE  id_product =' . (int)$ps_product->id . ' AND image_uri=\'' . $ps_image['image_uri'] . '\' ; ');
+                                    } else {
+                                        // $this->echoDebug("Non è necessario aggiornare l'immagine", IO_LEVEL_DEBUG);
+                                        $to_download = false;
+                                        // continue; //TODO CT 20210512 si potrebbe anche fare il continue
                                     }
-
-                                    //Elimino riga da tabella importerone6connect_images
-                                    $res = Db::getInstance()->Execute('DELETE FROM `' . _DB_PREFIX_ . 'importerone6connect_images` 
-                                                                    WHERE  id_product =' . (int)$ps_product->id . ' AND image_uri=\'' . $ps_image['image_uri'] . '\' ; ');
-                                } else {
-                                    // $this->echoDebug("Non è necessario aggiornare l'immagine", IO_LEVEL_DEBUG);
-                                    $to_download = false;
-                                    // continue; //TODO CT 20210512 si potrebbe anche fare il continue
                                 }
                             }
-                        }
-
-                        if ($to_download) {
-                            //Verificare parametro se fare il download subito oppure ritardato (realtime dal sito), se ritardato inserire solo la riga nella tabella io_images con id_image = 0
-                            if ($delayedDownloadsImages) {
-                                //Inserisco riga in tabella io_images con id_image = 0
-                                Db::getInstance()->Execute('INSERT IGNORE INTO `' . _DB_PREFIX_ . 'importerone6connect_images` (id_product, image_uri, id_image, orderindex, lastupdate) 
-                                                                VALUES(' . (int)$ps_product->id . ', \'' . pSQL($io6image->imageUri) . '\', 0,' . (int)$io6image->orderIndex . ',' . date('YmdHis', strtotime($io6image->lastUpdate)) . ' ) ; ');
-                            } else {
-                                //scarica l'immagine
-                                $image_data     = $this->downloadImage($io6image->imageUri);  // Get image data								
-                                if (!isset($image_data) || $image_data === false) continue;
-
-                                $image_filename = date('YmdHis') . '_' . basename($io6image->imageUri);
-                                $image_filepath = IO6_IMAGES_DIRPATH . $image_filename;
-
-                                file_put_contents($image_filepath, $image_data);
-
-                                $cms_image = new Image();
-                                $cms_image->id_product = (int)$ps_product->id;
-                                $cms_image->position = Image::getHighestPosition((int)$ps_product->id) + 1;
-                                $cms_image->cover = ((bool)Image::getCover((int)$ps_product->id)) ? 0 : 1;
-
-                                if ($cms_image->add()) {
-                                    // $cms_image->associateTo((int)(Context::getContext()->shop->id)); //Non serve perchè il metodo ->add già associa in automatico a tutti gli shop
-                                    if (@$this->generateImgIntoCms((int)$ps_product->id, $image_filepath, $cms_image)) {
-                                        // $this->echoDebug("added image=" . $image_filepath . " id product=" . $id_product, IO_LEVEL_DEBUG);
-                                        Db::getInstance()->Execute('INSERT IGNORE INTO `' . _DB_PREFIX_ . 'importerone6connect_images` (id_product, image_uri, id_image, orderindex, lastupdate) 
-                                            VALUES(' . (int)$ps_product->id  . ', \'' . pSQL($io6image->imageUri) . '\', ' . (int)$cms_image->id . ',' . (int)$io6image->orderIndex . ',' . date('YmdHis', strtotime($io6image->lastUpdate)) . ' ) ; ');
+    
+                            if ($to_download) {
+                                //Verificare parametro se fare il download subito oppure ritardato (realtime dal sito), se ritardato inserire solo la riga nella tabella io_images con id_image = 0
+                                if ($delayedDownloadsImages) {
+                                    //Inserisco riga in tabella io_images con id_image = 0
+                                    Db::getInstance()->Execute('INSERT IGNORE INTO `' . _DB_PREFIX_ . 'importerone6connect_images` (id_product, image_uri, id_image, orderindex, lastupdate) 
+                                                                    VALUES(' . (int)$ps_product->id . ', \'' . pSQL($io6image->imageUri) . '\', 0,' . (int)$io6image->orderIndex . ',' . date('YmdHis', strtotime($io6image->lastUpdate)) . ' ) ; ');
+                                } else {
+                                    //scarica l'immagine
+                                    $image_data     = $this->downloadImage($io6image->imageUri);  // Get image data
+                                    if (!isset($image_data) || $image_data === false) continue;
+    
+                                    $finfo = new finfo(FILEINFO_MIME_TYPE);
+                                    $image_mime_type = $finfo->buffer($image_data);
+
+                                    if (!str_contains($image_mime_type, 'image')) continue;
+                                    
+                                    if (str_contains($image_mime_type, 'bmp')) continue;
+                                    
+                                    $image_filename = date('YmdHis') . '_' . basename($io6image->imageUri);
+                                    $image_filepath = IO6_IMAGES_DIRPATH . $image_filename;
+    
+                                    file_put_contents($image_filepath, $image_data);
+    
+                                    $cms_image = new Image();
+                                    $cms_image->id_product = (int)$ps_product->id;
+                                    $cms_image->position = Image::getHighestPosition((int)$ps_product->id) + 1;
+                                    $cms_image->cover = ((bool)Image::getCover((int)$ps_product->id)) ? 0 : 1;
+    
+                                    if ($cms_image->add()) {
+                                        // $cms_image->associateTo((int)(Context::getContext()->shop->id)); //Non serve perchè il metodo ->add già associa in automatico a tutti gli shop
+                                        if (@$this->generateImgIntoCms((int)$ps_product->id, $image_filepath, $cms_image)) {
+                                            // $this->echoDebug("added image=" . $image_filepath . " id product=" . $id_product, IO_LEVEL_DEBUG);
+                                            Db::getInstance()->Execute('INSERT IGNORE INTO `' . _DB_PREFIX_ . 'importerone6connect_images` (id_product, image_uri, id_image, orderindex, lastupdate) 
+                                                VALUES(' . (int)$ps_product->id  . ', \'' . pSQL($io6image->imageUri) . '\', ' . (int)$cms_image->id . ',' . (int)$io6image->orderIndex . ',' . date('YmdHis', strtotime($io6image->lastUpdate)) . ' ) ; ');
+                                        } else {
+                                            $cms_image->delete(); //Rimuovo anche anagrafica immagine
+                                            // $this->echoDebug("generateImgIntoCms non riuscita. product_image_url=" . $image_filepath . " id product=" . $id_product, IO_LEVEL_WARNING);
+                                            // $this->count_notsaved++;
+                                        }
                                     } else {
-                                        $cms_image->delete(); //Rimuovo anche anagrafica immagine
-                                        // $this->echoDebug("generateImgIntoCms non riuscita. product_image_url=" . $image_filepath . " id product=" . $id_product, IO_LEVEL_WARNING);
                                         // $this->count_notsaved++;
+                                        // $this->echoDebug("errore image add=" . $image_filepath . " id product=" . $id_product, IO_LEVEL_WARNING);
                                     }
-                                } else {
-                                    // $this->count_notsaved++;
-                                    // $this->echoDebug("errore image add=" . $image_filepath . " id product=" . $id_product, IO_LEVEL_WARNING);
+                                    unlink($image_filepath);
+    
+                                    //usleep(1000000/3);							
                                 }
-                                unlink($image_filepath);
-
-                                //usleep(1000000/3);							
                             }
                         }
-                    }
-
-                    //pulizia immagini inversa
-                    if (!$isNewProduct) {
-                        // $sql = 'SELECT id_product, id_image, image_uri, lastupdate FROM '._DB_PREFIX_.'importerone6connect_images WHERE id_product = ' . (int)$ps_product->id;
-                        $sql = 'SELECT ' . _DB_PREFIX_ . 'image.id_product, ' . _DB_PREFIX_ . 'image.id_image, ' . _DB_PREFIX_ . 'importerone6connect_images.image_uri as io6ImageUri FROM `' . _DB_PREFIX_ . 'image` 
-                            INNER JOIN  `' . _DB_PREFIX_ . 'importerone6connect_images` ON `' . _DB_PREFIX_ . 'image`.id_product = `' . _DB_PREFIX_ . 'importerone6connect_images`.id_product AND `' . _DB_PREFIX_ . 'image`.id_image = `' . _DB_PREFIX_ . 'importerone6connect_images`.id_image
-                            WHERE `' . _DB_PREFIX_ . 'image`.id_product = ' . (int)$ps_product->id;
-                        $checkGallery = DB::getInstance()->executeS($sql);
-
-                        foreach ($checkGallery as $checkImage) {
-                            $foundImage = !empty($checkImage['io6ImageUri']);
-
-                            $foundImage &= !empty(array_filter(
-                                $io6product->images,
-                                function ($image) use ($checkImage) {
-                                    return $checkImage['io6ImageUri'] == $image->imageUri;
-                                }
-                            ));
-
-                            if (!$foundImage) {
-                                $idImageToDel = (int)$checkImage['id_image'];
-                                if ($idImageToDel > 0) {
-                                    $imageToDel = new Image($idImageToDel);
-                                    $imageToDel->delete();
+    
+                        //pulizia immagini inversa
+                        if (!$isNewProduct) {
+                            // $sql = 'SELECT id_product, id_image, image_uri, lastupdate FROM '._DB_PREFIX_.'importerone6connect_images WHERE id_product = ' . (int)$ps_product->id;
+                            $sql = 'SELECT ' . _DB_PREFIX_ . 'image.id_product, ' . _DB_PREFIX_ . 'image.id_image, ' . _DB_PREFIX_ . 'importerone6connect_images.image_uri as io6ImageUri FROM `' . _DB_PREFIX_ . 'image` 
+                                INNER JOIN  `' . _DB_PREFIX_ . 'importerone6connect_images` ON `' . _DB_PREFIX_ . 'image`.id_product = `' . _DB_PREFIX_ . 'importerone6connect_images`.id_product AND `' . _DB_PREFIX_ . 'image`.id_image = `' . _DB_PREFIX_ . 'importerone6connect_images`.id_image
+                                WHERE `' . _DB_PREFIX_ . 'image`.id_product = ' . (int)$ps_product->id;
+                            $checkGallery = DB::getInstance()->executeS($sql);
+    
+                            foreach ($checkGallery as $checkImage) {
+                                $foundImage = !empty($checkImage['io6ImageUri']);
+    
+                                $foundImage &= !empty(array_filter(
+                                    $io6product->images,
+                                    function ($image) use ($checkImage) {
+                                        return $checkImage['io6ImageUri'] == $image->imageUri;
+                                    }
+                                ));
+    
+                                if (!$foundImage && !empty($checkImage['io6ImageUri'])) {
+                                    $idImageToDel = (int)$checkImage['id_image'];
+                                    if ($idImageToDel > 0) {
+                                        $imageToDel = new Image($idImageToDel);
+                                        $imageToDel->delete();
+                                    }
+                                    //Elimino riga da tabella importerone6connect_images
+                                    $res = Db::getInstance()->Execute('DELETE FROM `' . _DB_PREFIX_ . 'importerone6connect_images` 
+                                                                    WHERE  id_product =' . (int)$checkImage['id_product'] . ' AND image_uri=\'' . pSQL($checkImage['io6ImageUri']) . '\';');
                                 }
-                                //Elimino riga da tabella importerone6connect_images
-                                $res = Db::getInstance()->Execute('DELETE FROM `' . _DB_PREFIX_ . 'importerone6connect_images` 
-                                                                WHERE  id_product =' . (int)$checkImage['id_product'] . ' AND image_uri=\'' . pSQL($checkImage['io6ImageUri']) . '\';');
                             }
                         }
+    
+                        //$this->io6_write_log(date('Y-m-d H:i:s') . " product images fine", IO6_LOG_WARNING);
+                        //TODO CT 20210515 Fare controllo che ci sia una immagine con flag Cover=1, altrimenti impostarne una.
                     }
-
-                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product images fine", IO6_LOG_WARNING);
-                    //TODO CT 20210515 Fare controllo che ci sia una immagine con flag Cover=1, altrimenti impostarne una.
-                }
-                //$this->io6_write_log(date('Y-m-d H:i:s') . " product features start", IO6_LOG_WARNING);
-                if ($update_features) {
-                    //     $serialized_attributes = [];
-                    //     $position = 0;
-                    foreach ($io6product->features as $feature) {
-                        if (!$feature->searchable) continue;
-
-                        $attribute_label = preg_replace_callback("/(&#[0-9]+;)/", function ($m) {
-                            return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES");
-                        }, $feature->name);
-                        $attribute_value = preg_replace_callback("/(&#[0-9]+;)/", function ($m) {
-                            return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES");
-                        }, $feature->value);
-                        if (strlen($attribute_value) > 255)
-                            $attribute_value = substr($attribute_value, 0, 255);
-
-                        if (empty($attribute_label) || empty($attribute_value) || !Validate::isGenericName($attribute_label) || !Validate::isGenericName($attribute_value)) {
-                            //$this->echoDebug("Valori non validi per feature - attribute_label: " . $attribute_label . " - attribute_value: " . $attribute_value, IO_LEVEL_WARNING);
-                            continue;
-                        }
-
-                        $id_feature = Feature::addFeatureImport($attribute_label);
-                        $custom = false; //forzo sempre a false per far abilitare le combo
-                        $id_feature_value = (int)FeatureValue::addFeatureValueImport($id_feature, $attribute_value, $ps_product->id, $default_language, $custom);
-                        $res = Product::addFeatureProductImport($ps_product->id, $id_feature, $id_feature_value);
-                        if (!$res) {
-                            throw new Exception("Caratteristica " . $attribute_label . " non salvata per il prodotto " . $ps_product->id);
-                        }
-
-                        if ($manage_facetedsearch_models && $ps_product->id_category_default) {
-
-                            $defaultCategory = new Category($ps_product->id_category_default);
-
-                            // INIZIO CREAZIONE TEMPLATE PER LE CARATTERISTICHE
-                            require_once('classes/ImporterOneFeature.php');
-                            $filtersData = array();
-                            // Creazione dei dati da inserire nel template
-                            $filtersData['shop_list'] = Shop::getContextListShopID(); // array(Context::getContext()->shop->id);
-                            $filtersData['categories'] = array($ps_product->id_category_default);
-                            $filtersData['layered_selection_feat_' . $id_feature] = array('filter_type' => 0, 'filter_show_limit' => 0);
-
-                            $templateData = [
-                                'name' => pSQL("modello-filtri-cat-" . $ps_product->id_category_default . "-" . $defaultCategory->getName()),
-                                'filters' => $filtersData, // andrà poi serializzato
-                                'n_categories' => (int) count($filtersData['categories'])
-                            ];
-
-                            if (ImporterOneFeature::saveTemplate($templateData, $this)) {
-                                $this->io6_write_log("Il template " . $templateData['name'] . " è stato salvato con successo.", IO6_LOG_INFO);
-                            } else { //TODO CT Non c'è nessun log nel metodo saveTemplate e quindi se ritorna False non si capisce il motivo
-                                $this->io6_write_log("Non è stato possibile salvare il template " . $templateData['name'], IO6_LOG_ERROR);
+                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product features start", IO6_LOG_WARNING);
+                    if ($update_features) {
+                        //     $serialized_attributes = [];
+                        //     $position = 0;
+                        foreach ($io6product->features as $feature) {
+                            if (!$feature->searchable) continue;
+    
+                            $attribute_label = preg_replace_callback("/(&#[0-9]+;)/", function ($m) {
+                                return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES");
+                            }, $feature->name);
+                            $attribute_value = preg_replace_callback("/(&#[0-9]+;)/", function ($m) {
+                                return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES");
+                            }, $feature->value);
+                            if (strlen($attribute_value) > 255)
+                                $attribute_value = substr($attribute_value, 0, 255);
+    
+                            if (empty($attribute_label) || empty($attribute_value) || !Validate::isGenericName($attribute_label) || !Validate::isGenericName($attribute_value)) {
+                                //$this->echoDebug("Valori non validi per feature - attribute_label: " . $attribute_label . " - attribute_value: " . $attribute_value, IO_LEVEL_WARNING);
+                                continue;
+                            }
+    
+                            $id_feature = Feature::addFeatureImport($attribute_label);
+                            $custom = false; //forzo sempre a false per far abilitare le combo
+                            $id_feature_value = (int)FeatureValue::addFeatureValueImport($id_feature, $attribute_value, $ps_product->id, $default_language, $custom);
+                            $res = Product::addFeatureProductImport($ps_product->id, $id_feature, $id_feature_value);
+                            if (!$res) {
+                                throw new Exception("Caratteristica " . $attribute_label . " non salvata per il prodotto " . $ps_product->id);
+                            }
+    
+                            if ($manage_facetedsearch_models && $ps_product->id_category_default) {
+    
+                                $defaultCategory = new Category($ps_product->id_category_default);
+    
+                                // INIZIO CREAZIONE TEMPLATE PER LE CARATTERISTICHE
+                                require_once('classes/ImporterOneFeature.php');
+                                $filtersData = array();
+                                // Creazione dei dati da inserire nel template
+                                $filtersData['shop_list'] = Shop::getContextListShopID(); // array(Context::getContext()->shop->id);
+                                $filtersData['categories'] = array($ps_product->id_category_default);
+                                $filtersData['layered_selection_feat_' . $id_feature] = array('filter_type' => 0, 'filter_show_limit' => 0);
+    
+                                $templateData = [
+                                    'name' => pSQL("modello-filtri-cat-" . $ps_product->id_category_default . "-" . $defaultCategory->getName()),
+                                    'filters' => $filtersData, // andrà poi serializzato
+                                    'n_categories' => (int) count($filtersData['categories'])
+                                ];
+    
+                                if (ImporterOneFeature::saveTemplate($templateData, $this)) {
+                                    $this->io6_write_log("Il template " . $templateData['name'] . " è stato salvato con successo.", IO6_LOG_INFO);
+                                } else { //TODO CT Non c'è nessun log nel metodo saveTemplate e quindi se ritorna False non si capisce il motivo
+                                    $this->io6_write_log("Non è stato possibile salvare il template " . $templateData['name'], IO6_LOG_ERROR);
+                                }
+                                // FINE CREAZIONE TEMPLATE PER LE CARATTERISTICHE
                             }
-                            // FINE CREAZIONE TEMPLATE PER LE CARATTERISTICHE
                         }
                     }
-                }
-               //$this->io6_write_log(date('Y-m-d H:i:s') . " product features fine", IO6_LOG_WARNING);
-
-                $retProduct['activeState'] = $activeState;
-                $retProduct['status'] = 'OK';
-                $retProduct['status_message'] = "Ok";
-                $sync_status = 1;
-                $sync_message = $retProduct['status_message'];
-
-                if (isset($ps_product->id) && $ps_product->id > 0) {
-                    $retProduct['ps_product_id'] = $ps_product->id;
-
-                    //TODO CT 20210510 Il salvataggio del prodotto scatena anche l'hook che già fa la insert, quindi si potrebbe pensare di fare solo l'update o cercare di non far eseguire quell'hook
-                    $sql = 'INSERT INTO `' . _DB_PREFIX_ . 'importerone6connect_products` 
-                    (`id_product`, `io6_id_product`, `sync_status`, `sync_message`, `sync_exclude`, `sync_date`, `manage_title`, `manage_shortdescription`, `manage_description`,
-                    `manage_categories`, `manage_prices`, `manage_stock`, `manage_images`, `manage_features`, `manage_dimensions`, `manage_weight`, `manage_htmlfeatures`, `manage_tax_rule`, `htmlfeatures`, `official_price`)
-                    VALUES (
-                        ' . (int)$ps_product->id . ',
-                        ' . (int)$io6product->id . ',
-                        ' . (int)$sync_status . ',
-                        \'' . pSQL($sync_message) . '\',
-                        0,
-                        ' . date('YmdHis') . ',
-                        2,2,2,2,2,2,2,2,2,2,2,2,
-                        \'' . pSQL(htmlentities($htmlfeatures)) . '\',
-                        ' . floatval($official_price) . '
-                    ) ON DUPLICATE KEY UPDATE 
-                        `io6_id_product` = ' . (int)$io6product->id . ',
-                        `sync_status` = ' . (int)$sync_status . ',
-                        `sync_message` = \'' . pSQL($sync_message) . '\',
-                        `sync_date` = ' . date('YmdHis') . ',
-                        `official_price` = ' . floatval($official_price) . '
-                        ' . ($update_features_html ? ', `htmlfeatures` = \'' . pSQL(htmlentities($htmlfeatures)) . '\' ' : ';');
-                    //$this->io6_write_log($sql, IO6_LOG_INFO);
-                    if (!Db::getInstance()->execute($sql)) {
-                        $this->context->controller->errors[] = Tools::displayError('Error: ') . Db::getInstance()->getNumberError() . Db::getInstance()->getMsgError();
+                    //$this->io6_write_log(date('Y-m-d H:i:s') . " product features fine", IO6_LOG_WARNING);
+    
+                    $retProduct['activeState'] = $activeState;
+                    $retProduct['status'] = 'OK';
+                    $retProduct['status_message'] = "Ok";
+                    $sync_status = 1;
+                    $sync_message = $retProduct['status_message'];
+    
+                    if (isset($ps_product->id) && $ps_product->id > 0) {
+                        $retProduct['ps_product_id'] = $ps_product->id;
+    
+                        //TODO CT 20210510 Il salvataggio del prodotto scatena anche l'hook che già fa la insert, quindi si potrebbe pensare di fare solo l'update o cercare di non far eseguire quell'hook
+                        $sql = 'INSERT INTO `' . _DB_PREFIX_ . 'importerone6connect_products` 
+                        (`id_product`, `catalog_id`, `io6_id_product`, `sync_status`, `sync_message`, `sync_exclude`, `sync_date`, `manage_title`, `manage_shortdescription`, `manage_description`,
+                        `manage_categories`, `manage_prices`, `manage_stock`, `manage_images`, `manage_features`, `manage_dimensions`, `manage_weight`, `manage_htmlfeatures`, `manage_tax_rule`, `htmlfeatures`, `official_price`)
+                        VALUES (
+                            ' . (int)$ps_product->id . ',
+                            ' . (int)$catalogId . ',
+                            ' . (int)$io6product->id . ',
+                            ' . (int)$sync_status . ',
+                            \'' . pSQL($sync_message) . '\',
+                            0,
+                            ' . date('YmdHis') . ',
+                            2,2,2,2,2,2,2,2,2,2,2,2,
+                            \'' . pSQL(htmlentities($htmlfeatures)) . '\',
+                            ' . floatval($official_price) . '
+                        ) ON DUPLICATE KEY UPDATE 
+                            `catalog_id` = '. (int)$catalogId.',
+                            `io6_id_product` = ' . (int)$io6product->id . ',
+                            `sync_status` = ' . (int)$sync_status . ',
+                            `sync_message` = \'' . pSQL($sync_message) . '\',
+                            `sync_date` = ' . date('YmdHis') . ',
+                            `official_price` = ' . floatval($official_price) . '
+                            ' . ($update_features_html ? ', `htmlfeatures` = \'' . pSQL(htmlentities($htmlfeatures)) . '\' ' : ';');
+                        //$this->io6_write_log($sql, IO6_LOG_INFO);
+                        if (!Db::getInstance()->execute($sql)) {
+                            $this->io6_write_log($sql, IO6_LOG_INFO);
+                            $this->io6_write_log("Errore salvataggio tabella appoggio", IO6_LOG_INFO);
+                            $this->context->controller->errors[] = Tools::displayError('Error: ') . Db::getInstance()->getNumberError() . Db::getInstance()->getMsgError();
+                        }
+                        //Riga commentata perchè non necessario salvare in cache il prodotto appena importato
+                        //Durante l'attuale sincro potrà essere importato 1 volta sola
+                        //$_SESSION['products_cache'][$io6product->id] = $ps_product->id;
                     }
-                    $this->ps_products_cache[$io6product->id] = $ps_product->id;
+
+                    Hook::exec('actionIO6ProductSaveAfter', ['io6_product' => &$io6product, 'ps_product' => &$ps_product]);
                 }
             } catch (Exception $e) {
                 $retProduct['status'] = 'KO';
@@ -1484,6 +1601,9 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             array_push($syncResults['products'], $retProduct);
             //$this->io6_write_log(date('Y-m-d H:i:s') . " product fine", IO6_LOG_WARNING); //TODO CT 20210511 Se gli passo $e va in errore di memory limit
         }
+        
+
+        
 
         //$this->io6_write_log("clean positions inizio", IO6_LOG_WARNING); //TODO CT 20210511 Se gli passo $e va in errore di memory limit
         if(!empty($categories_to_clean)){
@@ -1496,17 +1616,23 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         //$this->io6_write_log("clean positions fine", IO6_LOG_WARNING); //TODO CT 20210511 Se gli passo $e va in errore di memory limit
 
         //resetCatalog e Rebuild indici se arrivati all'ultima pagina
-        if ($currentPage == $io6_results['pages'] && empty($io6_id_product_syngle_sync)) {
+        if ($currentPage == $io6_results['pages']  && empty($io6_id_product_syngle_sync)) {
+            $_SESSION['categories_cache'] = [];
+			$_SESSION['brands_cache'] = [];
+			$_SESSION['suppliers_cache'] = [];
+			$_SESSION['products_cache'] = [];
+            
             //Resettare solo i prodotti gestiti da ImporterONE, ovvero presenti in importerone6connect_products e con flag sync_exclude <> 1    
             Db::getInstance()->Execute('UPDATE `' . _DB_PREFIX_ . 'product` product
 									INNER JOIN `' . _DB_PREFIX_ . 'importerone6connect_products` ioprod ON product.id_product = ioprod.id_product
 									SET product.`active` = 0 
-									WHERE product.`active` = 1 and ioprod.`sync_exclude` = 0 AND ioprod.io6_id_product > 0 AND IFNULL(ioprod.sync_status, 0) <> 1;');
+									WHERE product.`active` = 1 and ioprod.`sync_exclude` = 0 AND ioprod.io6_id_product > 0 AND IFNULL(ioprod.sync_status, 0) <> 1
+                                    AND ioprod.catalog_id = '.(int)$catalogId.';');
             Db::getInstance()->Execute('UPDATE `' . _DB_PREFIX_ . 'stock_available` sa
-                                    INNER JOIN `' . _DB_PREFIX_ . 'product` p ON p.id_product = sa.id_product 
+                                    INNER JOIN `' . _DB_PREFIX_ . 'product` p ON p.id_product = sa.id_product
 									INNER JOIN `' . _DB_PREFIX_ . 'importerone6connect_products` ioprod ON p.id_product = ioprod.id_product
-									SET sa.`quantity` = 0 
-									WHERE p.`active` = 0 and ioprod.`sync_exclude` = 0 AND ioprod.io6_id_product > 0;');
+									SET sa.`quantity` = 0
+									WHERE p.`active` = 0 and ioprod.`sync_exclude` = 0 AND ioprod.io6_id_product > 0 AND sa.quantity > 0;');
             Db::getInstance()->Execute('UPDATE `' . _DB_PREFIX_ . 'product_shop` p_shop
 										INNER JOIN `' . _DB_PREFIX_ . 'product` p ON p_shop.id_product = p.id_product
 										SET p_shop.active = p.active 
@@ -1528,11 +1654,11 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
             curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
             $image_data = curl_exec($ch);
-            
+
             if (!empty($image_data))
                 return $image_data;
-        } 
-        
+        }
+
         if (!function_exists('curl_version')){
             $image_data = @file_get_contents($image_uri);
             if (!empty($image_data))
@@ -1605,50 +1731,52 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         if ($checkApiSettings) {
 
             $io6Catalogs = $io6Engine->GetIO6Catalogs();
-
-            $io6CatalogsMatchingSelected = array_filter(
-                $io6Catalogs,
-                function ($e) use ($io6_configuration) {
-                    return $e->id == $io6_configuration->catalogId;
+            $hasCatalogSelected = false;
+            $hasPriceSelected = false;
+            foreach ($io6Catalogs as $catalogId => $catalog) {
+                if (isset($io6_configuration->catalogsData[$catalogId]) && !empty($io6_configuration->catalogsData[$catalogId])){
+                    $catalog->selected = true;
+                    $hasCatalogSelected = true;
                 }
-            );
-
-            if (count($io6Catalogs) > 0 && empty($io6_configuration->catalogId) || count($io6CatalogsMatchingSelected) == 0)
-                array_unshift($io6Catalogs, array('id' => '0', 'name' => 'Selezionare un catalogo'));
-            if (count($io6Catalogs) == 0)
-                $io6Catalogs = array(array('id' => '0', 'name' => 'Nessun Catalogo disponibile'));
 
-            $io6Pricelists = [];
-            if ($io6_configuration->catalogId > 0 && count($io6CatalogsMatchingSelected) > 0) {
-                $io6Pricelists = $io6Engine->GetIO6PriceLists();
+                $catalog->priceLists = $io6Engine->GetIO6PriceLists($catalog->id);
 
-                $io6PricelistsMatchingSelected = array_filter(
-                    $io6Pricelists,
-                    function ($e) use ($io6_configuration) {
-                        return $e->id == $io6_configuration->priceListId;
+                foreach($catalog->priceLists as $priceList){
+                    if ($priceList->id == $io6_configuration->catalogsData[$catalogId]['price_list_id']){
+                        $priceList->selected = true;
+                        $hasPriceSelected = true;
                     }
-                );
-                if (empty($io6_configuration->priceListId) || count($io6PricelistsMatchingSelected) == 0)
-                    array_unshift($io6Pricelists, array('id' => '0', 'name' => 'Selezionare un listino'));
-                if (count($io6Pricelists) == 0)
-                    $io6Pricelists = array(array('id' => '0', 'name' => 'Nessun listino disponibile'));
-            }
-
+                }
 
+                if (!isset($catalog->priceLists) || count($catalog->priceLists) == 0){
+                    $catalog->priceLists = array(new Io6PriceList(['id' => '0', 'name' => 'Nessun listino disponibile']));
+                } else {
+                    array_unshift($catalog->priceLists, new Io6PriceList(['id' => '0', 'name' => 'Selezionare un listino']));
+                }
+            }
 
-            /*$io6Catalogs = array( //Per test
-                                array('id' => '1', 'name' => 'Catalogo 1'),
-                                array('id' => '2', 'name' => 'Catalogo 2')
-            );
-            $io6Pricelists = array(//Per test
-                array('id' => '1', 'name' => 'Listino 1'),
-                array('id' => '2', 'name' => 'Listino 2'),
-                array('id' => '3', 'name' => 'Listino 3')
-            );*/
+            $productInDisabledCatalog = [];
+            $hasProductInDisabledCatalog = false;
+            if(isset($io6_configuration->catalogsData) && !empty($io6_configuration->catalogsData)){
+                //Check for products not in catalogs from ImporterONE
+                $sql = "SELECT ip.catalog_id, COUNT(p.id_product) as products_count FROM ". _DB_PREFIX_ ."importerone6connect_products ip 
+                LEFT JOIN ". _DB_PREFIX_ ."product p ON p.id_product = ip.id_product
+                WHERE p.active = 1 AND ip.catalog_id NOT IN (".implode(',', array_keys($io6_configuration->catalogsData)).") AND ip.catalog_id != 0
+                GROUP BY ip.catalog_id";
+                $productsNotInEnabledCatalogs = Db::getInstance()->executeS($sql);
+
+                foreach ($productsNotInEnabledCatalogs as $product) {
+                    if(!$hasProductInDisabledCatalog)
+                        $hasProductInDisabledCatalog = true;
+
+                    $productInDisabledCatalog[$product['catalog_id']]['catalog_name'] = isset($io6Catalogs[$product['catalog_id']]) ? $io6Catalogs[$product['catalog_id']]->name : '';
+                    $productInDisabledCatalog[$product['catalog_id']]['products_count'] = $product['products_count'];
+                }
+            }
 
-            $output .= $this->renderFormGeneralSettings($io6Catalogs, $io6Pricelists);
+            $output .= $this->renderFormGeneralSettings($io6Catalogs, $productInDisabledCatalog);
 
-            if (!empty(Configuration::get('IMPORTERONE6CONNECT_CATALOG')) && count($io6CatalogsMatchingSelected) > 0 && count($io6PricelistsMatchingSelected) > 0) {
+            if (!empty(Configuration::get('IMPORTERONE6CONNECT_CATALOGS')) && $hasCatalogSelected && $hasPriceSelected) {
 
                 $output .= $this->renderFormProductsSettings();
 
@@ -1656,6 +1784,8 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
 
                 $output .= $this->renderFormExecute();
 
+                $output .= $this->renderFormCron();
+
                 $output .= $this->renderFormStatistiche();
             }
         }
@@ -1808,31 +1938,21 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
 
     /* <-- Form di Api Settings Fine  */
 
-
-    /* Form di General Settings Inizio --> */
-    protected function renderFormGeneralSettings(array $io6Catalogs = [], array $io6Pricelists = [])
-    {
-        $helper = new HelperForm();
-
-        $helper->show_toolbar = false;
-        $helper->table = $this->table;
-        $helper->module = $this;
-        $helper->default_form_language = $this->context->language->id;
-        $helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG', 0);
-
-        $helper->identifier = $this->identifier;
-        $helper->submit_action = 'submitImporterone6connectModule_GeneralSettings';
-        $helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false)
-            . '&configure=' . $this->name . '&tab_module=' . $this->tab . '&module_name=' . $this->name;
-        $helper->token = Tools::getAdminTokenLite('AdminModules');
-
-        $helper->tpl_vars = array(
-            'fields_value' => $this->getConfigFormValuesGeneralSettings(), /* Add values for your inputs */
-            'languages' => $this->context->controller->getLanguages(),
-            'id_language' => $this->context->language->id,
+    protected function renderFormGeneralSettings(array $io6Catalogs = [], array $productInDisabledCatalog = []){
+        //$executeUrl = Context::getContext()->link->getModuleLink($this->name, 'actions', array('action' => 'expandStatisticInfo'));
+        $exportCategoriesUrl = $this->context->link->getModuleLink($this->name, 'actions', ['action' => 'exportCategoriesTree']);
+        
+        $this->context->smarty->assign(
+            array(
+                'moduleName' => $this->name,
+                'io6Catalogs' => $io6Catalogs,
+                'productsInDisabledCatalogs' => $productInDisabledCatalog,
+                'exportCategoriesUrl' => $exportCategoriesUrl
+            )
         );
 
-        return $helper->generateForm(array($this->getConfigFormGeneralSettings($io6Catalogs, $io6Pricelists)));
+        $output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/configure_general.tpl');
+        return $output;
     }
 
     /**
@@ -1858,7 +1978,18 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                             'name' => 'name'
                         ),
                     ),
-
+                    array(
+                        'type' => 'select',
+                        'multiple' => true,
+                        'label' => $this->l('Cataloghi'),
+                        'name' => 'IMPORTERONE6CONNECT_CATALOGS',
+                        'desc' => $this->l('Seleziona i Cataloghi ImporeterONE da cui importare i prodotti'),
+                        'options' => array(
+                            'query' => $io6Catalogs,
+                            'id' => 'id',
+                            'name' => 'name'
+                        ),
+                    ),
                 ),
                 'submit' => array(
                     'title' => $this->l('Save'),
@@ -1901,10 +2032,17 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
     {
         $output = "";
         $result = true;
-        $form_values = $this->getConfigFormValuesGeneralSettings();
 
-        foreach (array_keys($form_values) as $key) {
-            $result &= Configuration::updateValue($key, Tools::getValue($key));
+        $catalogSaved = [];
+        if (!empty(Tools::getValue("IMPORTERONE6CONNECT_CATALOGS"))){
+            $catalogs = Tools::getValue("IMPORTERONE6CONNECT_CATALOGS");
+
+            foreach ($catalogs as $key => $value) {
+                if (!empty($value['price_list_id']))
+                    $catalogSaved[$key] = ["catalog_id" => $key, "catalog_name" => $value['catalog_name'] ,"price_list_id" => (int)$value['price_list_id']];
+            }
+
+            $result &= Configuration::updateValue("IMPORTERONE6CONNECT_CATALOGS", serialize($catalogSaved));
         }
 
         if ($result)
@@ -1939,6 +2077,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             'id_language' => $this->context->language->id,
         );
 
+
         return $helper->generateForm(array($this->getConfigFormProductsSettings()));
     }
 
@@ -1972,6 +2111,25 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                             'name' => 'name'
                         ),
                     ),
+                    array(
+                        'type' => 'switch',
+                        'label' => $this->l('Utilizza i fornitori come filtro per la ricerca'),
+                        'name' => 'IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS',
+                        'is_bool' => true,
+                        'desc' => $this->l('Verranno presi in considerazione solo i prodotti associati con fornitori ImporterONE.'),
+                        'values' => array(
+                            array(
+                                'id' => 'manage_io6_suppliers',
+                                'value' => true,
+                                'label' => $this->l('Enabled')
+                            ),
+                            array(
+                                'id' => 'manage_io6_suppliers',
+                                'value' => false,
+                                'label' => $this->l('Disabled')
+                            )
+                        ),
+                    ),
                     array(
                         'type' => 'switch',
                         'label' => $this->l('Aggiorna i titoli'),
@@ -2337,6 +2495,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             'IMPORTERONE6CONNECT_MANAGE_FACETEDSEARCH_MODELS' => Configuration::get('IMPORTERONE6CONNECT_MANAGE_FACETEDSEARCH_MODELS'),
             'IMPORTERONE6CONNECT_MANAGE_TAX_RULE_DEFAULT' => Configuration::get('IMPORTERONE6CONNECT_MANAGE_TAX_RULE_DEFAULT'),
             'IMPORTERONE6CONNECT_TAX_RULE_DEFAULT' => Configuration::get('IMPORTERONE6CONNECT_TAX_RULE_DEFAULT'),
+            'IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS' => Configuration::get('IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS'),
         );
     }
 
@@ -2389,6 +2548,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
             'languages' => $this->context->controller->getLanguages(),
             'id_language' => $this->context->language->id,
         );
+        
 
         return $helper->generateForm(array($this->getConfigFormImportSettings()));
     }
@@ -2614,30 +2774,43 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
      */
     protected function renderFormExecute()
     {
-        $executeUrl = Context::getContext()->link->getModuleLink($this->name, 'actions', array('action' => 'executeSync')); //, 'token' => Tools::getToken(false)
-        $cronCommand = "php " . dirname(__FILE__) . '/cron.php "' . $executeUrl . '"';
-        $cronCommandFast = "php " . dirname(__FILE__) . '/cron.php "' . $executeUrl . '&fast=1"';
 
-        $cronCommandWarning = $cronCommand . '&accettoAvvisoRequisiti=1"';
-        $cronCommandFastWarning = $cronCommandFast . '&accettoAvvisoRequisiti=1"';
+        $server_requirements = $this->checkServerRequirements();
 
-        $cronCommandDownloadImages = 'curl -s "'.Context::getContext()->link->getModuleLink($this->name, 'downloadImages', array('limit' => '10000')).'"';
+        $lastProductSyncDate = '';
+        $sql = "SELECT COUNT(iop.id_product) FROM ". _DB_PREFIX_ ."importerone6connect_products iop
+        INNER JOIN ". _DB_PREFIX_ ."product p ON p.id_product = iop.id_product
+        WHERE iop.sync_status = 0 AND iop.sync_exclude = 0 AND p.active = 1";
+        $product_not_synced = Db::getInstance()->getValue($sql);
 
-        $server_requirements = $this->checkServerRequirements();
+        if($product_not_synced > 0){
+            $sql = "SELECT MAX(iop.sync_date) FROM ". _DB_PREFIX_ ."importerone6connect_products iop";
+            $lastProductSyncDate = Db::getInstance()->getValue($sql);
+        }
+
+        $sql = "SELECT COUNT(p.id_product) FROM ". _DB_PREFIX_ ."product p
+        LEFT JOIN ". _DB_PREFIX_ ."importerone6connect_products ip ON ip.id_product = p.id_product
+        WHERE ip.id_product IS NULL";
+        $productNotInIo6Tables = Db::getInstance()->getValue($sql);
 
         if (Tools::getValue('execute') == '1') {
             $this->io6Sync();
         }
 
+        //Funzionalità per convertire la data alla timezone del client
+        if (!empty($lastProductSyncDate)){
+            $lastProductSyncDate = $this->convertDateToCurrentTimezone($lastProductSyncDate);
+        }
+
+        $executeUrl = Context::getContext()->link->getModuleLink($this->name, 'actions', array('action' => 'executeSync')); //, 'token' => Tools::getToken(false)
+
         $this->context->smarty->assign(
             array(
+                'syncResume' => $product_not_synced > 0 ? true : false,
+                'lastProductSyncDate' => $lastProductSyncDate,
+                'productNotInIo6Tables' => $productNotInIo6Tables,
                 'executePageSize' => Configuration::get("IMPORTERONE6CONNECT_PAGESIZE"),
                 'executeUrl' => $executeUrl,
-                'cronCommand' => $cronCommand,
-                'cronCommandFast' => $cronCommandFast,
-                'cronCommandWarning' => $cronCommandWarning,
-                'cronCommandFastWarning' => $cronCommandFastWarning,
-                'cronCommandDownloadImages' => $cronCommandDownloadImages,
                 'serverRequirements' => $server_requirements,
                 //'cronUrl' => Tools::getHttpHost(true). "/modules/icecool/cron.php?icecoolCron=1" //"?token=".Tools::hash("icecool/cron")
                 //'cronUrl' => _PS_BASE_URL_ . "/modules/icecool/cron.php?icecoolCron=1" //"?token=".Tools::hash("icecool/cron")
@@ -2648,6 +2821,50 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         return $output;
     }
 
+    function convertDateToCurrentTimezone($lastProductSyncDate){
+        $oldTimezone = date_default_timezone_get();
+        $newTimezone = new DateTimeZone("Europe/Rome");
+        $dateToConvert = date_create($lastProductSyncDate, new DateTimeZone($oldTimezone));
+        $dateToConvert->setTimezone($newTimezone);
+    
+        return $dateToConvert->format('d/m/Y H:i:s');
+    }
+
+    /**
+     * Form Execute and Cron
+     */
+    protected function renderFormCron()
+    {
+        $io6_catalogs = unserialize(Configuration::get('IMPORTERONE6CONNECT_CATALOGS'));   
+
+        $cronCommands = [];
+        $cronCommandsFast = [];
+        $cronCommandsWarning = [];
+        $cronCommandsFastWarning = [];
+        foreach ($io6_catalogs as $key => $catalog) {
+            $executeUrl = Context::getContext()->link->getModuleLink($this->name, 'actions', array('action' => 'executeSync', "catalogId" => $catalog['catalog_id'])); //, 'token' => Tools::getToken(false)
+            $cronCommands[$catalog['catalog_name']] = "php " . dirname(__FILE__) . '/cron.php "' . $executeUrl . '"';
+            $cronCommandsFast[$catalog['catalog_name']] = "php " . dirname(__FILE__) . '/cron.php "' . $executeUrl . '&fast=1"';
+            $cronCommandsWarning[$catalog['catalog_name']] = "php " . dirname(__FILE__) . '/cron.php "' . $executeUrl . '&accettoAvvisoRequisiti=1"';
+            $cronCommandsFastWarning[$catalog['catalog_name']] = "php " . dirname(__FILE__) . '/cron.php "' . $executeUrl . '&fast=1&accettoAvvisoRequisiti=1"';
+        }
+
+        $cronCommandDownloadImages = 'curl -s "'.Context::getContext()->link->getModuleLink($this->name, 'downloadImages', array('limit' => '10000')).'"';
+    
+        $this->context->smarty->assign(
+            array(
+                'cronCommands' => $cronCommands,
+                'cronCommandsFast' => $cronCommandsFast,
+                'cronCommandsWarning' => $cronCommandsWarning,
+                'cronCommandsFastWarning' => $cronCommandsFastWarning,
+                'cronCommandDownloadImages' => $cronCommandDownloadImages,
+            )
+        );
+
+        $output = $this->context->smarty->fetch($this->local_path . 'views/templates/admin/cron_section.tpl');
+        return $output;
+    }
+
     /**
      * Form Execute and Cron
      */
@@ -2734,6 +2951,7 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
                 $this->context->smarty->assign(
                     array(
                         'importerone6connect_io6_id_product' => $results[0]['io6_id_product'],
+                        'importerone6connect_catalog_id' => $results[0]['catalog_id'],
                         'importerone6connect_sync_exclude' => $results[0]['sync_exclude'],
                         'importerone6connect_sync_status' => $results[0]['sync_status'],
                         'importerone6connect_sync_message' => $results[0]['sync_message'],
@@ -3060,12 +3278,23 @@ class Ps_Connect_Io6 extends Module  implements WidgetInterface
         }
     }
 
+    function formatByte($size)
+	{
+		$unit = array('b', 'KB', 'MB', 'GB', 'TB', 'PB');
+		$ram = number_format(@round($size / pow(1024, ($i = floor(log($size, 1024)))), 2),2);
+		return $ram . ' ' . $unit[$i];
+	}
+
     public function io6_write_log($log, $level)
     {
         $logFile = IO6_LOG_DIRPATH . date('Ymd') . ".txt";
         $time = date('Y-m-d H:i:s');
-        $logMessage = sprintf("%s - %s: %s\r\n", $time, $level, (is_array($log) || is_object($log) ? print_r($log, true) : $log));
+        $ram = $this->formatByte(memory_get_peak_usage()) . " - " . $this->formatByte(memory_get_usage());
+
+        $logMessage = sprintf("ram: %s - %s - %s: %s\r\n", $ram, $time, $level, (is_array($log) || is_object($log) ? print_r($log, true) : $log));
 
         error_log($logMessage, 3, $logFile);
     }
+
+    
 }
diff --git a/sql/install.php b/sql/install.php
index 76481f4587044bf2fd91b0fe50cd090979c6b582..30aa72ec33b45c926be413ab703a448abb379f15 100644
--- a/sql/install.php
+++ b/sql/install.php
@@ -27,6 +27,7 @@ $sql = array();
 
 $sql[] = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'importerone6connect_products` (
     `id_product` int UNSIGNED NOT NULL,
+    `catalog_id` int unsigned DEFAULT \'0\',
     `io6_id_product` int UNSIGNED NULL,
     `sync_status` int DEFAULT NULL,
     `sync_message` text,
diff --git a/src/Form/Modifier/ProductFormModifier.php b/src/Form/Modifier/ProductFormModifier.php
old mode 100644
new mode 100755
index fa0ee9d498c2fb914e1c3799e12eadf13e798daa..0b772b9e358eccf09438ca4e8e417b3dff53099b
--- a/src/Form/Modifier/ProductFormModifier.php
+++ b/src/Form/Modifier/ProductFormModifier.php
@@ -86,7 +86,7 @@ final class ProductFormModifier
         );
 
         if (!empty($io6_data['io6_id_product'])){
-            $single_sync_url = Context::getContext()->link->getAdminLink('AdminPsConnectIo6ActionsController', true, array('route' => 'admin_io6_productsync', 'io6_id_product' => $io6_data['io6_id_product'], 'new_product_page' => true));
+            $single_sync_url = Context::getContext()->link->getAdminLink('AdminPsConnectIo6ActionsController', true, array('route' => 'admin_io6_productsync', 'io6_id_product' => $io6_data['io6_id_product'], 'catalogId' => $io6_data['catalog_id'], 'new_product_page' => true));
             $this->formBuilderModifier->addAfter(
             $descriptionTabFormBuilder, // the tab
             'importerone_info', // the input/form from which to insert after/before
diff --git a/upgrade/upgrade-2.0.0.php b/upgrade/upgrade-2.0.0.php
new file mode 100644
index 0000000000000000000000000000000000000000..05833734ed5516dbdad0614215b2ecd07e0fc02d
--- /dev/null
+++ b/upgrade/upgrade-2.0.0.php
@@ -0,0 +1,55 @@
+<?php
+/**
+* 2007-2020 PrestaShop
+*
+* NOTICE OF LICENSE
+*
+* This source file is subject to the Academic Free License (AFL 3.0)
+* that is bundled with this package in the file LICENSE.txt.
+* It is also available through the world-wide-web at this URL:
+* http://opensource.org/licenses/afl-3.0.php
+* If you did not receive a copy of the license and are unable to
+* obtain it through the world-wide-web, please send an email
+* to license@prestashop.com so we can send you a copy immediately.
+*
+* DISCLAIMER
+*
+* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+* versions in the future. If you wish to customize PrestaShop for your
+* needs please refer to http://www.prestashop.com for more information.
+*
+*  @author    PrestaShop SA <contact@prestashop.com>
+*  @copyright 2007-2020 PrestaShop SA
+*  @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+*  International Registered Trademark & Property of PrestaShop SA
+*/
+if (!defined('_PS_VERSION_')) {
+    exit;
+}
+
+function upgrade_module_2_0_0($module)
+{
+    $result = true;
+
+    if (!Configuration::hasKey('IMPORTERONE6CONNECT_CATALOGS'))
+        $result &= Configuration::updateValue('IMPORTERONE6CONNECT_CATALOGS', serialize([]));
+    if (!Configuration::hasKey('IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS'))
+        $result &= Configuration::updateValue('IMPORTERONE6CONNECT_MANAGE_IO6_SUPPLIERS', 1);
+
+    $sql = "ALTER TABLE "._DB_PREFIX_."importerone6connect_products ADD COLUMN catalog_id int UNSIGNED DEFAULT 0 AFTER id_product";
+    $result &= Db::getInstance()->execute($sql);
+    
+    $result &= $module->registerHook('actionIO6ProductSaveBefore');
+    $result &= $module->registerHook('actionIO6ProductSaveAfter');
+    $result &= $module->registerHook('actionIO6CategorySaveBefore');
+    $result &= $module->registerHook('actionIO6CategorySaveAfter');
+    $result &= $module->registerHook('actionIO6BrandSaveBefore');
+    $result &= $module->registerHook('actionIO6BrandSaveAfter');
+    $result &= $module->registerHook('actionIO6SupplierSaveBefore');
+    $result &= $module->registerHook('actionIO6SupplierSaveAfter');
+
+    $result &= $module->uninstallOverrides();
+    $result &= $module->installOverrides();
+
+    return $result;
+}
diff --git a/vendor/.htaccess b/vendor/.htaccess
old mode 100644
new mode 100755
index 3de9e4008bd960a5b589911c311332b266288ed9..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
--- a/vendor/.htaccess
+++ b/vendor/.htaccess
@@ -1,10 +0,0 @@
-# Apache 2.2
-<IfModule !mod_authz_core.c>
-    Order deny,allow
-    Deny from all
-</IfModule>
-
-# Apache 2.4
-<IfModule mod_authz_core.c>
-    Require all denied
-</IfModule>
diff --git a/vendor/autoload.php b/vendor/autoload.php
old mode 100644
new mode 100755
index af4eafedc6c5df3941be227fb7045e251856b799..e373bbeaf5f66149383275d5611eabf020524d3c
--- a/vendor/autoload.php
+++ b/vendor/autoload.php
@@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
 
 require_once __DIR__ . '/composer/autoload_real.php';
 
-return ComposerAutoloaderInita5a6e2bb0a11e75425aaca6316dc467d::getLoader();
+return ComposerAutoloaderInit8bda4515f096db9c6abfe2b891767c21::getLoader();
diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php
old mode 100644
new mode 100755
diff --git a/vendor/composer/LICENSE b/vendor/composer/LICENSE
old mode 100644
new mode 100755
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php
old mode 100644
new mode 100755
diff --git a/vendor/composer/autoload_namespaces.php b/vendor/composer/autoload_namespaces.php
old mode 100644
new mode 100755
diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php
old mode 100644
new mode 100755
diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php
old mode 100644
new mode 100755
index b6a89e526086d7f27120156766c781a62a5eeb1d..a06d87584279c4ce25c9b4714145c95d8f9644a1
--- a/vendor/composer/autoload_real.php
+++ b/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
 
 // autoload_real.php @generated by Composer
 
-class ComposerAutoloaderInita5a6e2bb0a11e75425aaca6316dc467d
+class ComposerAutoloaderInit8bda4515f096db9c6abfe2b891767c21
 {
     private static $loader;
 
@@ -22,12 +22,12 @@ class ComposerAutoloaderInita5a6e2bb0a11e75425aaca6316dc467d
             return self::$loader;
         }
 
-        spl_autoload_register(array('ComposerAutoloaderInita5a6e2bb0a11e75425aaca6316dc467d', 'loadClassLoader'), true, false);
+        spl_autoload_register(array('ComposerAutoloaderInit8bda4515f096db9c6abfe2b891767c21', 'loadClassLoader'), true, false);
         self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
-        spl_autoload_unregister(array('ComposerAutoloaderInita5a6e2bb0a11e75425aaca6316dc467d', 'loadClassLoader'));
+        spl_autoload_unregister(array('ComposerAutoloaderInit8bda4515f096db9c6abfe2b891767c21', 'loadClassLoader'));
 
         require __DIR__ . '/autoload_static.php';
-        call_user_func(\Composer\Autoload\ComposerStaticInita5a6e2bb0a11e75425aaca6316dc467d::getInitializer($loader));
+        call_user_func(\Composer\Autoload\ComposerStaticInit8bda4515f096db9c6abfe2b891767c21::getInitializer($loader));
 
         $loader->register(false);
 
diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php
old mode 100644
new mode 100755
index b9a0ffa45ff3bebddd289c752dfae191bc625a1d..4548c064d53c7a7dc2aa41410cc2cefc3d9743dd
--- a/vendor/composer/autoload_static.php
+++ b/vendor/composer/autoload_static.php
@@ -4,7 +4,7 @@
 
 namespace Composer\Autoload;
 
-class ComposerStaticInita5a6e2bb0a11e75425aaca6316dc467d
+class ComposerStaticInit8bda4515f096db9c6abfe2b891767c21
 {
     public static $prefixLengthsPsr4 = array (
         'I' => 
@@ -32,9 +32,9 @@ class ComposerStaticInita5a6e2bb0a11e75425aaca6316dc467d
     public static function getInitializer(ClassLoader $loader)
     {
         return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInita5a6e2bb0a11e75425aaca6316dc467d::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInita5a6e2bb0a11e75425aaca6316dc467d::$prefixDirsPsr4;
-            $loader->classMap = ComposerStaticInita5a6e2bb0a11e75425aaca6316dc467d::$classMap;
+            $loader->prefixLengthsPsr4 = ComposerStaticInit8bda4515f096db9c6abfe2b891767c21::$prefixLengthsPsr4;
+            $loader->prefixDirsPsr4 = ComposerStaticInit8bda4515f096db9c6abfe2b891767c21::$prefixDirsPsr4;
+            $loader->classMap = ComposerStaticInit8bda4515f096db9c6abfe2b891767c21::$classMap;
 
         }, null, ClassLoader::class);
     }
diff --git a/views/css/back.css b/views/css/back.css
index 909a6ebc3573434b527379032f4e397e7be44d08..30c73178156589f45780fec5c72d73cb17377d05 100755
--- a/views/css/back.css
+++ b/views/css/back.css
@@ -82,3 +82,56 @@ div[id^="io6_info_"]{
 #statistic_info_container{
 	font-size: 14px;
 }
+
+#generalSettingsForm select {
+	max-width: 300px;
+}
+
+#generalSettingsForm h4{
+	font-weight: 700;
+}
+
+div[id^='io6-container-catalog-']{
+	display: flex;
+	align-items: center;
+}
+
+div[id^='io6-container-catalog-'] label{
+	margin: 0px 0px 0px 5px;
+}
+
+div[id^='price-selection-catalog-']{
+	padding: 0px 0px 20px 20px;
+}
+
+div[id^='warnings-catalog-'] li{
+	margin-top: 10px;
+}
+
+div[id^='warnings-catalog-'] .move-products-container{
+	display: flex;
+}
+
+#export-categories-io6 .form-group {
+	padding: 10px;
+}
+
+#generalSettingsForm .catalogs .catalog-data{
+	margin: 0px 10px;
+}
+
+#catalogs-table td {
+	padding: 10px;
+}
+
+#download-not-io6-product{
+	display: flex;
+	align-items: center;
+	float: right;
+}
+
+#download-not-io6-product i{
+	font-size: 1.2rem;
+	margin-right: 5px;
+}
+
diff --git a/views/js/ps_connect_io6.js b/views/js/ps_connect_io6.js
old mode 100644
new mode 100755
index d8d8ed6ab381a96d48216f6d14b8b7f6bc94a6e1..df9630fec53321a03060c0738308890d5d5d1a02
--- a/views/js/ps_connect_io6.js
+++ b/views/js/ps_connect_io6.js
@@ -27,6 +27,17 @@
 */
 
 $(document).ready(function () {
+	if ($("input[id^='io6-catalog-'").length > 0){
+		$("input[id^='io6-catalog-'").each(function(e){
+			var price_select = $(this).prop('id').replace('io6-catalog-', 'io6-price-catalog-');
+			var price_select_container = $(this).prop('id').replace('io6-catalog-', 'price-selection-catalog-');
+			if (!$(this).is(":checked")){
+				$('#'+price_select).prop("disabled", true);
+			}
+		});
+	}
+
+})
 
 	$(document).on('click', '#product_description_importerone_single_sync', async function(e) {
 		e.preventDefault();
@@ -48,10 +59,9 @@ $(document).ready(function () {
 			complete: function() {
 			}
 		});
-    });
+	});
 
-    $("#io6-test-api").unbind();
-	$("#io6-test-api").on('click', async function(e) {
+	$(document).on('click', '#io6-test-api', async function(e) {
 		e.preventDefault();
 		var endPoint = $('#IMPORTERONE6CONNECT_API_ENDPOINT').val();
 		var token = $('#IMPORTERONE6CONNECT_API_TOKEN').val();
@@ -73,11 +83,128 @@ $(document).ready(function () {
 				$('#api-settings_form .form-wrapper').append('<div class="module_confirmation alert alert-' + (data.response.passed ? data.response.iswarning ? 'warning' : 'success' : 'danger') + '"><h4 style="margin-bottom:0;">'+ data.response.message + '</h4></div>');
 			},
 			error: function (error) {
-				console.log("ERROR " + error.toString());		
+				console.log("ERROR " + error.toString());
 			},
 			complete: function() {
 			}
 		});
-    });    
+	});
+
+	$(document).on("change","input[id^='io6-catalog-']", function(e) {
+		var price_select = $(this).prop('id').replace('io6-catalog-', 'io6-price-catalog-');
+		var price_select_container = $(this).prop('id').replace('io6-catalog-', 'price-selection-catalog-');
+		
+		if ($(this).is(":checked")){
+			$("#"+price_select).prop("disabled", false);
+		} else {
+			$("#"+price_select).prop("disabled", true);
+			$("#"+price_select).prop("value", 0);
+		}
+	});
+
+
+	$(document).on("click","div[id^='warnings-catalog-'] .btn-move-products", async function(e) {
+		e.preventDefault();
+
+		$(this).attr('href', $(this).attr('href').concat('&newCatalogId=' + e.target.dataset.newCatalogId));
+
+		await $.ajax({
+			method: "post",
+			async: true,
+			url: $(this).attr('href'),
+			success: function (data) {
+				window.location.href = window.location.href;
+			},
+			error: function (error) {
+				$('#generalSettingsErrorSection').append('<span class="alert alert-danger' + '">'+ error.status + ' ' + error.responseText + '</span>');
+			},
+		});
+		
+			
+	})
+
+	$(document).on("change",".move-products-container select", function(e) {
+		if (e.target.selectedOptions[0].value != 0){
+			$(this).siblings('.btn-move-products')[0].dataset.newCatalogId = e.target.selectedOptions[0].value;
+			$(this).siblings('.btn-move-products')[0].classList.remove('disabled');
+		} else {
+			$(this).siblings('.btn-move-products')[0].classList.add('disabled');
+		}
+	})
+
+	$(document).on("click","div[id^='warnings-catalog-'] .btn-disable-products", async function(e) {
+		e.preventDefault();
+		
+		await $.ajax({
+            method: "post",
+            async: true,
+            url:  $(this).attr('href'),
+            success: function (data) {
+                window.location.href = window.location.href;
+            },
+            error: function (error) {
+				$('#generalSettingsErrorSection').append('<span class="alert alert-danger' + '">'+ error.status + ' ' + error.responseText + '</span>');
+            },
+        });
+			
+	})
+
+	$(document).on("click","#download-not-io6-product", async function(e) {
+		e.preventDefault();
+		
+		await $.ajax({
+            method: "post",
+            async: true,
+            url:  $(this).attr('href'),
+            success: function (data) {
+                var downloadLink = document.createElement("a");
+				downloadLink.download = "product_not_in_io6_tables.csv";
+                var fileData = ['\ufeff'+data];
+                var blobObject = new Blob(fileData,{
+                    type: "text/csv;charset=utf-8;"
+                });
+
+                var url = URL.createObjectURL(blobObject);
+                downloadLink.href = url;
+
+                document.body.appendChild(downloadLink);
+                downloadLink.click();
+                document.body.removeChild(downloadLink);
+            },
+            error: function (error) {
+				$('#generalSettingsErrorSection').append('<span class="alert alert-danger' + '">'+ error.status + ' ' + error.responseText + '</span>');
+            },
+        });
+			
+	})
+
+	$(document).on("click","#io6-export-categories", async function(e) {
+		e.preventDefault();
+		
+		await $.ajax({
+            method: "post",
+            async: true,
+            url:  $(this).attr('href'),
+            success: function (data) {
+                var downloadLink = document.createElement("a");
+				downloadLink.download = "prestashop_categories_tree.csv";
+                var fileData = ['\ufeff'+data];
+                var blobObject = new Blob(fileData,{
+                    type: "text/csv;charset=utf-8;"
+                });
+
+                var url = URL.createObjectURL(blobObject);
+                downloadLink.href = url;
+
+                document.body.appendChild(downloadLink);
+                downloadLink.click();
+                document.body.removeChild(downloadLink);
+            },
+            error: function (error) {
+				$('#generalSettingsErrorSection').append('<span class="alert alert-danger' + '">'+ error.status + ' ' + error.responseText + '</span>');
+            },
+        });
+			
+	})
+
 
-});
diff --git a/views/templates/admin/configure_actions.tpl b/views/templates/admin/configure_actions.tpl
index c82e126385dab872f9142faa9b43222232f7c9ef..62e0040b2c9169b59ce7c8f532081ec98468c13c 100644
--- a/views/templates/admin/configure_actions.tpl
+++ b/views/templates/admin/configure_actions.tpl
@@ -25,89 +25,190 @@
 
 <script type="text/javascript">
 
-$(document).ready(function () {
     $cancel = false;
-    
-	$("#io6-exec-sync").unbind();
-	$("#io6-exec-cancel-sync").on('click', function() {
+
+	$(document).on('click', '#io6-exec-cancel-sync', function() {
 		$cancel = true;
 		$('#io6-exec-sync-info').html("Annullamento in corso...");
 	});
-	
-	
-	$("#io6-exec-sync").unbind();
-	$("#io6-exec-sync").on('click', async function() {
-		$cancel = false;
-		$(this).prop('disabled', true);
-		$("#io6-exec-cancel-sync").removeClass("display-none");
-		var resumeSync = $("#io6-resume-sync").is(':checked') ? 1 : 0;
-		var fastSync = $("#io6-fast-sync").is(':checked') ? 1 : 0;
-	
-		var currentPage = 1;
-		var totalPages = 1;
-		
-		
-		$('#io6-exec-sync-info').html('Inizio sincronizzazione...');			
-		$('#io6-exec-sync-info').show();
 
-		$('#io6-exec-sync-status').hide();
-		$('#io6-exec-sync-status').html('');
+	$(document).on('click', '#io6-exclude-products',async function(e){
+		var href = $(this).attr('href');
+		await $.ajax({
+				method: "get",
+				async: true,
+				dataType: 'json',
+				url: href,
+
+				success: function (data) {
+					if (data.success){
+						$('#io6-exclude-products').prop("disabled", true);
+						$('#io6-include-products').prop("disabled", true);
+						$("#io6-exec-sync").prop("disabled", false);
+					}
+					$('#io6-exclude-include-info').html('<b>Procedura completata: '+ data.message +'</b>');
 
-		
-		while (currentPage <= totalPages && !$cancel) {
-			await $.ajax({
+				},
+				error: function (error) {
+					$('#io6-exclude-include-info').html('<div class="module_confirmation alert alert-danger' + '"><h4 style="margin-bottom:0;">'+ error.message +'</h4></div>');
+				},
+				complete: function() {
+				}
+			});
+	});
+
+	$(document).on('click', '#io6-include-products',async function(e){
+		var href = $(this).attr('href');
+		await $.ajax({
 				method: "get",
 				async: true,
 				dataType: 'json',
 				//url: window.location.protocol + '//' + window.location.hostname + '/wp-admin/admin-ajax.php?action=io6-sync&page=' + currentPage,
-				url: '{$executeUrl}&page=' + currentPage + '&fast=' + fastSync + '&resume=' + resumeSync,
-				
+				url: href,
+
 				success: function (data) {
-					totalPages = data.pages;
-					
-					$('#io6-exec-sync-info').html('Totale prodotti: ' + data.elementsFounds + ". Pagine: " + currentPage + " di " + data.pages);
-					$('#io6-exec-sync-status').show();
-					data.products.forEach(element => {
-						$('#io6-exec-sync-status').prepend("<p class='status-message " + element.status + "' >Prodotto: " + element.io6_id + " - EAN: " + element.ean + " - PARTNUMBER: " + element.partnumber + " - Status: " + element.status_message +  "</p>");
-					});
+					if (data.success){
+						$('#io6-exclude-products').prop("disabled", true);
+						$('#io6-include-products').prop("disabled", true);
+						$("#io6-exec-sync").prop("disabled", false);
+					}
+					$('#io6-exclude-include-info').html('<b>Procedura completata: '+ data.message +'</b>');
 				},
 				error: function (error) {
-					$('#io6-exec-sync-info').html('<div class="module_confirmation alert alert-danger' + '"><h4 style="margin-bottom:0;">'+ error.status + ' ' + error.responseText + '. Ultima pagina importata: '+ currentPage +'</h4></div>');
-					//$('#io6-exec-sync-info').html(error.statusText + "<br/>" + error.status);							
+					$('#io6-exclude-include-info').html('<div class="module_confirmation alert alert-danger' + '"><h4 style="margin-bottom:0;">'+ error.message +'</h4></div>');
 				},
 				complete: function() {
 				}
 			});
-			currentPage++;
+	});
+
+
+	$(document).on('click', "#io6-exec-sync",async function(e){
+		$cancel = false;
+		$(this).prop('disabled', true);
+		$("#io6-exec-cancel-sync").removeClass("display-none");
+		var resumeSync = $("#io6-resume-sync").is(':checked') ? 1 : 0;
+		var fastSync = $("#io6-fast-sync").is(':checked') ? 1 : 0;
+		var catalogsSelected = $("input[id^='io6-catalog-'");
+
+		$('#io6-exec-sync-info').html('Inizio sincronizzazione...');
+		$('#io6-exec-sync-info').show();
+
+		$('#io6-exec-sync-status').hide();
+		$('#io6-exec-sync-status').html('');
+
+		for (i = 0; i < catalogsSelected.length; i++) {
+			if(catalogsSelected[i].checked){
+				var currentPage = 1;
+				var totalPages = 1;
+
+				while (currentPage <= totalPages && !$cancel) {
+					await $.ajax({
+						method: "get",
+						async: true,
+						dataType: 'json',
+						//url: window.location.protocol + '//' + window.location.hostname + '/wp-admin/admin-ajax.php?action=io6-sync&page=' + currentPage,
+						url: '{$executeUrl}&catalogId='+catalogsSelected[i].value+'&page=' + currentPage + '&fast=' + fastSync + '&resume=' + resumeSync,
+
+						success: function (data) {
+							totalPages = data.pages;
+
+							$('#io6-exec-sync-info').html('Catalogo "'+catalogsSelected[i].dataset.catalogName +'", Totale prodotti: ' + data.elementsFounds + ". Pagine: " + currentPage + " di " + data.pages);
+							$('#io6-exec-sync-status').show();
+
+							if(currentPage == 1){
+								$('#io6-exec-sync-status').prepend("<p class='status-message'><b>INIZIO IMPORTAZIONE CATALOGO: "+catalogsSelected[i].dataset.catalogName+"</b></p>")
+							}
+
+							data.products.forEach(element => {
+								$('#io6-exec-sync-status').prepend("<p class='status-message " + element.status + "' >Catalogo: "+ element.catalog_id +" - ID Prodotto IO6: " + element.io6_id + " - ID Prodotto Prestashop: "+ element.ps_product_id +" - EAN: " + element.ean + " - PARTNUMBER: " + element.partnumber + " - Status: " + element.status_message +  "</p>");
+							});
+
+							if(currentPage == totalPages){
+								$('#io6-exec-sync-status').prepend("<p class='status-message'><b>FINE IMPORTAZIONE CATALOGO: "+catalogsSelected[i].dataset.catalogName+"</b></p>")
+								$('#io6-exec-sync-status').prepend("<span><b>-------------------------------------------------------</b></span>")
+							}
+						},
+						error: function (error) {
+							$('#io6-exec-sync-info').html('<div class="module_confirmation alert alert-danger' + '"><h4 style="margin-bottom:0;">'+ error.status + ' ' + error.responseText + '. Ultima pagina importata: '+ currentPage +' di '+ totalPages +'</h4></div>');
+							//$('#io6-exec-sync-info').html(error.statusText + "<br/>" + error.status);
+						},
+						complete: function() {
+						}
+					});
+					currentPage++;
+				}
+			}
 		}
 
+
 		if($cancel)
 			$('#io6-exec-sync-info').append('<br/>Sincronizzazione interrotta.');
 		else
-			$('#io6-exec-sync-info').append('<br/>Sincronizzazione terminata.');			
+			$('#io6-exec-sync-info').append('<br/>Sincronizzazione terminata.');
 
 		$(this).prop('disabled', false);
 		$("#io6-exec-cancel-sync").addClass("display-none");
-			      
-    });    
-  });
+
+    });
+
 
 </script>
 
 <div class="panel">
 	<h3><i class="icon icon-cogs"></i> {l s='Actions' mod='importerone6connect'}</h3>
 	<p>{l s='Avvio della procedura di sincronizzazione del catalogo da ImporterONE Cloud' mod='importerone6connect'}</p>
-	
+
 
 	<div class="form-group">
+		{if $productNotInIo6Tables > 0}
+			<div class="alert alert-warning">
+				<h4><b>{$productNotInIo6Tables} prodotti presenti nel catalogo risultano non associati ad ImporterONE</b></h4>
+				<strong>N.B. queste azioni sono irreversibili, si consiglia di effettuare un backup del database prima di procedere</strong>
+				<p>
+					<ul>
+						<li>
+							Se desideri che questi prodotti siano ignorati, dovrai escluderli dalla sincronizzazione (Questi prodotti non saranno gestiti da ImporterONE).
+						</li>
+						<li>
+							Se desideri che tutti i prodotti già presenti nel sito vengano associati ad ImporterONE, dovrai includerli nella sincronizzazione (Assume rilevanza la scelta inserita nella configurazione in Product Settings --> Utilizzare i fornitori IO6).
+						</li>
+					</ul>
+				</p>
+				<p>Per maggiori informazioni consultare la <a href="https://www.imprimis.it/importerone/help/plugin-prestashop-1-7/#prodotti-non-associati">guida.</a></p>
+				<div class="row" style="margin-top: 10px;">
+					<div class="col-md-9">
+						<button class="btn btn-secondary" id="io6-exclude-products"
+							href="{url entity='module' name='ps_connect_io6' controller='actions' params = ['action' => 'excludeProducts']}">
+							{l s='Escludi i prodotti dalla sincronizzazione' mod='importerone6connect'}
+						</button>
+						<button class="btn btn-secondary" id="io6-include-products"
+							href="{url entity='module' name='ps_connect_io6' controller='actions' params = ['action' => 'includeProducts']}">
+							{l s='Includi i prodotti nella sincronizzazione' mod='importerone6connect'}
+						</button>
+						<br>
+						<span id="io6-exclude-include-info" class="text-center"></span>
+					</div>
+					<div class="col-md-3">
+						<button class="btn btn-secondary" id="download-not-io6-product"
+							href="{url entity='module' name='ps_connect_io6' controller='actions' params = ['action' => 'downloadNotIO6Catalog']}">
+							<i class="icon icon-download"></i><span>{l s='Scarica prodotti' mod='importerone6connect'}</span>
+						</button>
+					</div>
+				</div>
+			</div>
+		{/if}
 		<br/>
-		<label>
-			<input type="checkbox" class="" name="io6-resume-sync" id="io6-resume-sync" value="1"/>
-			{l s='Riprendere sincronizzazione precedente' mod='importerone6connect'}
-			<br />
-			<small>({l s='Se la precedente sincronizzazione non è stata completata, i prodotti già importati verranno ignorati durante questa sincronizzazione' mod='importerone6connect'})</small>
-		</label>
+		{if $syncResume}
+			<label>
+				<input type="checkbox" class="" name="io6-resume-sync" id="io6-resume-sync" value="1"/>
+				{l s='Riprendere sincronizzazione precedente' mod='importerone6connect'}
+				<br />
+				<small>({l s='Presente una sincronizzazione avviata ma non completata. Con questa configurazione i prodotti già importati verranno ignorati. Data ultimo prodotto importato: ' mod='importerone6connect'} {$lastProductSyncDate}) </small>
+
+			</label>
 		<br/>
+		{/if}
 		<label>
 			<input type="checkbox" class="" name="io6-fast-sync" id="io6-fast-sync" value="1"/>
 			{l s='Esegui sincronizzazione veloce' mod='importerone6connect'}
@@ -115,29 +216,16 @@ $(document).ready(function () {
 			<small>({l s='Verranno aggiornati solamente prezzo e quantità dei prodotti esistenti, i prodotti nuovi verranno scartati' mod='importerone6connect'})</small>
 		</label>
 		<br/>
-		<button class="btn btn-primary" id="io6-exec-sync">
+		<button class="btn btn-primary" id="io6-exec-sync" {if $productNotInIo6Tables} disabled {/if}>
 			{l s='Aggiorna catalogo da ImporterONE ...' mod='importerone6connect'}
-		</button>		
+		</button>
 		<button class="btn btn-cancel display-none" id="io6-exec-cancel-sync" >
 			{l s='Annulla' mod='importerone6connect'}
-		</button>		
+		</button>
 	</div>
 	<div class="wrap">
 		<div id="io6-exec-sync-info" class="sync-info"></div>
-		<div id="io6-exec-sync-status" class="sync-status"></div>	
-	</div>
-	<div class="form-group">
-		<br/>		
-		<strong>{l s='Comando CRON sincronizzazione normale' mod='importerone6connect'}</strong>
-		<div class="" style="border: none;border-left: 3px solid #fcc94f;padding: 10px;position: relative;background-color: #fff3d7;color: #d2a63c;">{$cronCommand}</div>
-		<p class="help-block">{l s='Puoi configurare un CRON per l\'esecuzione del comando PHP con i parametri sopra indicati per eseguire l\'aggiornamento automatico del catalogo' mod='importerone6connect'}</p>
-		<br/>		
-		<strong>{l s='Comando CRON sincronizzazione veloce' mod='importerone6connect'}</strong>
-		<div class="" style="border: none;border-left: 3px solid #fcc94f;padding: 10px;position: relative;background-color: #fff3d7;color: #d2a63c;">{$cronCommandFast}</div>
-		<p class="help-block">{l s='Puoi configurare un CRON Fast per l\'esecuzione del comando PHP con i parametri sopra indicati per eseguire l\'aggiornamento automatico del catalogo, verranno aggiornati solamente prezzo e quantità dei prodotti esistenti, i prodotti nuovi verranno scartati' mod='importerone6connect'}</p>
-		<strong>{l s='Comando CRON download immagini' mod='importerone6connect'}</strong>
-		<div class="" style="border: none;border-left: 3px solid #fcc94f;padding: 10px;position: relative;background-color: #fff3d7;color: #d2a63c;">{$cronCommandDownloadImages}</div>
-		<p class="help-block">{l s='Puoi configurare un CRON per l\'esecuzione del comando PHP con i parametri sopra indicati per eseguire l\'aggiornamento automatico delle immagini del catalogo.' mod='importerone6connect'}</p>
+		<div id="io6-exec-sync-status" class="sync-status"></div>
 	</div>
 </div>
 
@@ -156,4 +244,4 @@ $(document).ready(function () {
       </div>
     </div>
   </div>
-</div> *}
\ No newline at end of file
+</div> *}
diff --git a/views/templates/admin/configure_general.tpl b/views/templates/admin/configure_general.tpl
new file mode 100755
index 0000000000000000000000000000000000000000..1ffbe996dafe40d614a1fec164426bb68b611daa
--- /dev/null
+++ b/views/templates/admin/configure_general.tpl
@@ -0,0 +1,110 @@
+{*
+* 2007-2021 PrestaShop
+*
+* NOTICE OF LICENSE
+*
+* This source file is subject to the Academic Free License (AFL 3.0)
+* that is bundled with this package in the file LICENSE.txt.
+* It is also available through the world-wide-web at this URL:
+* http://opensource.org/licenses/afl-3.0.php
+* If you did not receive a copy of the license and are unable to
+* obtain it through the world-wide-web, please send an email
+* to license@prestashop.com so we can send you a copy immediately.
+*
+* DISCLAIMER
+*
+* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+* versions in the future. If you wish to customize PrestaShop for your
+* needs please refer to http://www.prestashop.com for more information.
+*
+*  @author    PrestaShop SA <contact@prestashop.com>
+*  @copyright 2007-2021 PrestaShop SA
+*  @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+*  International Registered Trademark & Property of PrestaShop SA
+*}
+
+<form id="generalSettingsForm" name="generalSettingsForm" action="{Context::getContext()->link->getAdminLink('AdminModules', true, null, array('configure' => $moduleName))}" method="post">
+	<div class="panel">
+		<h3><i class="icon process-icon-stats"></i> {l s='Impostazioni Generali' mod='importerone6connect'}</h3>
+		<div class="row">
+			<div class="col-md-6">
+				<div id="general-settings">
+					<h4>{l s='Seleziona cataloghi da importare' mod='importerone6connect'}</h4>
+					<table id="catalogs-table">
+					{foreach from=$io6Catalogs item=catalog key=key name=name}
+						<tr id="io6-container-catalog-{$catalog->id}" class="catalog-data">
+							<td>
+								<input type="checkbox" id="io6-catalog-{$catalog->id}" name="IMPORTERONE6CONNECT_CATALOGS[{$catalog->id}]" value="{$catalog->id}" data-catalog-name="{$catalog->name}" {if $catalog->selected}checked{/if}>
+								<input type="hidden" id="io6-catalog-{$catalog->id}-name" name="IMPORTERONE6CONNECT_CATALOGS[{$catalog->id}][catalog_name]" value="{$catalog->name}">
+								<label for="io6-catalog-{$catalog->id}">{$catalog->name}</label>
+							</td>
+							<td id="price-selection-catalog-{$catalog->id}">
+								{if !empty($catalog->priceLists)}
+									<span>{l s='Seleziona il listino da importare:' mod='importerone6connect'}</span>
+									<select id="io6-price-catalog-{$catalog->id}" name="IMPORTERONE6CONNECT_CATALOGS[{$catalog->id}][price_list_id]">
+										{foreach from=$catalog->priceLists item=priceList}
+											<option value="{$priceList->id}" {if $priceList->selected}selected{/if}>{$priceList->name}</option>
+										{/foreach}
+									</select>
+								{/if}
+							</td>
+						</tr>
+					{/foreach}
+					</table>
+				</div>
+				{if $productsInDisabledCatalogs|count > 0}
+				<div id="catalog-product-warnings" class="alert alert-warning">
+					{foreach from=$productsInDisabledCatalogs item=disabledCatalog key=catalogId}
+						{if $disabledCatalog['products_count'] > 0}
+							<div id="warnings-catalog-{$catalogId}">
+							<h4>{l s='Problematica con catalogo ' mod='importerone6connect'} {if !empty($disabledCatalog['catalog_name'])}{$disabledCatalog['catalog_name']}{else}{$catalogId} {l s='(Catalogo non più presente in ImporterONE)' mod='importerone6connect'}{/if}</h4>
+								<span>{l s='Nel database di Prestashop sono presenti %s prodotti assegnati ad un catalogo non abilitato. Scegli l\'azione da effettuare:' mod='importerone6connect' sprintf=[$disabledCatalog['products_count']]}</span>
+								<div>
+									<ul>
+										<li>{l s='Disattiva i prodotti interessati' mod='importerone6connect'} <a class="btn btn-primary btn-sm btn-disable-products" href="{Context::getContext()->link->getModuleLink('ps_connect_io6', 'actions', array('action' => "disableProducts", 'catalogId' => $catalogId))}">{l s='Disattiva' mod='importerone6connect'}</a></li>
+										<li>{l s='Sposta i prodotti in un nuovo catalogo' mod='importerone6connect'}
+											<div class="move-products-container">
+												<select>
+												{foreach from=$io6Catalogs item=catalog name="newCatalogOptions"}
+													{if $smarty.foreach.newCatalogOptions.first}
+														<option value="0">{l s='Selezionare un catalogo' mod='importerone6connect'}</option>
+													{/if}
+													{if $catalog->id != $catalogId}
+														<option value="{$catalog->id}">{$catalog->name}</option>
+													{/if}
+												{/foreach}
+												</select>
+												<a data-new-catalog-id="" class="btn btn-primary btn-sm btn-move-products disabled" href="{Context::getContext()->link->getModuleLink('ps_connect_io6', 'actions', array('action' => "moveProducts", 'oldCatalogId' => $catalogId))}">{l s='Sposta' mod='importerone6connect'}</a>
+											</div>
+										</li>
+									</ul>
+								</div>
+							</div>
+						{/if}
+					{/foreach}
+				</div>
+				{/if}
+
+				<div id="generalSettingsErrorSection"></div>
+			</div>
+			<div id="export-categories-io6" class="col-md-6">
+				<h4>{l s='Esporta categorie per mapping' mod='importerone6connect'}</h4>
+				<p>
+						Scarica l'albero categorie in formato CSV per popolare le categorie di un catalogo personale in ImporterONE.<br/>
+						Verranno estratte solo le categorie attive.
+				</p>
+				<div class="form-group p-2">
+					<button class="btn btn-secondary" id="io6-export-categories" href="{$exportCategoriesUrl}">Esporta categorie</button>
+					
+				</div>
+			</div>
+		</div>
+		
+		<div class="panel-footer">
+			<button form="generalSettingsForm" type="submit" id="submitImporterone6connectModule_GeneralSettings" name="submitImporterone6connectModule_GeneralSettings" value="1" class="btn btn-default pull-right">
+			<i class="process-icon-save"></i> Salva
+			</button>
+		</div>
+	</div>
+</form>
+	
diff --git a/views/templates/admin/cron_section.tpl b/views/templates/admin/cron_section.tpl
new file mode 100755
index 0000000000000000000000000000000000000000..9b8be80ed43e8fbbc6d8e8441421da56ba1f21ef
--- /dev/null
+++ b/views/templates/admin/cron_section.tpl
@@ -0,0 +1,53 @@
+{*
+* 2007-2021 PrestaShop
+*
+* NOTICE OF LICENSE
+*
+* This source file is subject to the Academic Free License (AFL 3.0)
+* that is bundled with this package in the file LICENSE.txt.
+* It is also available through the world-wide-web at this URL:
+* http://opensource.org/licenses/afl-3.0.php
+* If you did not receive a copy of the license and are unable to
+* obtain it through the world-wide-web, please send an email
+* to license@prestashop.com so we can send you a copy immediately.
+*
+* DISCLAIMER
+*
+* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
+* versions in the future. If you wish to customize PrestaShop for your
+* needs please refer to http://www.prestashop.com for more information.
+*
+*  @author    PrestaShop SA <contact@prestashop.com>
+*  @copyright 2007-2021 PrestaShop SA
+*  @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+*  International Registered Trademark & Property of PrestaShop SA
+*}
+
+<div class="panel">
+    <h3><i class="icon process-icon-cogs"></i> {l s='Cron' mod='importerone6connect'}</h3>
+    <h4><strong>Verificare con il proprio provider che sia possibile configurare il cron come suggerito.</strong></h4>
+    <br/>
+    <div class="form-group">
+		<strong>{l s='Comando CRON sincronizzazione normale' mod='importerone6connect'}</strong>
+		<br/>
+		{foreach from=$cronCommands item=cronCommand key=catalog_name name=name}
+			<span>{l s='CRON catalogo: ' mod='importerone6connect'} {$catalog_name}</span>
+			<div class="" style="border: none;border-left: 3px solid #fcc94f;padding: 10px;position: relative;background-color: #fff3d7;color: #d2a63c;">{$cronCommand}</div>
+			<p class="help-block">{l s='Puoi configurare un CRON per l\'esecuzione del comando PHP con i parametri sopra indicati per eseguire l\'aggiornamento automatico del catalogo' mod='importerone6connect'}</p>
+			<br/>
+		{/foreach}
+		<br/>
+		<strong>{l s='Comando CRON sincronizzazione veloce' mod='importerone6connect'}</strong>
+		<br/>
+		{foreach from=$cronCommandsFast item=cronCommandFast key=catalog_name name=name}
+			<span>{l s='CRON catalogo: ' mod='importerone6connect'} {$catalog_name}</span>
+			<div class="" style="border: none;border-left: 3px solid #fcc94f;padding: 10px;position: relative;background-color: #fff3d7;color: #d2a63c;">{$cronCommandFast}</div>
+			<p class="help-block">{l s='Puoi configurare un CRON Fast per l\'esecuzione del comando PHP con i parametri sopra indicati per eseguire l\'aggiornamento automatico del catalogo, verranno aggiornati solamente prezzo e quantità dei prodotti esistenti, i prodotti nuovi verranno scartati' mod='importerone6connect'}</p>
+			<br/>
+		{/foreach}
+		<br/>
+		<strong>{l s='Comando CRON download immagini' mod='importerone6connect'}</strong>
+		<div class="" style="border: none;border-left: 3px solid #fcc94f;padding: 10px;position: relative;background-color: #fff3d7;color: #d2a63c;">{$cronCommandDownloadImages}</div>
+		<p class="help-block">{l s='Puoi configurare un CRON per l\'esecuzione del comando PHP con i parametri sopra indicati per eseguire l\'aggiornamento automatico delle immagini del catalogo.' mod='importerone6connect'}</p>
+	</div>
+</div>
\ No newline at end of file
diff --git a/views/templates/admin/displayAdminProductsExtra.tpl b/views/templates/admin/displayAdminProductsExtra.tpl
index d5067533cadf77c82f64a6cd6a16ea7eca72a432..991d4eeff8b936ff77007e5a2f3780c8e0c793da 100644
--- a/views/templates/admin/displayAdminProductsExtra.tpl
+++ b/views/templates/admin/displayAdminProductsExtra.tpl
@@ -36,6 +36,13 @@
             </div>
         </div>
         <div class="col-lg-12">
+          <div class="row form-group">
+            <div class="col-md-4">
+              <div class="checkbox">                          
+                <label>{l s='ID Catalogo ImporterONE' mod='importerone6connect'} <span>{$importerone6connect_catalog_id}</span></label>
+              </div>
+            </div>
+          </div>
           <div class="row form-group">
             <div class="col-md-4">
               <div class="checkbox">                          
diff --git a/views/templates/admin/displayAdminProductsMainStepLeftColumnMiddle.tpl b/views/templates/admin/displayAdminProductsMainStepLeftColumnMiddle.tpl
old mode 100644
new mode 100755
index 6759b3041b7c6a8a36ffa14c0747b6edcbe4941a..4e278efd03d5e47c0b3e682fd9247c6f923bb64a
--- a/views/templates/admin/displayAdminProductsMainStepLeftColumnMiddle.tpl
+++ b/views/templates/admin/displayAdminProductsMainStepLeftColumnMiddle.tpl
@@ -32,21 +32,19 @@
             {if $importerone6connect_sync_status == 1}
               <span class="p-1">{l s='Sincronizzato il: [1]sync_date[/1]' mod='importerone6connect' sprintf=['sync_date' => $importerone6connect_sync_date] tags=['<strong>']}</span>
             {else}
-              <span class="bg-warning p-1">
-                {if !empty($importerone6connect_sync_message)}
-                  {$importerone6connect_sync_message}
+                {if !empty($importerone6connect_sync_message) && !empty($importerone6connect_sync_date)}
+                  <span class="p-1">{l s='Sincronizzato il: [1]sync_date[/1] - sync_message' mod='importerone6connect' sprintf=['sync_date' => $importerone6connect_sync_date, 'sync_message' => $importerone6connect_sync_message] tags=['<strong>']}</span>
                 {else}
-                  {l s='Non ancora sincronizzato' mod='importerone6connect'}
+                  <span class="bg-warning p-1">{l s='Non ancora sincronizzato' mod='importerone6connect'}</span>
                 {/if}
-              </span>
             {/if}
           {else}
             <span class="bg-warning p-1">{l s='Prodotto non sincronizzato con ImporterONE.' mod='importerone6connect'}</span>
           {/if}
-          {if !empty($importerone6connect_io6_id_product)}
+          {if !empty($importerone6connect_io6_id_product) && $importerone6connect_catalog_id > 0}
           <div>
             <a id="io6-single-prod-sync" class="btn btn-primary"
-            href="{url entity='sf' route='admin_io6_productsync' sf-params=['io6_id_product' => $importerone6connect_io6_id_product]}">
+            href="{url entity='sf' route='admin_io6_productsync' sf-params=['io6_id_product' => $importerone6connect_io6_id_product, 'catalogId' => $importerone6connect_catalog_id]}">
             {l s='Sincronizza con ImporterONE' mod='importerone6connect'}</a>
           </div>
           {/if}
diff --git a/views/templates/admin/statistic_info.tpl b/views/templates/admin/statistic_info.tpl
index 4a32d993528481158a607866f458366d1d3516eb..7f9a6427776b73ee249aaf03ba7892f0b3bfffd3 100755
--- a/views/templates/admin/statistic_info.tpl
+++ b/views/templates/admin/statistic_info.tpl
@@ -122,9 +122,8 @@
 </div>
 
 <script type="text/javascript">
-
-$(document).ready(function () {
-	$("a[id^=btnShow_]").on('click', async function(e) {
+        
+	$(document).on('click', 'a[id^=btnShow_]', async function(e) {
         e.preventDefault();
         var info_container = $(this).prop('id').replace('btnShow_', 'io6_info_');
 		$('#'+info_container).html('');
@@ -149,8 +148,7 @@ $(document).ready(function () {
         });
     });
 
-    $("button[id^=io6_downloadCSV_]").on('click', async function(e) {
-        debugger;
+    $(document).on('click', 'button[id^=io6_downloadCSV_]', async function(e) {
         e.preventDefault();
         var download_info_container = $(this).prop('id').replace('io6_downloadCSV_', 'io6_download_info_');
 
@@ -159,7 +157,6 @@ $(document).ready(function () {
             async: true,
             url:  $(this).attr('href'),
             success: function (data) {
-                debugger;
                 var downloadLink = document.createElement("a");
                 var fileData = ['\ufeff'+data];
                 var blobObject = new Blob(fileData,{
@@ -180,6 +177,5 @@ $(document).ready(function () {
             },
         });
     });
-  });
 
 </script>
diff --git a/views/templates/admin/statistic_section.tpl b/views/templates/admin/statistic_section.tpl
index 4e89e9d701650bb42ba733541d2b612846cfe615..969080c7ecbfee6932e8e6a689d6672e00e17c77 100755
--- a/views/templates/admin/statistic_section.tpl
+++ b/views/templates/admin/statistic_section.tpl
@@ -31,8 +31,7 @@
 
 <script type="text/javascript">
 
-$(document).ready(function () {
-	$("#show_statistic_info").on('click', async function(e) {
+	$(document).on('click', '#show_statistic_info', async function(e) {
         e.preventDefault();
 		
         await $.ajax({
@@ -50,6 +49,5 @@ $(document).ready(function () {
             },
         });
     });    
-  });
 
 </script>
\ No newline at end of file