Add functionality for product update and addition from XML feed

- Implemented URL parameters to switch between add and update modes.
- Enhanced XML loading from a remote URL.
- Added logging for updated products with a daily log file.
- Improved product update logic to change default category if necessary.
- Refactored functions for better readability and performance.
- Ensured proper type casting for database interactions.
- Added functionality to create or update product combinations.
- Improved user feedback with HTML output for added products and combinations.
This commit is contained in:
2025-11-19 20:37:58 +01:00
parent 6ed7882f09
commit 4d03f9c793
2 changed files with 512 additions and 939 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,37 @@
<?php <?php
// https://pacyga.pl/wp-content/uploads/woo-feed/custom/xml/komplet-produktow-3.xml // https://pacyga.pl/wp-content/uploads/woo-feed/custom/xml/komplet-produktow-3.xml
// Include PrestaShop configuration // Include PrestaShop configuration
$config['update_price'] = false;
include(dirname(__FILE__).'/config/config.inc.php'); include(dirname(__FILE__).'/config/config.inc.php');
include(dirname(__FILE__).'/init.php'); include(dirname(__FILE__).'/init.php');
// Load XML file $context = Context::getContext();
$xml = simplexml_load_file('komplet-produktow-3.xml') or die("Error: Cannot create object");
// Sprawdzenie trybu działania na podstawie parametrów URL
$modeAdd = (Tools::getValue('add') === 'true');
$modeUpdate = (Tools::getValue('update') === 'true');
if (!$modeAdd && !$modeUpdate) {
die('Brak akcji. Dodaj do adresu ?add=true lub ?update=true');
}
// Plik logu aktualizacji cen
$logFile = __DIR__ . '/update_price_log.csv';
// Wczytanie XML
$xmlUrl = 'https://pacyga.pl/wp-content/uploads/woo-feed/custom/xml/komplet-produktow-3.xml';
$xml = simplexml_load_file($xmlUrl) or die("Error: Cannot create object");
// === FUNKCJE POMOCNICZE ===
// Function to find attribute group by name // Function to find attribute group by name
function findAttributeGroupByName($name) { function findAttributeGroupByName($name) {
$id_lang = Context::getContext()->language->id; $id_lang = Context::getContext()->language->id;
$result = Db::getInstance()->getRow('SELECT `id_attribute_group` FROM `'._DB_PREFIX_.'attribute_group_lang` WHERE `name` = \''.pSQL($name).'\' AND `id_lang` = '.(int)$id_lang); $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; return $result ? new AttributeGroup($result['id_attribute_group']) : false;
} }
@@ -20,8 +40,11 @@ function findAttributeByName($id_attribute_group, $name) {
$id_lang = Context::getContext()->language->id; $id_lang = Context::getContext()->language->id;
$sql = 'SELECT a.`id_attribute` $sql = 'SELECT a.`id_attribute`
FROM `'._DB_PREFIX_.'attribute` a FROM `'._DB_PREFIX_.'attribute` a
JOIN `'._DB_PREFIX_.'attribute_lang` al ON a.`id_attribute` = al.`id_attribute` JOIN `'._DB_PREFIX_.'attribute_lang` al
WHERE al.`name` = \''.pSQL($name).'\' AND al.`id_lang` = '.(int)$id_lang.' AND a.`id_attribute_group` = '.(int)$id_attribute_group; 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); $result = Db::getInstance()->getRow($sql);
return $result ? new Attribute($result['id_attribute']) : false; return $result ? new Attribute($result['id_attribute']) : false;
} }
@@ -55,7 +78,7 @@ function createMultiLangField($field) {
$languages = Language::getLanguages(false); $languages = Language::getLanguages(false);
$res = []; $res = [];
foreach ($languages as $lang) { foreach ($languages as $lang) {
$res[$lang['id_lang']] = $field; $res[(int)$lang['id_lang']] = $field;
} }
return $res; return $res;
} }
@@ -66,16 +89,16 @@ function createLinkRewrite($field) {
$res = []; $res = [];
$linkRewrite = Tools::link_rewrite($field); // PrestaShop's function to create valid link_rewrite $linkRewrite = Tools::link_rewrite($field); // PrestaShop's function to create valid link_rewrite
foreach ($languages as $lang) { foreach ($languages as $lang) {
$res[$lang['id_lang']] = $linkRewrite; $res[(int)$lang['id_lang']] = $linkRewrite;
} }
return $res; return $res;
} }
// Function to get category ID from name // Function to get category ID from name (nieużywana, ale poprawiona)
function getCategoryId($categoryName) { function getCategoryId($categoryName) {
$category = Category::searchByName(1, $categoryName); // 1 for default language id $result = Category::searchByName(1, $categoryName); // 1 for default language id
if (!empty($category)) { if (!empty($result) && isset($result[0]['id_category'])) {
return $category['id_category']; return (int)$result[0]['id_category'];
} else { } else {
// Create category if not exists // Create category if not exists
$category = new Category(); $category = new Category();
@@ -83,7 +106,7 @@ function getCategoryId($categoryName) {
$category->link_rewrite = createLinkRewrite($categoryName); $category->link_rewrite = createLinkRewrite($categoryName);
$category->id_parent = 2; // Default parent category $category->id_parent = 2; // Default parent category
$category->add(); $category->add();
return $category->id; return (int)$category->id;
} }
} }
@@ -91,7 +114,7 @@ function getCategoryId($categoryName) {
function addProductImage($productId, $imageUrl) function addProductImage($productId, $imageUrl)
{ {
$image = new Image(); $image = new Image();
$image->id_product = $productId; $image->id_product = (int)$productId;
$image->position = Image::getHighestPosition($productId) + 1; $image->position = Image::getHighestPosition($productId) + 1;
$image->cover = true; // Set the first image as cover $image->cover = true; // Set the first image as cover
$image->add(); $image->add();
@@ -105,7 +128,12 @@ function addProductImage($productId, $imageUrl)
$imageTypes = ImageType::getImagesTypes('products'); $imageTypes = ImageType::getImagesTypes('products');
foreach ($imageTypes as $imageType) { foreach ($imageTypes as $imageType) {
ImageManager::resize($imagePath . '.jpg', $imagePath . '-' . stripslashes($imageType['name']) . '.jpg', $imageType['width'], $imageType['height']); ImageManager::resize(
$imagePath . '.jpg',
$imagePath . '-' . stripslashes($imageType['name']) . '.jpg',
(int)$imageType['width'],
(int)$imageType['height']
);
} }
return true; return true;
@@ -113,24 +141,38 @@ function addProductImage($productId, $imageUrl)
// Function to find product by reference // Function to find product by reference
function findProductByReference($reference) { function findProductByReference($reference) {
$result = Db::getInstance()->getRow('SELECT `id_product` FROM `'._DB_PREFIX_.'product` WHERE `reference` = \''.pSQL($reference).'\''); $sql = 'SELECT `id_product`
return $result ? new Product($result['id_product']) : false; 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 to find combination by product ID and attribute IDs
function findCombinationByAttributes($id_product, $attributeIds) { function findCombinationByAttributes($id_product, $attributeIds) {
if (empty($attributeIds)) {
return false;
}
sort($attributeIds); sort($attributeIds);
$conditions = [];
foreach ($attributeIds as $id_attr) {
$conditions[] = 'pac.`id_attribute` = '.(int)$id_attr;
}
$sql = 'SELECT c.`id_product_attribute` $sql = 'SELECT c.`id_product_attribute`
FROM `'._DB_PREFIX_.'product_attribute` c FROM `'._DB_PREFIX_.'product_attribute` c
JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON c.`id_product_attribute` = pac.`id_product_attribute` JOIN `'._DB_PREFIX_.'product_attribute_combination` pac
ON c.`id_product_attribute` = pac.`id_product_attribute`
WHERE c.`id_product` = '.(int)$id_product.' WHERE c.`id_product` = '.(int)$id_product.'
GROUP BY c.`id_product_attribute` GROUP BY c.`id_product_attribute`
HAVING SUM(pac.`id_attribute` = '.implode(' OR pac.`id_attribute` = ', array_map('intval', $attributeIds)).') = '.count($attributeIds); HAVING SUM('.implode(' OR ', $conditions).') = '.count($attributeIds);
$result = Db::getInstance()->getRow($sql); $result = Db::getInstance()->getRow($sql);
return $result ? new Combination($result['id_product_attribute']) : false; return $result ? new Combination((int)$result['id_product_attribute']) : false;
} }
// Parse XML and group products by Symbol // === GRUPOWANIE PRODUKTÓW PO SYMBOLU ===
$productsBySymbol = []; $productsBySymbol = [];
foreach ($xml->product as $productData) { foreach ($xml->product as $productData) {
$symbol = (string)$productData->item_group_id; $symbol = (string)$productData->item_group_id;
@@ -140,7 +182,117 @@ foreach ($xml->product as $productData) {
$productsBySymbol[$symbol][] = $productData; $productsBySymbol[$symbol][] = $productData;
} }
// Create or update products with combinations based on grouped data // =======================================
// =========== TRYB AKTUALIZACJI =========
// =======================================
if ($modeUpdate) {
$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;
// 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;
}
// Nowa cena z XML
$newPrice = floatval(str_replace(',', '', (string)$mainProductData->price));
if ($newPrice <= 0) {
// brak sensownej ceny pomiń
continue;
}
// Aktualizacja ceny produktu
$product->price = $newPrice;
// 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();
// Usuń starą kategorię domyślną, jeśli istnieje w tablicy
$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()) {
// 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 '<p>Zaktualizowano produkt: '.htmlspecialchars((string)$mainProductData->title).' ('.$reference.')</p>';
echo '<p>Nowa cena: '.$newPrice.'</p>';
$updatedSomething = true;
}
// Aktualizujemy tylko jeden produkt na jedno wywołanie
break;
}
if ($updatedSomething) {
// Odśwież stronę, żeby przy kolejnym wywołaniu zaktualizować następny produkt
echo '<script>setTimeout(function(){ location.reload(); }, 250);</script>';
} else {
echo '<p>Brak produktów do aktualizacji na dzisiaj (wszystkie z XML zostały już zaktualizowane).</p>';
}
exit;
}
// =======================================
// =========== TRYB DODAWANIA ============
// =======================================
$productAdded = false;
$combinationAdded = false;
// Tworzenie lub aktualizacja produktów z kombinacjami (dodawanie)
foreach ($productsBySymbol as $symbol => $products) { foreach ($productsBySymbol as $symbol => $products) {
if (empty($products)) { if (empty($products)) {
continue; continue;
@@ -150,23 +302,24 @@ foreach ($productsBySymbol as $symbol => $products) {
$mainProductData = $products[0]; $mainProductData = $products[0];
$mainProduct = findProductByReference((string)$mainProductData->sku); $mainProduct = findProductByReference((string)$mainProductData->sku);
$productAdded = false;
if (!$mainProduct) { if (!$mainProduct) {
// Create a new product if it doesn't exist // Create a new product if it doesn't exist
$mainProduct = new Product(); $mainProduct = new Product();
$mainProduct->name = createMultiLangField((string)$mainProductData->title); $mainProduct->name = createMultiLangField((string)$mainProductData->title);
$description = (string)$mainProductData->description; $description = (string)$mainProductData->description;
$description = str_replace("\n", "<br>", $description); $description = str_replace("\n", "<br>", $description);
$mainProduct->description = createMultiLangField($description); $mainProduct->description = createMultiLangField($description);
$mainProduct->price = floatval(str_replace(',','',$mainProductData->price));
$mainProduct->price = floatval(str_replace(',', '', (string)$mainProductData->price));
$mainProduct->reference = (string)$mainProductData->sku; $mainProduct->reference = (string)$mainProductData->sku;
$mainProduct->id_category_default = 2; $mainProduct->id_category_default = 2; // np. Strona główna
$mainProduct->link_rewrite = createLinkRewrite((string)$mainProductData->title); $mainProduct->link_rewrite = createLinkRewrite((string)$mainProductData->title);
$mainProduct->add(); $mainProduct->add();
// Add images to the product // Add images to the product
if (!empty($mainProductData->image)) { if (!empty($mainProductData->image)) {
addProductImage($mainProduct->id, $mainProductData->image); addProductImage($mainProduct->id, (string)$mainProductData->image);
} }
for ($i = 1; $i <= 10; $i++) { for ($i = 1; $i <= 10; $i++) {
@@ -177,15 +330,6 @@ foreach ($productsBySymbol as $symbol => $products) {
} }
$productAdded = true; $productAdded = true;
} else {
// Update existing product price and description
if ( $config['update_price'] == true ) {
$mainProduct->price = floatval(str_replace(',','',$mainProductData->price));
$description = (string)$mainProductData->description;
$description = str_replace("\n", "<br>", $description);
$mainProduct->description = createMultiLangField($description);
$mainProduct->update();
}
} }
// Ensure the product is saved before adding combinations // Ensure the product is saved before adding combinations
@@ -198,14 +342,13 @@ foreach ($productsBySymbol as $symbol => $products) {
$addedCombinations = []; $addedCombinations = [];
// Add or update combinations for each product in the group // Add or update combinations for each product in the group
$combinationAdded = false;
foreach ($products as $productData) { foreach ($products as $productData) {
$attributes = [ $attributes = [
'Kolor' => (string)$productData->Kolor, 'Kolor' => (string)$productData->Kolor,
'Dlugosc' => (string)$productData->Dlugosc, 'Dlugosc' => (string)$productData->Dlugosc,
'Szerokosc' => (string)$productData->Szerokosc, 'Szerokosc' => (string)$productData->Szerokosc,
'Glebokosc' => (string)$productData->Glebokosc, 'Glebokosc' => (string)$productData->Glebokosc,
'Wysokosc' => (string)$productData->Wysokosc, 'Wysokosc' => (string)$productData->Wysokosc,
]; ];
$attributeIds = []; $attributeIds = [];
@@ -214,7 +357,7 @@ foreach ($productsBySymbol as $symbol => $products) {
$attributeGroupId = createAttribute($name, [$value]); $attributeGroupId = createAttribute($name, [$value]);
$attribute = findAttributeByName($attributeGroupId, $value); $attribute = findAttributeByName($attributeGroupId, $value);
if ($attribute) { if ($attribute) {
$attributeIds[] = $attribute->id; $attributeIds[] = (int)$attribute->id;
} }
} }
} }
@@ -224,12 +367,12 @@ foreach ($productsBySymbol as $symbol => $products) {
$key = implode('-', $attributeIds); $key = implode('-', $attributeIds);
// Add or update combination if it is unique // Add or update combination if it is unique
if (!empty($attributeIds)) { if (!empty($attributeIds) && !isset($addedCombinations[$key])) {
$combination = findCombinationByAttributes($mainProduct->id, $attributeIds); $combination = findCombinationByAttributes($mainProduct->id, $attributeIds);
if (!$combination) { if (!$combination) {
// Create new combination // Create new combination
$combination = new Combination(); $combination = new Combination();
$combination->id_product = $mainProduct->id; $combination->id_product = (int)$mainProduct->id;
$combination->quantity = 100; // Default quantity, you can adjust this $combination->quantity = 100; // Default quantity, you can adjust this
$combination->reference = (string)$productData->sku; $combination->reference = (string)$productData->sku;
$combination->add(); $combination->add();
@@ -256,18 +399,19 @@ foreach ($productsBySymbol as $symbol => $products) {
Product::updateDefaultAttribute($mainProduct->id); Product::updateDefaultAttribute($mainProduct->id);
if ($productAdded || $combinationAdded) { if ($productAdded || $combinationAdded) {
if ($productAdded) { if ($productAdded) {
echo "<p>Dodałem produkt: " . (string)$mainProductData->title . "</p>"; echo "<p>Dodałem produkt: " . htmlspecialchars((string)$mainProductData->title) . "</p>";
} }
if ($combinationAdded) { if ($combinationAdded) {
echo "<p>Dodałem kombinację: " . (string)$mainProductData->title . "</p>"; echo "<p>Dodałem kombinację: " . htmlspecialchars((string)$mainProductData->title) . "</p>";
} }
break; // Break if a new product or combination was added break; // Break if a new product or combination was added
} }
} }
// reload page after 1s if product or combination was added
// reload page after 250ms if product or combination was added (dla trybu add)
if ($productAdded || $combinationAdded) { if ($productAdded || $combinationAdded) {
echo "<script>setTimeout(function(){location.reload();}, 250);</script>"; echo "<script>setTimeout(function(){location.reload();}, 250);</script>";
} }
?> ?>