diff --git a/import-products.php b/import-products.php new file mode 100644 index 00000000..d9c8c51b --- /dev/null +++ b/import-products.php @@ -0,0 +1,377 @@ + Podatki > Reguły podatkowe +$configTaxRulesGroupId = 1; + +// ID Kategorii domyślnej, do której mają trafić produkty (np. "Kinkiety" lub ogólna) +$configDefaultCategoryId = 12; + +// Czy włączyć produkt po imporcie? +$configActive = 1; + +// ============================================ + +// Sprawdzenie trybu działania +$modeAdd = (Tools::getValue('add') === 'true'); +$modeUpdate = (Tools::getValue('update') === 'true'); +$modeSynch = (Tools::getValue('synch') === 'true'); + +if (!$modeAdd && !$modeUpdate && !$modeSynch) { + die('Brak akcji. Dodaj do adresu ?add=true lub ?update=true lub ?synch=true'); +} + +// Plik logu +$logFile = __DIR__ . '/sollux_import_log.csv'; + +// Wczytanie XML +$xmlUrl = 'https://sollux-lighting.com/product_feed/sollux/XML_polski_PLN_wszystkie_vip.xml'; +$xml = simplexml_load_file($xmlUrl) or die("Error: Cannot create object from XML"); + + +// === FUNKCJE POMOCNICZE === + +// Tworzenie pola multilang (wymagane przez Prestę) +function createMultiLangField($field) { + $languages = Language::getLanguages(false); + $res = []; + foreach ($languages as $lang) { + $res[(int)$lang['id_lang']] = $field; + } + return $res; +} + +// Tworzenie przyjaznego linku +function createLinkRewrite($field) { + $languages = Language::getLanguages(false); + $res = []; + $linkRewrite = Tools::link_rewrite($field); + foreach ($languages as $lang) { + $res[(int)$lang['id_lang']] = $linkRewrite; + } + return $res; +} + +// Pobieranie zdjęcia +function addProductImage($productId, $imageUrl) { + if (empty($imageUrl)) return false; + + $image = new Image(); + $image->id_product = (int)$productId; + $image->position = Image::getHighestPosition($productId) + 1; + $image->cover = ($image->position == 1); // Pierwsze zdjęcie jako okładka + if (!$image->add()) return false; + + $imagePath = $image->getPathForCreation(); + $url = str_replace(' ', '%20', trim($imageUrl)); + + // Próba pobrania + if (!@copy($url, $imagePath . '.jpg')) { + $image->delete(); + return false; + } + + // Generowanie miniatur + $imageTypes = ImageType::getImagesTypes('products'); + foreach ($imageTypes as $imageType) { + if (!ImageManager::resize( + $imagePath . '.jpg', + $imagePath . '-' . stripslashes($imageType['name']) . '.jpg', + (int)$imageType['width'], + (int)$imageType['height'] + )) { + // W razie błędu resize można obsłużyć wyjątek, tutaj cicho pomijamy + } + } + return true; +} + +// Znajdź produkt po SKU (reference) +function findProductByReference($reference) { + if (empty($reference)) return false; + + $sql = 'SELECT `id_product` + FROM `'._DB_PREFIX_.'product` + WHERE `reference` = \''.pSQL($reference).'\''; + $result = Db::getInstance()->getRow($sql); + return $result ? new Product((int)$result['id_product']) : false; +} + +// Parsowanie ceny (zamiana przecinków na kropki, usuwanie spacji) +function parsePrice($rawPrice) { + $clean = str_replace([' ', ','], ['', '.'], (string)$rawPrice); + return (float)$clean; +} + +// Budowanie tabeli HTML z atrybutów XML +function buildAttributesHtml($xmlAttributesNode) { + if (!$xmlAttributesNode || !isset($xmlAttributesNode->attribute)) { + return ''; + } + + $html = '
| ' . htmlspecialchars($name) . ' | '; + $html .= '' . htmlspecialchars($value) . ' | '; + $html .= '
Wyłączono produkty niedostępne w feedzie.
"; + + // Włącz produkty, które są w XML + $sqlEnable = 'UPDATE `'._DB_PREFIX_.'product` p + JOIN `'._DB_PREFIX_.'sollux_temp` t ON p.reference = t.sku + SET p.active = 1 + WHERE p.active = 0'; + + $db->execute($sqlEnable); + echo "Włączono produkty dostępne w feedzie.
"; + + // Posprzątaj + $db->execute('DROP TABLE `'._DB_PREFIX_.'sollux_temp`'); + echo 'Zakończono synchronizację.
'; + exit; +} + +// 2. TRYB AKTUALIZACJI (Ceny, Stany) +if ($modeUpdate) { + cleanLogFile($logFile); + $today = date('Y-m-d'); + $updatedCount = 0; + + // Wczytaj log, aby nie aktualizować tego samego produktu wielokrotnie tego samego dnia + $processedSkus = []; + if (file_exists($logFile)) { + $lines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + foreach ($lines as $line) { + $data = explode(';', $line); // Date;SKU + if (isset($data[0]) && $data[0] == $today && isset($data[1])) { + $processedSkus[trim($data[1])] = true; + } + } + } + + echo "Zaktualizowano: $sku (Cena netto: $priceNet)
"; + $updatedCount++; + + // Aktualizujemy 1 produkt na wywołanie, żeby nie przekroczyć czasu wykonywania? + // W poprzednim skrypcie był break. Jeśli masz crona co minutę, odkomentuj break. + // Jeśli odpalasz ręcznie w przeglądarce, break spowoduje konieczność ciągłego odświeżania. + // Zostawiam break dla bezpieczeństwa, odświeżaj stronę (meta reload na dole). + break; + } + + if ($updatedCount > 0) { + echo ''; + echo 'Trwa przeładowanie strony...
'; + } else { + echo 'Wszystkie produkty z XML zostały już dzisiaj zaktualizowane.
'; + } + exit; +} + +// 3. TRYB DODAWANIA (ADD) +if ($modeAdd) { + $addedCount = 0; + + foreach ($xml->product as $productNode) { + $sku = trim((string)$productNode->sku); + if (empty($sku)) continue; + + // Sprawdź czy produkt już istnieje + if (findProductByReference($sku)) { + // Produkt istnieje, w trybie ADD nic nie robimy (ewentualnie można zrobić update) + continue; + } + + // === TWORZENIE NOWEGO PRODUKTU === + $product = new Product(); + $product->reference = $sku; + $product->ean13 = trim((string)$productNode->ean); + $product->name = createMultiLangField(trim((string)$productNode->nazwa_produktu)); + + // Kategoria i Producent + $product->id_category_default = (int)$configDefaultCategoryId; + $product->id_manufacturer = (int)$configManufacturerId; + $product->id_tax_rules_group = (int)$configTaxRulesGroupId; // VAT + + // Cena + $priceGross = parsePrice($productNode->cena_detaliczna_brutto_pln); + $product->price = Tools::ps_round($priceGross / 1.23, 6); + + // Wymiary i Waga + $product->width = (float)$productNode->szerokosc; + $product->height = (float)$productNode->wysokosc; + $product->depth = (float)$productNode->dlugosc; + $product->weight = (float)$productNode->waga_produktu; + + // Opisy + $shortDesc = trim((string)$productNode->opis_krotki_html); + $longDescRaw = trim((string)$productNode->opis_dlugi_korzysci_html); + + // Generowanie tabeli specyfikacji z atrybutów + $attributesHtml = buildAttributesHtml($productNode->attributes); + + // Sklejenie opisu: Opis marketingowy + Tabela atrybutów + $finalLongDesc = $longDescRaw . 'Dodano produkt: " . $product->name[Context::getContext()->language->id] . " ($sku)
"; + $addedCount++; + + // Break po dodaniu jednego, aby odciążyć serwer (skrypt musi być wywoływany cyklicznie) + break; + } else { + echo "Błąd podczas dodawania produktu: $sku
"; + } + } + + if ($addedCount > 0) { + echo ''; + echo 'Dodano produkt. Odświeżanie...
'; + } else { + echo 'Brak nowych produktów do dodania (lub wszystkie już istnieją).
'; + } +} +?> \ No newline at end of file