controller) { $context->controller = new FrontController(); $context->controller->init(); } } // Гарантиране на shop контекст if (Shop::isFeatureActive()) { if (!Shop::getContext()) { Shop::setContext(Shop::CONTEXT_SHOP, (int)Configuration::get('PS_SHOP_DEFAULT')); } } } catch (Exception $e) { http_response_code(500); header('Content-Type: application/json; charset=utf-8'); echo json_encode(array('error' => 'PrestaShop initialization failed: ' . $e->getMessage())); exit; } // ---------- ГАРАНТИРАН КОНТЕКСТ ---------- $context = Context::getContext(); // Shop if (!$context->shop || !(int)$context->shop->id) { $idShop = (int)Configuration::get('PS_SHOP_DEFAULT'); if ($idShop) { $context->shop = new Shop($idShop); Shop::setContext(Shop::CONTEXT_SHOP, $idShop); } } // Language if (!$context->language || !(int)$context->language->id) { $idLang = (int)Configuration::get('PS_LANG_DEFAULT'); if ($idLang) $context->language = new Language($idLang); } // Currency if (!$context->currency || !(int)$context->currency->id) { $idCur = (int)Configuration::get('PS_CURRENCY_DEFAULT'); if ($idCur) $context->currency = new Currency($idCur); } // Country if (!$context->country || !(int)$context->country->id) { $idCountry = (int)Configuration::get('PS_COUNTRY_DEFAULT'); if ($idCountry) $context->country = new Country($idCountry); } $link = $context->link; // ---------- ПОМОЩНИ ФУНКЦИИ ---------- function ps_get_active_languages() { static $langs = null; if ($langs === null) { $langs = Language::getLanguages(true, Context::getContext()->shop->id); } return $langs; } function ps_currency() { static $cur = null; if ($cur === null) { $defaultId = (int)Configuration::get('PS_CURRENCY_DEFAULT'); $cur = new Currency($defaultId); } return $cur; } // Активни продукти (ID desc) function ps_fetch_active_products($offset=0, $limit=100000) { $sql = (new DbQuery()) ->select('p.id_product, p.reference') ->from('product', 'p') ->innerJoin('product_shop', 'ps', 'p.id_product = ps.id_product AND ps.id_shop = '.(int)Context::getContext()->shop->id) ->where('ps.active = 1') ->orderBy('p.id_product DESC') ->limit((int)$limit, (int)$offset); $rows = Db::getInstance()->executeS($sql); return $rows ? $rows : array(); } // Имена и link_rewrite за всички активни езици function ps_fetch_names_for_product($id_product) { $langs = ps_get_active_languages(); $ids = array(); foreach ($langs as $l) $ids[] = (int)$l['id_lang']; if (!$ids) return array(); $sql = (new DbQuery()) ->select('pl.id_lang, pl.name, pl.link_rewrite') ->from('product_lang', 'pl') ->where('pl.id_product='.(int)$id_product) ->where('pl.id_shop='.(int)Context::getContext()->shop->id) ->where('pl.id_lang IN ('.implode(',', $ids).')'); $rows = Db::getInstance()->executeS($sql); $out = array(); if ($rows) { foreach ($rows as $r) { $out[(int)$r['id_lang']] = array( 'name' => $r['name'], 'link_rewrite' => $r['link_rewrite'], ); } } return $out; } // id на кавър изображението function ps_cover_image_id($id_product) { $cover = Image::getCover($id_product); if ($cover && !empty($cover['id_image'])) return (int)$cover['id_image']; return null; } // URL за миниатюра + URL към продукта function ps_image_and_product_links($id_product, $namesByLang, $link) { $langs = ps_get_active_languages(); $firstLangId = (int)$langs[0]['id_lang']; $linkRewrite = isset($namesByLang[$firstLangId]['link_rewrite']) ? $namesByLang[$firstLangId]['link_rewrite'] : 'product'; $coverId = ps_cover_image_id($id_product); // Определяне на типа изображение $thumbType = 'home_default'; if (class_exists('ImageType')) { if (method_exists('ImageType','getFormattedName')) { $thumbType = ImageType::getFormattedName('home'); } elseif (method_exists('ImageType','getFormatedName')) { $thumbType = ImageType::getFormatedName('home'); } } $imgUrl = $coverId ? $link->getImageLink($linkRewrite, $coverId, $thumbType) : null; $productUrl = $link->getProductLink($id_product, $linkRewrite, null, null, $firstLangId); return array($imgUrl, $productUrl); } // Наличности по комбинации function ps_sizes_and_qty($id_product) { $langs = ps_get_active_languages(); $id_lang = (int)$langs[0]['id_lang']; $prod = new Product($id_product, false, $id_lang, Context::getContext()->shop->id); $combs = $prod->getAttributeCombinations($id_lang); if (!$combs) $combs = array(); $byAttr = array(); foreach ($combs as $c) { $ipa = (int)$c['id_product_attribute']; if (!isset($byAttr[$ipa])) $byAttr[$ipa] = array('attrs'=>array(), 'ipa'=>$ipa); $gname = isset($c['group_name']) ? mb_strtolower($c['group_name']) : ''; $aname = isset($c['attribute_name']) ? $c['attribute_name'] : ''; $byAttr[$ipa]['attrs'][] = array('group'=>$gname, 'name'=>$aname); } $preferSize = array(); foreach ($byAttr as $ipa => $data) { foreach ($data['attrs'] as $a) { if (preg_match('/(size|размер)/iu', $a['group'])) { $preferSize[$ipa] = true; break; } } } $rows = array(); foreach ($byAttr as $ipa => $data) { $qty = (int)StockAvailable::getQuantityAvailableByProduct($id_product, $ipa, (int)Context::getContext()->shop->id); $sizeLabel = null; if (!empty($preferSize[$ipa])) { foreach ($data['attrs'] as $a) { if (preg_match('/(size|размер)/iu', $a['group'])) { $sizeLabel = $a['name']; break; } } } if ($sizeLabel === null) { $parts = array(); foreach ($data['attrs'] as $a) { $parts[] = $a['name']; } $sizeLabel = implode(' / ', $parts); } $rows[] = array('label'=>$sizeLabel, 'qty'=>$qty); } $withStock = array(); foreach ($rows as $r) { if ($r['qty'] > 0) $withStock[] = $r; } return $withStock ? $withStock : $rows; } // Общо наличност function ps_total_qty($id_product) { return (int)StockAvailable::getQuantityAvailableByProduct($id_product, 0, (int)Context::getContext()->shop->id); } // Цени function ps_prices($id_product) { $ctx = Context::getContext(); $idShop = (int)$ctx->shop->id; $idCur = (int)$ctx->currency->id; // Базова цена от product_shop $q = new DbQuery(); $q->select('ps.price') ->from('product_shop', 'ps') ->where('ps.id_product='.(int)$id_product) ->where('ps.id_shop='.(int)$idShop); $row = Db::getInstance()->getRow($q); $base = $row ? (float)$row['price'] : 0.0; // Търсене на специфични цени $now = date('Y-m-d H:i:s'); $spQ = new DbQuery(); $spQ->select('reduction, reduction_type') ->from('specific_price', 'sp') ->where('sp.id_product='.(int)$id_product) ->where('sp.id_shop IN (0,'.(int)$idShop.')') ->where('sp.id_currency IN (0,'.(int)$idCur.')') ->where('sp.id_country IN (0,'.(int)$ctx->country->id.')') ->where('sp.id_group = 0') ->where('sp.id_customer = 0') ->where('(sp.from = "0000-00-00 00:00:00" OR sp.from <= "'.$now.'")') ->where('(sp.to = "0000-00-00 00:00:00" OR sp.to >= "'.$now.'")') ->orderBy('sp.id_specific_price DESC'); $sp = Db::getInstance()->getRow($spQ); $current = $base; if ($sp && (float)$sp['reduction'] > 0) { if ($sp['reduction_type'] === 'percentage') { $current = $base * (1.0 - (float)$sp['reduction']); } else { // amount $current = $base - (float)$sp['reduction']; } if ($current < 0) $current = 0.0; } // ДОБАВЕТЕ ТУК УМНОЖЕНИЕТО С 1.2 ЗА ДДС $base_with_vat = $base * 1.2; $current_with_vat = $current * 1.2; return array((float)$base, (float)$current); } // Форматиране на цена function ps_fmt_price($price) { // Добавяне на ДДС $price_with_vat = $price * 1.2; return Tools::displayPrice($price, ps_currency()); } // Събиране на данните function ps_collect_data() { $products = ps_fetch_active_products(0, 100000); $langs = ps_get_active_languages(); $out = array(); foreach ($products as $p) { $id = (int)$p['id_product']; $ref = $p['reference']; $names = ps_fetch_names_for_product($id); list($imgUrl, $pUrl) = ps_image_and_product_links($id, $names, Context::getContext()->link); // Имена за всички активни езици $nameParts = array(); foreach ($langs as $l) { $id_lang = (int)$l['id_lang']; $iso = $l['iso_code']; $nm = isset($names[$id_lang]['name']) ? $names[$id_lang]['name'] : ''; if ($nm !== '') { $nameParts[] = '

['.$iso.'] '.$nm.'

'; } } $namesAll = implode("\n", $nameParts); // Размери + количества $sizes = ps_sizes_and_qty($id); $sizeParts = array(); foreach ($sizes as $s) { $label = isset($s['label']) ? $s['label'] : ''; $qty = isset($s['qty']) ? (int)$s['qty'] : 0; $sizeParts[] = $label . ': ' . $qty; } $sizesStr = implode("\n", $sizeParts); $totalQty = ps_total_qty($id); list($base, $curr) = ps_prices($id); // ДОБАВЕТЕ ДДС ТУК ДИРЕКТНО $base_with_vat = $base * 1.2; $curr_with_vat = $curr * 1.2; $out[] = array( 'id' => $id, 'reference' => $ref, 'image' => $imgUrl, 'plink' => $pUrl, 'names' => $namesAll, 'sizes' => $sizesStr, 'total' => $totalQty, 'base' => ps_fmt_price($base * 1.2), //Това умножение по 1,2 се прави за да показва цената с ДДС 'current' => ps_fmt_price($curr * 1.2), //Това умножение по 1,2 се прави за да показва цената с ДДС 'has_disc' => ($curr < $base) ? 1 : 0, //'disc_percent' => ($base > 0 && $curr < $base) ? (int)round((($base - $curr) / $base) * 100) : 0, 'disc_percent' => ($base > 0 && $curr < $base) ? (int) round((($base - $curr) / $base) * 100) : 0, ); } return $out; } // ---------- РЕЖИМИ (AJAX/EXPORT/VIEW) ---------- if (isset($_GET['action']) && $_GET['action'] === 'data') { header('Content-Type: application/json; charset=utf-8'); try { $data = ps_collect_data(); echo json_encode(array('data'=>$data), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } catch (Exception $e) { echo json_encode(array('error'=>'Грешка при събиране на данни: ' . $e->getMessage())); } exit; } // Експорт към Excel (CSV UTF-8 BOM) if (isset($_GET['export']) && $_GET['export'] === '1') { try { $rows = ps_collect_data(); $filename = 'products_export_' . date('Ymd_His') . '.csv'; header('Content-Type: text/csv; charset=utf-8'); header('Content-Disposition: attachment; filename="' . $filename . '"'); echo "\xEF\xBB\xBF"; $out = fopen('php://output', 'w'); fputcsv($out, array( 'ID','Reference','Product URL','Image URL','Names (all languages)', 'Sizes (qty)','Total Qty','Base Price','Current Price','Discount %', ), ';'); foreach ($rows as $r) { fputcsv($out, array( $r['id'], $r['reference'], $r['plink'], $r['image'], preg_replace("/\r?\n/", ' | ', $r['names']), preg_replace("/\r?\n/", ' | ', $r['sizes']), $r['total'], $r['base'], $r['current'], ($r['disc_percent'] > 0 ? ('-' . $r['disc_percent'] . '%') : ''), ), ';'); } fclose($out); } catch (Exception $e) { header('Content-Type: text/plain; charset=utf-8'); echo 'Грешка при експорт: ' . $e->getMessage(); } exit; } ?> Активни продукти – репорт

Активни продукти / Неактивни с наличност за продажба!

Зареждане на данни…
Може да отнеме малко време при много продукти.
ID Ref Снимка Име (всички езици) Размери (наличности) Общо наличност Цена (с ДДС)