diff --git a/modules/ecomzone-final-28012025.zip b/modules/ecomzone-final-28012025.zip new file mode 100644 index 0000000..b383126 Binary files /dev/null and b/modules/ecomzone-final-28012025.zip differ diff --git a/modules/ecomzone-vancho1.zip b/modules/ecomzone-vancho1.zip new file mode 100644 index 0000000..4594a17 Binary files /dev/null and b/modules/ecomzone-vancho1.zip differ diff --git a/modules/ecomzone-withsave.zip b/modules/ecomzone-withsave.zip new file mode 100644 index 0000000..f493507 Binary files /dev/null and b/modules/ecomzone-withsave.zip differ diff --git a/modules/ecomzone/cron.php b/modules/ecomzone/cron.php new file mode 100644 index 0000000..2b0ec32 --- /dev/null +++ b/modules/ecomzone/cron.php @@ -0,0 +1,8 @@ +hookActionCronJob(); +} \ No newline at end of file diff --git a/modules/ecomzone/ecomzone.php b/modules/ecomzone/ecomzone.php index b9f775f..d5cdfed 100644 --- a/modules/ecomzone/ecomzone.php +++ b/modules/ecomzone/ecomzone.php @@ -39,14 +39,16 @@ class EcomZone extends Module return false; } - if (!$this->registerHook('actionProductUpdate')) { + if (!$this->registerHook('actionProductUpdate') || + !$this->registerHook('actionCronJob')) { $this->errors[] = $this->l('Could not register hooks'); return false; } - // Set default API key from your working configuration + // Set default API configuration if (!Configuration::updateValue('ECOMZONE_API_KEY', 'klRyAdrXaxL0s6PEUp7LDlH6T8aPSCtBY8NiEHsHiWpc6646K2TZPi5KMxUg') || - !Configuration::updateValue('ECOMZONE_API_URL', 'https://dropship.ecomzone.eu/api')) { + !Configuration::updateValue('ECOMZONE_API_URL', 'https://dropship.ecomzone.eu/api') || + !Configuration::updateValue('ECOMZONE_LAST_CRON', time())) { $this->errors[] = $this->l('Could not set default configuration'); return false; } @@ -60,13 +62,12 @@ class EcomZone extends Module $debugOutput = ''; if (Tools::isSubmit('submitEcomZone')) { - $apiKey = trim(Tools::getValue('ECOMZONE_API_KEY')); + $apiKey = Tools::getValue('ECOMZONE_API_KEY'); if (!$apiKey) { $output .= $this->displayError($this->l('API Key is required')); } else { Configuration::updateValue('ECOMZONE_API_KEY', $apiKey); - $debugOutput .= "API Key saved: " . substr($apiKey, 0, 10) . "...\n"; $output .= $this->displayConfirmation($this->l('Settings updated')); } } @@ -74,40 +75,37 @@ class EcomZone extends Module // Handle manual fetch if (Tools::isSubmit('fetchProducts')) { try { - $debugOutput .= "Starting product fetch...\n"; + $debugOutput .= "Starting manual product fetch...\n"; + $result = $this->cronRefreshProducts(); - // Get all products - $catalog = $this->api->getCatalog(1000); - - if (isset($catalog['data']) && is_array($catalog['data'])) { - $debugOutput .= sprintf("Fetching all products...\n"); - $totalProducts = count($catalog['data']); - - // Show first 5 products as preview - for ($i = 0; $i < min(5, $totalProducts); $i++) { - $product = $catalog['data'][$i]; - $debugOutput .= sprintf( - "Product %d/%d: %s - %s (Price: %s EUR, Stock: %s)\n", - $i + 1, - $totalProducts, - $product['sku'], - $product['product_name'], - $product['product_price'], - $product['stock'] - ); + if ($result['success']) { + $catalog = $this->api->getCatalog(1000); + if (isset($catalog['data']) && is_array($catalog['data'])) { + $totalProducts = count($catalog['data']); + $debugOutput .= sprintf("Found %d products\n\nPreview of first 5 products:\n", $totalProducts); + + // Show first 5 products as preview + for ($i = 0; $i < min(5, $totalProducts); $i++) { + $product = $catalog['data'][$i]; + $debugOutput .= sprintf( + "Product %d/%d: %s - %s (Price: %s EUR, Stock: %s)\n", + $i + 1, + $totalProducts, + $product['sku'], + $product['product_name'], + $product['product_price'], + $product['stock'] + ); + } + + if ($totalProducts > 5) { + $debugOutput .= "\n... and " . ($totalProducts - 5) . " more products\n"; + } + + $debugOutput .= sprintf("\nTotal products updated: %d\n", $result['updated']); } - - if ($totalProducts > 5) { - $debugOutput .= "...\n"; // Indicate there are more products - } - - $debugOutput .= sprintf("\nTotal products fetched: %d\n", $totalProducts); - } else { - $debugOutput .= "No products found or invalid response format\n"; + $output .= $this->displayConfirmation($this->l('Products fetched successfully')); } - - $output .= $this->displayConfirmation($this->l('Products fetched successfully')); - } catch (Exception $e) { $debugOutput .= "Error: " . $e->getMessage() . "\n"; $output .= $this->displayError($this->l('Error fetching products')); @@ -225,4 +223,223 @@ class EcomZone extends Module ); } } + + public function cronRefreshProducts() + { + try { + PrestaShopLogger::addLog( + 'EcomZone: Starting scheduled product refresh', + 1, + null, + 'EcomZone' + ); + + $catalog = $this->api->getCatalog(1000); + + if (!isset($catalog['data']) || !is_array($catalog['data'])) { + throw new Exception('Invalid catalog data received from API'); + } + + $totalProducts = count($catalog['data']); + $updatedCount = 0; + $createdCount = 0; + $defaultLangId = (int)Configuration::get('PS_LANG_DEFAULT'); + $defaultShopId = (int)Configuration::get('PS_SHOP_DEFAULT'); + + foreach ($catalog['data'] as $ecomZoneProduct) { + $reference = $ecomZoneProduct['sku']; + $productId = Product::getIdByReference($reference); + + try { + if (!$productId) { + // Create new product + $product = new Product(); + $product->reference = $reference; + $product->name = [$defaultLangId => $ecomZoneProduct['product_name']]; + $product->description = [$defaultLangId => $ecomZoneProduct['long_description'] ?? '']; + $product->description_short = [$defaultLangId => $ecomZoneProduct['description'] ?? '']; + $product->price = (float)$ecomZoneProduct['product_price']; + $product->active = true; // Make sure product is active + $product->visibility = 'both'; // Show in catalog and search + $product->available_for_order = true; + $product->show_price = true; + $product->id_shop_default = $defaultShopId; + $product->id_category_default = 2; // Home category + + // Add to all shops if multistore + $product->id_shop_list = Shop::getShops(true, null, true); + + if ($product->add()) { + $productId = $product->id; + + // Associate with Home category + $product->addToCategories([2]); + + // Set stock + StockAvailable::setQuantity($productId, 0, (int)$ecomZoneProduct['stock']); + + // Set stock settings + StockAvailable::setProductOutOfStock($productId, 1); // Allow orders when out of stock + + // Update shop association + $product->updateCategories($product->id_shop_list); + + // Add minimum quantity of 1 + $product->minimal_quantity = 1; + $product->update(); + + $createdCount++; + + // Download and set product image if available + if (!empty($ecomZoneProduct['image'])) { + $this->importProductImage($product, $ecomZoneProduct['image']); + } + } + } else { + // Update existing product + $product = new Product($productId); + $product->name[$defaultLangId] = $ecomZoneProduct['product_name']; + $product->description[$defaultLangId] = $ecomZoneProduct['long_description'] ?? ''; + $product->description_short[$defaultLangId] = $ecomZoneProduct['description'] ?? ''; + $product->price = (float)$ecomZoneProduct['product_price']; + $product->active = true; // Make sure product is active + $product->visibility = 'both'; + $product->available_for_order = true; + $product->show_price = true; + $product->update(); + + StockAvailable::setQuantity($productId, 0, (int)$ecomZoneProduct['stock']); + $updatedCount++; + } + + // Clear cache for this product + $this->clearProductCache($productId); + + } catch (Exception $e) { + PrestaShopLogger::addLog( + sprintf('EcomZone: Error processing product %s: %s', $reference, $e->getMessage()), + 3, + null, + 'Product' + ); + continue; + } + } + + // Clear cache after all products are processed + $this->clearCache(); + + PrestaShopLogger::addLog( + sprintf('EcomZone: Created %d new products, Updated %d existing products', + $createdCount, + $updatedCount + ), + 1, + null, + 'EcomZone' + ); + + return [ + 'success' => true, + 'message' => sprintf('Created %d new products, Updated %d existing products', $createdCount, $updatedCount), + 'total' => $totalProducts, + 'created' => $createdCount, + 'updated' => $updatedCount + ]; + + } catch (Exception $e) { + PrestaShopLogger::addLog( + 'EcomZone Error: ' . $e->getMessage(), + 3, + null, + 'EcomZone' + ); + throw $e; + } + } + + private function importProductImage($product, $imageUrl) + { + try { + $tempFile = tempnam(_PS_TMP_IMG_DIR_, 'import'); + if (@file_put_contents($tempFile, @file_get_contents($imageUrl))) { + $product->deleteImages(); // Remove existing images + $image = new Image(); + $image->id_product = $product->id; + $image->position = 1; + $image->cover = true; + + if ($image->add()) { + return (bool)@rename($tempFile, _PS_PROD_IMG_DIR_ . $image->getImgPath() . '.jpg'); + } + } + return false; + } catch (Exception $e) { + PrestaShopLogger::addLog( + sprintf('EcomZone: Error importing image for product %d: %s', $product->id, $e->getMessage()), + 3, + null, + 'Product' + ); + return false; + } + } + + public function hookActionCronJob() + { + $lastRun = (int)Configuration::get('ECOMZONE_LAST_CRON'); + $currentTime = time(); + + // Check if 2 hours have passed (7200 seconds) + if (($currentTime - $lastRun) >= 7200) { + $this->cronRefreshProducts(); + Configuration::updateValue('ECOMZONE_LAST_CRON', $currentTime); + } + } + + public function uninstall() + { + return parent::uninstall() && + Configuration::deleteByName('ECOMZONE_API_KEY') && + Configuration::deleteByName('ECOMZONE_API_URL') && + Configuration::deleteByName('ECOMZONE_LAST_CRON'); + } + + private function clearProductCache($productId) + { + try { + Tools::clearSmartyCache(); + Tools::clearXMLCache(); + Media::clearCache(); + + $sql = 'DELETE FROM ' . _DB_PREFIX_ . 'smarty_cache + WHERE template LIKE "%product%"'; + Db::getInstance()->execute($sql); + + } catch (Exception $e) { + PrestaShopLogger::addLog( + sprintf('EcomZone: Error clearing cache for product %d: %s', $productId, $e->getMessage()), + 3, + null, + 'Product' + ); + } + } + + private function clearCache() + { + try { + Tools::clearSmartyCache(); + Tools::clearXMLCache(); + Media::clearCache(); + Tools::generateIndex(); + } catch (Exception $e) { + PrestaShopLogger::addLog( + 'EcomZone: Error clearing cache: ' . $e->getMessage(), + 3, + null, + 'EcomZone' + ); + } + } } \ No newline at end of file