name = 'ecomzone'; $this->tab = 'market_place'; $this->version = '1.0.0'; $this->author = 'Your Name'; $this->need_instance = 0; $this->bootstrap = true; $this->ps_versions_compliancy = [ 'min' => '1.7.0.0', 'max' => _PS_VERSION_ ]; parent::__construct(); $this->displayName = $this->l('EcomZone Integration'); $this->description = $this->l('Integrates PrestaShop with EcomZone Dropshipping API'); // Initialize API require_once(dirname(__FILE__) . '/classes/EcomZoneAPI.php'); $this->api = new EcomZoneAPI(); } public function install() { if (!parent::install()) { $this->errors[] = $this->l('Could not install the module'); return false; } if (!$this->registerHook('actionProductUpdate') || !$this->registerHook('actionCronJob')) { $this->errors[] = $this->l('Could not register hooks'); return false; } // Set default API configuration if (!Configuration::updateValue('ECOMZONE_API_KEY', 'klRyAdrXaxL0s6PEUp7LDlH6T8aPSCtBY8NiEHsHiWpc6646K2TZPi5KMxUg') || !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; } return true; } public function getContent() { $output = ''; $debugOutput = ''; if (Tools::isSubmit('submitEcomZone')) { $apiKey = Tools::getValue('ECOMZONE_API_KEY'); if (!$apiKey) { $output .= $this->displayError($this->l('API Key is required')); } else { Configuration::updateValue('ECOMZONE_API_KEY', $apiKey); $output .= $this->displayConfirmation($this->l('Settings updated')); } } // Handle manual fetch if (Tools::isSubmit('fetchProducts')) { try { $debugOutput .= "Starting manual product fetch...\n"; $result = $this->cronRefreshProducts(); 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']); } $output .= $this->displayConfirmation($this->l('Products fetched successfully')); } } catch (Exception $e) { $debugOutput .= "Error: " . $e->getMessage() . "\n"; $output .= $this->displayError($this->l('Error fetching products')); } } // Store debug output in smarty variable $this->context->smarty->assign('debug_output', $debugOutput); return $output . $this->displayForm(); } public function displayForm() { $fields_form[0]['form'] = [ 'legend' => [ 'title' => $this->l('Settings'), ], 'input' => [ [ 'type' => 'text', 'label' => $this->l('API Key'), 'name' => 'ECOMZONE_API_KEY', 'required' => true, 'size' => 50 ], ], 'buttons' => [ [ 'type' => 'submit', 'title' => $this->l('Fetch Products'), 'icon' => 'process-icon-download', 'name' => 'fetchProducts', 'class' => 'btn btn-primary pull-left' ] ], 'submit' => [ 'title' => $this->l('Save'), 'class' => 'btn btn-default pull-right' ] ]; $helper = new HelperForm(); $helper->module = $this; $helper->name_controller = $this->name; $helper->token = Tools::getAdminTokenLite('AdminModules'); $helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name; $helper->default_form_language = Configuration::get('PS_LANG_DEFAULT'); $helper->fields_value['ECOMZONE_API_KEY'] = Configuration::get('ECOMZONE_API_KEY'); // Add debug console after form $form = $helper->generateForm($fields_form); $debug_console = '
' . $this->l('Debug Console') . '
                    ' . $this->context->smarty->getTemplateVars('debug_output') . '
                
'; return $form . $debug_console; } public function getErrors() { return $this->errors; } public function hookActionProductUpdate($params) { try { $product = $params['product']; $productId = $product->id; // Get product reference (SKU) $reference = $product->reference; if (!empty($reference)) { // Get product data from EcomZone $ecomZoneProduct = $this->api->getProduct($reference); if ($ecomZoneProduct && isset($ecomZoneProduct['data'])) { // Update stock if (isset($ecomZoneProduct['data']['stock'])) { StockAvailable::setQuantity($productId, 0, (int)$ecomZoneProduct['data']['stock']); } // Update price if (isset($ecomZoneProduct['data']['product_price'])) { $product->price = (float)$ecomZoneProduct['data']['product_price']; $product->update(); } PrestaShopLogger::addLog( sprintf('EcomZone: Updated product %s (ID: %d)', $reference, $productId), 1, // Notice level null, 'Product', $productId, true ); } } } catch (Exception $e) { PrestaShopLogger::addLog( sprintf('EcomZone: Error updating product %d: %s', $productId, $e->getMessage()), 3, // Error level null, 'Product', $productId, true ); } } 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' ); } } }