CCCPaste

All active products in prestashop

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 Снимка Име (всички езици) Размери (наличности) Общо наличност Цена (с ДДС)