language->id; $sql = 'SELECT `id_attribute_group` FROM `'._DB_PREFIX_.'attribute_group_lang` WHERE `name` = \''.pSQL($name).'\' AND `id_lang` = '.(int)$id_lang; $result = Db::getInstance()->getRow($sql); return $result ? new AttributeGroup($result['id_attribute_group']) : false; } // Function to find attribute by name function findAttributeByName($id_attribute_group, $name) { $id_lang = Context::getContext()->language->id; $sql = 'SELECT a.`id_attribute` FROM `'._DB_PREFIX_.'attribute` a JOIN `'._DB_PREFIX_.'attribute_lang` al ON a.`id_attribute` = al.`id_attribute` WHERE al.`name` = \''.pSQL($name).'\' AND al.`id_lang` = '.(int)$id_lang.' AND a.`id_attribute_group` = '.(int)$id_attribute_group; $result = Db::getInstance()->getRow($sql); return $result ? new Attribute($result['id_attribute']) : false; } // Function to create attribute if it doesn't exist function createAttribute($name, $values) { $attributeGroup = findAttributeGroupByName($name); if (!$attributeGroup) { $attributeGroup = new AttributeGroup(); $attributeGroup->name = createMultiLangField($name); $attributeGroup->public_name = createMultiLangField($name); $attributeGroup->group_type = 'select'; $attributeGroup->add(); } foreach ($values as $value) { $attribute = findAttributeByName($attributeGroup->id, $value); if (!$attribute) { $attribute = new Attribute(); $attribute->id_attribute_group = $attributeGroup->id; $attribute->name = createMultiLangField($value); $attribute->add(); } } return $attributeGroup->id; } // Helper function to create a multi-language field function createMultiLangField($field) { $languages = Language::getLanguages(false); $res = []; foreach ($languages as $lang) { $res[(int)$lang['id_lang']] = $field; } return $res; } // Helper function to create a valid link_rewrite function createLinkRewrite($field) { $languages = Language::getLanguages(false); $res = []; $linkRewrite = Tools::link_rewrite($field); // PrestaShop's function to create valid link_rewrite foreach ($languages as $lang) { $res[(int)$lang['id_lang']] = $linkRewrite; } return $res; } // Function to get category ID from name (nieużywana, ale poprawiona) function getCategoryId($categoryName) { $result = Category::searchByName(1, $categoryName); // 1 for default language id if (!empty($result) && isset($result[0]['id_category'])) { return (int)$result[0]['id_category']; } else { // Create category if not exists $category = new Category(); $category->name = createMultiLangField($categoryName); $category->link_rewrite = createLinkRewrite($categoryName); $category->id_parent = 2; // Default parent category $category->add(); return (int)$category->id; } } function getAllImageUrlsFromXmlProduct($productData, $max = 10) { $urls = []; // główne if (!empty($productData->image)) { $urls[] = trim((string)$productData->image); } // images_1..10 oraz Images_1..10 (różna wielkość liter w XML!) for ($i = 1; $i <= $max; $i++) { $k1 = 'images_' . $i; $k2 = 'Images_' . $i; $u1 = isset($productData->{$k1}) ? trim((string)$productData->{$k1}) : ''; $u2 = isset($productData->{$k2}) ? trim((string)$productData->{$k2}) : ''; if ($u1 !== '') $urls[] = $u1; if ($u2 !== '') $urls[] = $u2; } // usuń duplikaty + puste $urls = array_values(array_unique(array_filter($urls))); return $urls; } // Function to download image from URL and associate it with a product function addProductImage($productId, $imageUrl, $isCover = false) { $image = new Image(); $image->id_product = (int)$productId; $image->position = Image::getHighestPosition($productId) + 1; $image->cover = (bool)$isCover; // tylko pierwsze jako cover $image->add(); $imagePath = $image->getPathForCreation(); // pobranie pliku $url = str_replace(' ', '%20', trim($imageUrl)); // UWAGA: copy() czasem failuje na HTTPS; file_get_contents + file_put_contents bywa pewniejsze $data = @file_get_contents($url); if ($data === false) { $image->delete(); return false; } if (@file_put_contents($imagePath . '.jpg', $data) === false) { $image->delete(); return false; } $imageTypes = ImageType::getImagesTypes('products'); foreach ($imageTypes as $imageType) { ImageManager::resize( $imagePath . '.jpg', $imagePath . '-' . stripslashes($imageType['name']) . '.jpg', (int)$imageType['width'], (int)$imageType['height'] ); } return true; } // Function to find product by reference function findProductByReference($reference) { $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; } // Function to find combination by product ID and attribute IDs function findCombinationByAttributes($id_product, $attributeIds) { if (empty($attributeIds)) { return false; } sort($attributeIds); $conditions = []; foreach ($attributeIds as $id_attr) { $conditions[] = 'pac.`id_attribute` = '.(int)$id_attr; } $sql = 'SELECT c.`id_product_attribute` FROM `'._DB_PREFIX_.'product_attribute` c JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON c.`id_product_attribute` = pac.`id_product_attribute` WHERE c.`id_product` = '.(int)$id_product.' GROUP BY c.`id_product_attribute` HAVING SUM('.implode(' OR ', $conditions).') = '.count($attributeIds); $result = Db::getInstance()->getRow($sql); return $result ? new Combination((int)$result['id_product_attribute']) : false; } // znajdowanie kombinacji po indeksie/SKU (reference) function findCombinationByReference($id_product, $reference) { $sql = 'SELECT `id_product_attribute` FROM `'._DB_PREFIX_.'product_attribute` WHERE `id_product` = '.(int)$id_product.' AND `reference` = \''.pSQL($reference).'\''; $id = Db::getInstance()->getValue($sql); return $id ? new Combination((int)$id) : false; } function parsePrice($rawPrice) { // Na wszelki wypadek rzutujemy na string i obcinamy spacje $rawPrice = trim((string)$rawPrice); if ($rawPrice === '') { return 0.0; } // Zostawiamy tylko cyfry, przecinek, kropkę i minus // Usuwamy walutę, spacje, itp. $clean = preg_replace('/[^\d,.\-]/', '', $rawPrice); $hasComma = strpos($clean, ',') !== false; $hasDot = strpos($clean, '.') !== false; // Przypadek typowo polski: "1234,56" lub "125,00" if ($hasComma && !$hasDot) { $clean = str_replace(',', '.', $clean); } // Przypadek mieszany: "1.234,56" -> usuń kropki (separatory tysięcy), przecinek zamień na kropkę elseif ($hasComma && $hasDot) { $clean = str_replace('.', '', $clean); // usuwamy separatory tysięcy $clean = str_replace(',', '.', $clean); // przecinek na kropkę } // Jeśli jest tylko kropka ("1234.56") – nic nie zmieniamy return (float)$clean; } // Bazowa cena dla grupy – najtańszy wariant (zwraca [brutto, netto]) function getBasePricesFromGroup($products) { $minNet = null; $minGross = null; foreach ($products as $p) { $gross = parsePrice((string)$p->price); if ($gross <= 0) { continue; } $net = Tools::ps_round($gross / 1.23, 6); if ($minNet === null || $net < $minNet) { $minNet = $net; $minGross = $gross; } } if ($minNet === null) { return [0.0, 0.0]; } return [$minGross, $minNet]; } // Czyści log aktualizacji cen - zostawia tylko wpisy z ostatnich X dni function cleanUpdateLog($logFile, $daysToKeep = 30) { if (!file_exists($logFile)) { return; } $cutoffDate = date('Y-m-d', strtotime('-'.(int)$daysToKeep.' days')); $lines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); if ($lines === false || empty($lines)) { return; } $newLines = []; foreach ($lines as $line) { $parts = explode(';', $line); if (count($parts) < 1) { // linia uszkodzona – pomijamy continue; } $logDate = trim($parts[0]); // Jeśli data ma format YYYY-MM-DD i jest nowsza/równa cutoff – zostawiamy if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $logDate) && $logDate >= $cutoffDate) { $newLines[] = $line; } // Jeśli format daty jest dziwny – na wszelki wypadek zachowajmy wpis elseif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $logDate)) { $newLines[] = $line; } } // Nadpisujemy plik przefiltrowaną zawartością if (!empty($newLines)) { file_put_contents($logFile, implode(PHP_EOL, $newLines) . PHP_EOL); } else { // Jeśli wszystko stare/uszkodzone – czyścimy plik file_put_contents($logFile, ''); } } // Zwraca id_tax_rules_group dla stawki VAT (np. 23) dla kraju domyślnego function getTaxRulesGroupIdForRate($rate, $id_country = null) { if ($id_country === null) { $id_country = (int)Configuration::get('PS_COUNTRY_DEFAULT'); } $sql = 'SELECT trg.`id_tax_rules_group` FROM `'._DB_PREFIX_.'tax_rules_group` trg INNER JOIN `'._DB_PREFIX_.'tax_rule` tr ON (trg.`id_tax_rules_group` = tr.`id_tax_rules_group`) INNER JOIN `'._DB_PREFIX_.'tax` t ON (tr.`id_tax` = t.`id_tax`) WHERE trg.`active` = 1 AND tr.`id_country` = '.(int)$id_country.' AND t.`rate` = '.(float)$rate.' ORDER BY trg.`id_tax_rules_group` ASC'; $id = Db::getInstance()->getValue($sql); return $id ? (int)$id : 8; } // Zwraca główny produkt z grupy – pierwszy, którego SKU istnieje w PrestaShop function findMainProductDataFromGroup($products) { foreach ($products as $p) { $ref = (string)$p->sku; if ($ref !== '' && findProductByReference($ref)) { return $p; // to główny produkt } } return null; } // === GRUPOWANIE PRODUKTÓW PO SYMBOLU === $productsBySymbol = []; foreach ($xml->product as $productData) { $symbol = (string)$productData->item_group_id; if (!isset($productsBySymbol[$symbol])) { $productsBySymbol[$symbol] = []; } $productsBySymbol[$symbol][] = $productData; } // ID grupy VAT 23% $idTaxRulesGroup23 = 8; // ======================================= // =========== TRYB AKTUALIZACJI ========= // ======================================= if ($modeUpdate) { cleanUpdateLog($logFile, 30); $today = date('Y-m-d'); $updatedToday = []; // Wczytanie logu aktualizacji if (file_exists($logFile)) { $lines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($lines as $line) { $parts = explode(';', $line); if (count($parts) >= 3) { $logDate = trim($parts[0]); $logType = trim($parts[1]); // np. 'product' $logRef = trim($parts[2]); if ($logDate === $today) { $updatedToday[$logType.'_'.$logRef] = true; } } } } $updatedSomething = false; foreach ($productsBySymbol as $symbol => $products) { if (empty($products)) { continue; } // Główny produkt – referencja z pierwszego elementu grupy // $mainProductData = $products[0]; // $reference = (string)$mainProductData->sku; // $key = 'product_'.$reference; $mainProductData = findMainProductDataFromGroup($products); if (!$mainProductData) { continue; // w grupie nie ma produktu, który istnieje w Presta } $reference = (string)$mainProductData->sku; $key = 'product_'.$reference; // Jeśli już zaktualizowany dzisiaj – pomijamy if (isset($updatedToday[$key])) { continue; } $product = findProductByReference($reference); if (!$product) { // produkt nie istnieje w Presta - pomijamy w trybie update continue; } // BAZA: najtańszy wariant w grupie (brutto i netto) list($grossBase, $netPrice) = getBasePricesFromGroup($products); if ($grossBase <= 0 || $netPrice <= 0) { // brak sensownej ceny – pomiń continue; } // Flagi / liczniki $updatedProductPrice = false; $updatedCombinationCount = 0; // Aktualizacja ceny produktu (NETTO) – baza = najtańszy wariant $product->price = $netPrice; $updatedProductPrice = true; // Produkt zawsze aktywny + delivery times $product->active = 1; $product->delivery_in_stock = createMultiLangField('2-7 dni roboczych'); $product->delivery_out_stock = createMultiLangField('4-10 tygodni'); // Upewnij się, że produkt ma ustawioną grupę VAT 23% if (!empty($idTaxRulesGroup23) && (int)$product->id_tax_rules_group !== (int)$idTaxRulesGroup23) { $product->id_tax_rules_group = (int)$idTaxRulesGroup23; } // Sprawdź kategorię domyślną – jeśli "Strona główna", zamień na "Meble" (ID 107) $id_lang = (int)$context->language->id; $defaultCategory = new Category($product->id_category_default, $id_lang); if (Validate::isLoadedObject($defaultCategory) && $defaultCategory->name == 'Strona główna') { $newCategoryId = 107; // Meble // Ustaw nową kategorię domyślną $product->id_category_default = (int)$newCategoryId; // Podmień kategorie produktu (zachowując ewentualne inne) $categories = $product->getCategories(); $categories = array_diff($categories, [(int)$defaultCategory->id]); $categories[] = (int)$newCategoryId; $categories = array_unique(array_map('intval', $categories)); $product->updateCategories($categories); } // Zapis produktu if ($product->update()) { // --- STANY MAGAZYNOWE PRODUKTU (ID_PRODUCT_ATTRIBUTE = 0) --- $mainStatus = (string)$mainProductData->Status_magazynowy; $mainQty = ($mainStatus === 'instock') ? 100 : 0; StockAvailable::setQuantity($product->id, 0, $mainQty); // --- AKTUALIZACJA CEN I STANÓW KOMBINACJI NA PODSTAWIE XML --- foreach ($products as $productDataVariant) { $variantRef = (string)$productDataVariant->sku; // Szukamy kombinacji po indeksie/SKU $combination = findCombinationByReference($product->id, $variantRef); if (!$combination) { continue; } // Cena brutto wariantu z XML $variantGross = parsePrice((string)$productDataVariant->price); if ($variantGross <= 0) { continue; } // Netto wariantu $variantNet = Tools::ps_round($variantGross / 1.23, 6); // Impact względem ceny bazowej produktu (najtańszy wariant) $impact = $variantNet - $netPrice; // zabezpieczenie na wypadek minimalnych różnic/zaokrągleń if ($impact < 0) { $impact = 0; } $impact = Tools::ps_round($impact, 6); $combination->price = $impact; // Stan magazynowy kombinacji $variantStatus = (string)$productDataVariant->Status_magazynowy; $variantQty = ($variantStatus === 'instock') ? 100 : 0; StockAvailable::setQuantity($product->id, $combination->id, $variantQty); if ($combination->update()) { $updatedCombinationCount++; } } // --- KONIEC AKTUALIZACJI KOMBINACJI --- // Zapis do logu – że ten produkt został dziś zaktualizowany $logLine = $today.';product;'.$reference.';'.$product->id.PHP_EOL; file_put_contents($logFile, $logLine, FILE_APPEND); echo '

Zaktualizowano produkt: '.htmlspecialchars((string)$mainProductData->title).' ('.$reference.')

'; echo '

Nowa bazowa cena brutto (najtańszy wariant) z XML: '.$grossBase.'

'; echo '

Nowa cena netto produktu (bazowa) w Presta: '.$netPrice.'

'; // INFO: czy zaktualizowano cenę produktu if ($updatedProductPrice) { echo '

Cena produktu została zaktualizowana.

'; } else { echo '

Cena produktu nie uległa zmianie.

'; } // INFO: ile kombinacji zaktualizowano if ($updatedCombinationCount > 0) { echo '

Zaktualizowano ceny/ilości kombinacji: '.$updatedCombinationCount.' szt.

'; } else { echo '

Nie zaktualizowano żadnej kombinacji (brak dopasowanych SKU albo cen).

'; } $updatedSomething = true; } // Aktualizujemy tylko jeden produkt na jedno wywołanie break; } if ($updatedSomething) { // echo ''; } else { echo '

Brak produktów do aktualizacji na dzisiaj (wszystkie z XML zostały już zaktualizowane).

'; } exit; } // ======================================= // =========== TRYB DODAWANIA ============ // ======================================= if ($modeAdd) { $productAdded = false; $combinationAdded = false; // Tworzenie lub aktualizacja produktów z kombinacjami (dodawanie) foreach ($productsBySymbol as $symbol => $products) { if (empty($products)) { continue; } // ===== Filter item_group_id ===== // $mainProductDataTemp = $products[0]; // if ((string)$mainProductDataTemp->item_group_id !== '68590') { // continue; // } // Główny produkt – wybieramy deterministycznie $mainProductData = findMainProductDataFromGroup($products); if (!$mainProductData) { // fallback: jeśli żaden nie istnieje, wybierz alfabetycznie najniższy SKU usort($products, function($a, $b) { return strcmp((string)$a->sku, (string)$b->sku); }); $mainProductData = $products[0]; } $mainProduct = findProductByReference((string)$mainProductData->sku); // BAZA: najtańszy wariant w grupie (brutto i netto) list($grossBase, $netPrice) = getBasePricesFromGroup($products); if (!$mainProduct) { // Create a new product if it doesn't exist $mainProduct = new Product(); $mainProduct->name = createMultiLangField((string)$mainProductData->title); $description = (string)$mainProductData->description; $description = str_replace("\n", "
", $description); $mainProduct->description = createMultiLangField($description); // Cena BRUTTO z XML -> NETTO (23%) – bazą jest najtańszy wariant $mainProduct->price = $netPrice > 0 ? $netPrice : 0; // VAT 23% jeśli dostępny $mainProduct->id_tax_rules_group = 8; // Produkt aktywny + delivery times $mainProduct->active = 1; $mainProduct->delivery_in_stock = createMultiLangField('2-7 dni roboczych'); $mainProduct->delivery_out_stock = createMultiLangField('4-10 tygodni'); $mainProduct->reference = (string)$mainProductData->sku; $mainProduct->id_category_default = 107; // np. Meble $mainProduct->link_rewrite = createLinkRewrite((string)$mainProductData->title); // Najpierw dodaj produkt $mainProduct->add(); $mainProduct = new Product($mainProduct->id); $mainProduct->id_tax_rules_group = 8; $mainProduct->update(); // ===== Poprawne przypisanie kategorii ===== $id_lang = (int)$context->language->id; $defaultCategory = new Category($mainProduct->id_category_default, $id_lang); if (Validate::isLoadedObject($defaultCategory) && $defaultCategory->name == 'Strona główna') { $newCategoryId = 107; // Meble $mainProduct->id_category_default = (int)$newCategoryId; // Podmieniamy kategorie produktu (zachowując inne) $categories = $mainProduct->getCategories(); $categories = array_diff($categories, [(int)$defaultCategory->id]); $categories[] = (int)$newCategoryId; $categories = array_unique(array_map('intval', $categories)); $mainProduct->updateCategories($categories); } // ===== Koniec ustawienia kategorii ===== // Add images to the product $imageUrls = getAllImageUrlsFromXmlProduct($mainProductData, 10); $first = true; foreach ($imageUrls as $url) { addProductImage($mainProduct->id, $url, $first); $first = false; } $productAdded = true; } // Ensure the product is saved before adding combinations if (!$mainProduct->id) { echo "Failed to create or update main product: " . (string)$mainProductData->title . "\n"; continue; } // Ensure the combination set is unique for the product $addedCombinations = []; // Add or update combinations for each product in the group foreach ($products as $productData) { $attributes = [ 'Kolor' => (string)$productData->Kolor, 'Długość' => (string)$productData->Dlugosc, 'Szerokość' => (string)$productData->Szerokosc, 'Głębokość' => (string)$productData->Glebokosc, 'Wysokość' => (string)$productData->Wysokosc, ]; $attributeIds = []; foreach ($attributes as $name => $value) { if (!empty($value)) { $attributeGroupId = createAttribute($name, [$value]); $attribute = findAttributeByName($attributeGroupId, $value); if ($attribute) { $attributeIds[] = (int)$attribute->id; } } } // Create a unique key for the attribute set sort($attributeIds); $key = implode('-', $attributeIds); // Add or update combination if it is unique if (!empty($attributeIds) && !isset($addedCombinations[$key])) { $combination = findCombinationByAttributes($mainProduct->id, $attributeIds); // Oblicz cenę wariantu $variantGross = parsePrice((string)$productData->price); $variantNet = $variantGross > 0 ? Tools::ps_round($variantGross / 1.23, 6) : 0; // Impact względem ceny bazowej produktu $impact = $variantNet - $netPrice; if ($impact < 0) { $impact = 0; // zabezpieczenie } $impact = Tools::ps_round($impact, 6); if (!$combination) { // Create new combination $combination = new Combination(); $combination->id_product = (int)$mainProduct->id; $combination->quantity = 100; // startowo, i tak zaraz nadpiszemy StockAvailable $combination->reference = (string)$productData->sku; $combination->price = $impact; // wpływ na cenę (tax excluded) $combination->ecotax = 0; $combination->wholesale_price = 0; $combination->default_on = 0; $combination->add(); $combination->setAttributes($attributeIds); // Dodatkowy update aby upewnić się że cena jest prawidłowo zapisana $combination->price = $impact; $combination->update(); $combinationAdded = true; } else { // Update existing combination $combination->quantity = 100; // startowo $combination->price = $impact; // aktualizacja ceny $combination->update(); } // Mark this combination as added $addedCombinations[$key] = true; } if ($combinationAdded) { break; // Break if a new combination was added } } // --- STANY MAGAZYNOWE PRODUKTU (ID_PRODUCT_ATTRIBUTE = 0) --- $mainStatus = (string)$mainProductData->Status_magazynowy; $mainQty = ($mainStatus === 'instock') ? 100 : 0; StockAvailable::setQuantity($mainProduct->id, 0, $mainQty); // --- STANY MAGAZYNOWE KOMBINACJI --- foreach ($products as $productDataVariant) { $variantRef = (string)$productDataVariant->sku; $variantStatus = (string)$productDataVariant->Status_magazynowy; $variantQty = ($variantStatus === 'instock') ? 100 : 0; $combination = findCombinationByReference($mainProduct->id, $variantRef); if ($combination) { StockAvailable::setQuantity($mainProduct->id, $combination->id, $variantQty); } } // Ensure the product has combinations enabled $mainProduct->checkDefaultAttributes(); Product::updateDefaultAttribute($mainProduct->id); // Upewnij się że produkt główny ma poprawne ustawienie VAT po dodaniu kombinacji if ($productAdded || $combinationAdded) { $mainProduct = new Product($mainProduct->id); // Przeładuj produkt if (!empty($idTaxRulesGroup23) && (int)$mainProduct->id_tax_rules_group !== (int)$idTaxRulesGroup23) { $mainProduct->id_tax_rules_group = (int)$idTaxRulesGroup23; $mainProduct->update(); } } if ($productAdded || $combinationAdded) { if ($productAdded) { echo "

Dodałem produkt: " . htmlspecialchars((string)$mainProductData->title) . "

"; } if ($combinationAdded) { echo "

Dodałem kombinację: " . htmlspecialchars((string)$mainProductData->title) . "

"; } break; // Break if a new product or combination was added } } echo '

Dodawanie zakończone.

'; exit; } // ======================================= // ========= TRYB SYNCHRONIZACJI ========= // ======================================= if ($modeSynch) { echo '

Rozpoczynam synchronizację produktów...

'; $db = Db::getInstance(); // 1. Wyczyszczenie tymczasowej tabeli $db->execute('TRUNCATE TABLE `'._DB_PREFIX_.'drewmax_products_temp`'); // 1.1 Wczytywanie SKU z XML i dodawanie do tymczasowej tabeli $skusInXml = []; foreach ($xml->product as $productData) { $sku = trim((string)$productData->sku); if ($sku === '') continue; $skusInXml[] = $sku; $db->execute(' INSERT INTO `'._DB_PREFIX_.'drewmax_products_temp` (`sku`, `date_checked`) VALUES (\''.pSQL($sku).'\', NOW()) '); } // 2. Praca z historią if (!empty($skusInXml)) { // Utworzenie listy SKU dla SQL $skusList = "'" . implode("','", array_map('pSQL', $skusInXml)) . "'"; // 2.1 Dodawanie nowych SKU do historii lub przywracanie aktywności $sqlInsert = ' INSERT INTO `'._DB_PREFIX_.'drewmax_products_history` (`sku`, `active`) SELECT t.sku, 1 FROM `'._DB_PREFIX_.'drewmax_products_temp` t LEFT JOIN `'._DB_PREFIX_.'drewmax_products_history` h ON h.sku = t.sku WHERE h.sku IS NULL '; $db->execute($sqlInsert); $sqlUpdateActive = ' UPDATE `'._DB_PREFIX_.'drewmax_products_history` h JOIN `'._DB_PREFIX_.'drewmax_products_temp` t ON h.sku = t.sku SET h.active = 1 WHERE h.active = 0 '; $db->execute($sqlUpdateActive); } // 2.2 Wykluczanie produktów, których nie ma w temp $sqlDeactivate = ' UPDATE `'._DB_PREFIX_.'drewmax_products_history` h LEFT JOIN `'._DB_PREFIX_.'drewmax_products_temp` t ON h.sku = t.sku SET h.active = 0 WHERE t.sku IS NULL AND h.active = 1 '; $db->execute($sqlDeactivate); // Wyłącz produkty w PrestaShop dla SKU, które mają active=0 $skusToDisable = $db->executeS(' SELECT sku FROM `'._DB_PREFIX_.'drewmax_products_history` WHERE active = 0 '); // 3. Synchronizacja statusu produktów i kombinacji w PrestaShop // Pobieramy tylko SKU z historii (źródło prawdy) $allHistory = $db->executeS(' SELECT sku, active FROM `'._DB_PREFIX_.'drewmax_products_history` '); foreach ($allHistory as $row) { $sku = trim($row['sku']); $activeStatus = (int)$row['active']; if ($sku === '') { continue; } /** * KROK 3.1 * Sprawdzenie czy SKU jest GŁÓWNYM PRODUKTEM * (tylko ps_product.reference) */ $idProduct = (int)$db->getValue(' SELECT id_product FROM `'._DB_PREFIX_.'product` WHERE reference = \''.pSQL($sku).'\' LIMIT 1 '); if ($idProduct > 0) { // === GŁÓWNY PRODUKT === $product = new Product($idProduct); if (!Validate::isLoadedObject($product)) { continue; } if ($activeStatus === 0 && (int)$product->active === 1) { // Wyłącz produkt $product->active = 0; $product->update(); echo "Wyłączono PRODUKT: {$sku}
"; } if ($activeStatus === 1 && (int)$product->active === 0) { // Włącz produkt $product->active = 1; $product->update(); echo "Włączono PRODUKT: {$sku}
"; } // Główny produkt obsłużony → NIE sprawdzamy kombinacji continue; } /** * KROK 3.2 * Jeśli NIE jest produktem → sprawdzamy czy to KOMBINACJA */ $combinationRow = $db->getRow(' SELECT id_product_attribute, id_product FROM `'._DB_PREFIX_.'product_attribute` WHERE reference = \''.pSQL($sku).'\' LIMIT 1 '); if ($combinationRow) { // === KOMBINACJA === if ($activeStatus === 0) { $idProductAttribute = (int)$combinationRow['id_product_attribute']; $combination = new Combination($idProductAttribute); if (Validate::isLoadedObject($combination)) { $combination->delete(); echo "Usunięto KOMBINACJĘ: {$sku} (ID: {$idProductAttribute})
"; } } // Jeśli active = 1 → NIC NIE ROBIMY (kombinacji się nie aktywuje) continue; } /** * KROK 3.3 * SKU nie istnieje w PrestaShop → ignorujemy */ } echo '

Synchronizacja zakończona.

'; } // reload page after 250ms if product or combination was added (dla trybu add) if ($productAdded || $combinationAdded) { // echo ""; } ?>