Current File : /var/www/vinorea/modules/ipexportimport/classes/export/EIACombinationsExport.php
<?php
/**
 *
 * NOTICE OF LICENSE
 *
 *  @author    SmartPresta <tehran.alishov@gmail.com>
 *  @copyright 2024 SmartPresta
 *  @license   http://opensource.org/licenses/afl-3.0.php Commercial License!
 */

if (!defined('_PS_VERSION_')) {
    exit;
}

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

class EIACombinationsExport extends EIAExport
{
    protected $xmlMainTag = 'Combination';
    protected $xmlMainTagPl = 'Combinations';

    public function __construct($module)
    {
        parent::__construct($module);
        $this->entityNamePl = $module->l('Combinations', 'EIACombinationsExport');
    }

    private function getImageLink($id_image)
    {
        $theme = Shop::isFeatureActive() && file_exists(_PS_PROD_IMG_DIR_ . Image::getImgFolderStatic($id_image) . $id_image . '-' . (int) Context::getContext()->shop->id_theme . '.jpg') ? '-' . Context::getContext()->shop->id_theme : '';
        $uri_path = _THEME_PROD_DIR_ . Image::getImgFolderStatic($id_image) . $id_image . $theme . '.jpg';
        return $this->context->link->protocol_content . Tools::getMediaServer($uri_path) . $uri_path;
    }

    protected function getDataFromDb()
    {
        // Columns that do not exist directly in the DB
        $absentColumns = array(
            'image_urls' => 'image.ids'
        );

        $low = !empty(Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS("SHOW COLUMNS FROM `" . _DB_PREFIX_ . "product_attribute_shop` LIKE 'low_stock_threshold'"));
        $newColumns = [
            'combination.isbn' => !empty(Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS("SHOW COLUMNS FROM `" . _DB_PREFIX_ . "product_attribute` LIKE 'isbn'")),
            'combination.mpn' => !empty(Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS("SHOW COLUMNS FROM `" . _DB_PREFIX_ . "product_attribute` LIKE 'mpn'")),
            'combination_shop.low_stock_threshold' => $low,
            'combination_shop.low_stock_alert' => $low,
            'stock_available.physical_quantity' => !empty(Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS("SHOW COLUMNS FROM `" . _DB_PREFIX_ . "stock_available` LIKE 'physical_quantity'")),
            'stock_available.reserved_quantity' => !empty(Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS("SHOW COLUMNS FROM `" . _DB_PREFIX_ . "stock_available` LIKE 'reserved_quantity'")),
            'stock_available.location' => !empty(Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS("SHOW COLUMNS FROM `" . _DB_PREFIX_ . "stock_available` LIKE 'location'")),
        ];

        if ($this->auto) {
            $combinations = pSQL(implode(',', $this->datatables['combinations']['data']));
            $combinationsType = $this->datatables['combinations']['type'];

            $quantityOperator = pSQL($this->inputs['quantity_operator']);
            $quantity = (int) $this->inputs['quantity'];
            
            $categories = $this->inputs['categories'];
            $filterCategories = $this->inputs['category_whether_filter'];
            $categories_without = $this->inputs['category_without'];

            $attributes = pSQL(implode(',', $this->datatables['attributes']['data']));
            $attributesType = $this->datatables['attributes']['type'];
            
            $discount = $this->inputs['discount'];
        } else {            
            $combinations = pSQL(Tools::getValue('combinations_data'));
            $combinationsType = Tools::getValue('combinations_type');

            $quantityOperator = pSQL(Tools::getValue('quantity_operator'));
            $quantity = (int) Tools::getValue('quantity');
            
            $categories = Tools::getValue('categories');
            $filterCategories = Tools::getValue('category_whether_filter');
            $categories_without = Tools::getValue('category_without');

            $attributes = pSQL(Tools::getValue('attributes_data'));
            $attributesType = Tools::getValue('attributes_type');
            
            $discount = Tools::getValue('discount');
        }
        
        $eIHelper = new EIAHelper($this->module);

        $this->sql = '
            SELECT SQL_CALC_FOUND_ROWS ';
        if (in_array($this->fileType, ['xml'])) {
            $fieldsInTree = $eIHelper->getFieldsInTree('combinations');
            foreach ($this->selectedColumns as $k => $col) {
                if (array_key_exists($k, $absentColumns)) {
                    $this->sql .= "
                    {$absentColumns[$k]} `{$fieldsInTree[$k]}`, ";
                } else {
                    $this->sql .= "
                    $k AS `{$fieldsInTree[$k]}`, ";
                }
            }
        } else {
            foreach ($this->selectedColumns as $k => $col) {
                if (array_key_exists($k, $absentColumns)) {
                    $this->sql .= "
                    {$absentColumns[$k]} `$col`, ";
                } elseif (array_key_exists($k, $newColumns) && !$newColumns[$k]) {
                    $this->sql .= "
                    '' `$col`, ";
                } else {
                    $this->sql .= "
                        $k `$col`, ";
                }
            }
        }

        $this->sql = rtrim($this->sql, ', ');

        // Filter By Category
        $categoriesCond = $categoriesCond2 = '';
        if ($filterCategories === '1') {
            if ($categories) {
                $categoriesCond = ' WHERE id_category IN (' . implode(',', $categories) . ')';
                $categoriesCond2 .= 'category.id_product IS NOT NULL';
                if ($categories_without !== '0') {
                    $categoriesCond2 .= ' OR for_null_category.id_product IS NULL';
                }
                $categoriesCond2 = ' 
                    AND (' . $categoriesCond2 . ')';
            } else {
                if ($categories_without !== '0') {
                    $categoriesCond2 .= ' 
                        AND (for_null_category.id_product IS NULL)';
                }
            }
        }

        // Filter By Attribute
        $attributesCond = $attributesCond2 = '';
        if ($attributes) {
            if ($attributesType === 'unselected') {
                $attributesCond = ' WHERE id_attribute NOT IN (' . $attributes . ')';
            } else {
                $attributesCond = ' WHERE id_attribute IN (' . $attributes . ')';
            }
            $attributesCond2 .= 'attributes.id_product_attribute IS NOT NULL';

            $attributesCond2 = ' 
                AND (' . $attributesCond2 . ')';
        }

        $this->sql .= '
            FROM 
            ' . _DB_PREFIX_ . 'product_attribute combination
                LEFT JOIN
            ' . _DB_PREFIX_ . 'product_attribute_shop combination_shop ON combination.id_product_attribute = combination_shop.id_product_attribute
                    AND combination_shop.id_shop = ' . $this->shopId . '
                LEFT JOIN
            ' . _DB_PREFIX_ . 'product product ON combination.id_product = product.id_product
                LEFT JOIN
            ' . _DB_PREFIX_ . 'product_lang product_lang ON combination.id_product = product_lang.id_product
                    AND product_lang.id_shop = ' . $this->shopId . '
                    AND product_lang.id_lang = ' . $this->langId . '
                LEFT JOIN (
                    SELECT
                        pac.id_product_attribute,
                        GROUP_CONCAT(CONCAT_WS(":", IFNULL(agl.name, ""), al.name) ORDER BY agl.name, al.name, a.color SEPARATOR "' . $this->multivalueSeparator . '") name_values,
                        GROUP_CONCAT(ag.group_type ORDER BY agl.name, al.name, a.color SEPARATOR "' . $this->multivalueSeparator . '") `types`,
                        GROUP_CONCAT(agl.name ORDER BY agl.name, al.name, a.color SEPARATOR "' . $this->multivalueSeparator . '") `groups`,
                        GROUP_CONCAT(agl.public_name ORDER BY agl.name, al.name, a.color SEPARATOR "' . $this->multivalueSeparator . '") `public_name`,
                        GROUP_CONCAT(IF(a.color = "", al.name, CONCAT_WS(":", al.name, a.color)) ORDER BY agl.name, al.name, a.color SEPARATOR "' . $this->multivalueSeparator . '") `values`
                    FROM (
                        SELECT DISTINCT id_product_attribute
                        FROM ' . _DB_PREFIX_ . 'product_attribute_combination' .
            $attributesCond . '
                    ) temp
                    JOIN ' . _DB_PREFIX_ . 'product_attribute_combination pac ON temp.id_product_attribute = pac.id_product_attribute
                    JOIN ' . _DB_PREFIX_ . 'attribute a ON pac.id_attribute = a.id_attribute
                    JOIN ' . _DB_PREFIX_ . 'attribute_shop ash ON a.id_attribute = ash.id_attribute AND ash.id_shop = ' . $this->shopId . '
                    JOIN ' . _DB_PREFIX_ . 'attribute_lang al ON a.id_attribute = al.id_attribute AND al.id_lang = ' . $this->langId . '
                    JOIN ' . _DB_PREFIX_ . 'attribute_group ag ON a.id_attribute_group = ag.id_attribute_group
                    JOIN ' . _DB_PREFIX_ . 'attribute_group_shop agsh ON a.id_attribute_group = agsh.id_attribute_group AND agsh.id_shop = ' . $this->shopId . '
                    JOIN ' . _DB_PREFIX_ . 'attribute_group_lang agl ON a.id_attribute_group = agl.id_attribute_group AND agl.id_lang = ' . $this->langId . '
                    GROUP BY pac.id_product_attribute
                ) attributes ON combination.id_product_attribute = attributes.id_product_attribute
                LEFT JOIN (
                    SELECT DISTINCT id_product
                    FROM ' . _DB_PREFIX_ . 'category_product ' . $categoriesCond . '
                ) category ON product.id_product = category.id_product
                LEFT JOIN (
                    SELECT DISTINCT id_product FROM ' . _DB_PREFIX_ . 'category_product
                ) for_null_category ON product.id_product = for_null_category.id_product
                LEFT JOIN (
                    SELECT 
                        pai.id_product_attribute,
                        GROUP_CONCAT(IF(pai.id_image = 0, "", pai.id_image) ORDER BY i.position SEPARATOR "' . $this->multivalueSeparator . ' ") ids,
                        GROUP_CONCAT(il.`legend` ORDER BY i.position SEPARATOR "' . $this->multivalueSeparator . ' ") `texts`,
                        GROUP_CONCAT(i.`position` ORDER BY i.position SEPARATOR "' . $this->multivalueSeparator . ' ") `positions`
                    FROM ' . _DB_PREFIX_ . 'product_attribute_image pai
                    LEFT JOIN ' . _DB_PREFIX_ . 'image i ON pai.id_image = i.id_image
                    LEFT JOIN ' . _DB_PREFIX_ . 'image_lang il ON pai.id_image = il.id_image AND il.id_lang = ' . $this->langId . '
                    GROUP BY pai.id_product_attribute
                ) image ON combination.id_product_attribute = image.id_product_attribute
                LEFT JOIN ' . _DB_PREFIX_ . 'stock_available stock_available ON combination.id_product = stock_available.id_product
                    AND combination.id_product_attribute = stock_available.id_product_attribute
                    ' . StockAvailable::addSqlShopRestriction(null, $this->shopId, 'stock_available') . '
                LEFT JOIN (
                    SELECT
                        wpl.id_product,
                        wpl.id_product_attribute,
                        GROUP_CONCAT(CONCAT_WS(":", w.`reference`, w.`name`, wpl.location) SEPARATOR "' . $this->multivalueSeparator . '") name_ref_loc
                    FROM ' . _DB_PREFIX_ . 'warehouse_product_location wpl
                    LEFT JOIN ' . _DB_PREFIX_ . 'warehouse w ON wpl.id_warehouse = w.id_warehouse 
                    WHERE wpl.id_product_attribute <> 0
                    GROUP BY wpl.id_product, wpl.id_product_attribute
                ) warehouse ON combination.id_product = warehouse.id_product AND combination.id_product_attribute = warehouse.id_product_attribute
            ';

        $this->sql .= '
                WHERE 1
            ';
        
        // Filter By Combination
        $combinationCond = '';
        if ($combinations) {
            if ($combinationsType === 'unselected') {
                $combinationCond = 'combination.id_product_attribute NOT IN (' . $combinations . ')';
            } else {
                $combinationCond = 'combination.id_product_attribute IN (' . $combinations . ')';
            }
        }
        if ($combinationCond) {
            $this->sql .= ' 
                        AND (' . $combinationCond . ') ';
        }
        
        // Filter By Category
        $this->sql .= $categoriesCond2;

        // Filter By Quantity
        if ($quantityOperator !== 'none' && ($quantity || $quantity == '0')) {
            $this->sql .= '
                AND stock_available.quantity ' . EIAHelper::getOperator($quantityOperator) . $quantity;
        }

        // Filter By Attribute
        $this->sql .= $attributesCond2;
        
        // Filter By Discount
        $discountCond = '';
        if ($discount === 'discounted') {
            $discountCond = '
                AND EXISTS (SELECT *
                    FROM ' . _DB_PREFIX_ . 'specific_price
                    WHERE id_product_attribute = combination.id_product_attribute
                        AND id_shop = ' . $this->shopId . '
                        AND (`from` < NOW() OR `from` = "0000-00-00 00:00:00") 
                        AND (`to` > NOW() OR `to` = "0000-00-00 00:00:00"))
                ';
        } elseif ($discount === 'nondiscounted') {
            $discountCond = '
                AND NOT EXISTS (SELECT *
                    FROM ' . _DB_PREFIX_ . 'specific_price
                    WHERE id_product_attribute = combination.id_product_attribute
                        AND id_shop = ' . $this->shopId . '
                        AND (`from` < NOW() OR `from` = "0000-00-00 00:00:00") 
                        AND (`to` > NOW() OR `to` = "0000-00-00 00:00:00"))
                ';
        }
        $this->sql .= $discountCond;

        // Filter by fields data
        $this->sql .= $eIHelper->getFieldsFilterString($this->auto, $this->inputs);

        // Sort By ...
        $this->sql .= ' ORDER BY ' . $this->sort . $this->sortWay;
        if ($this->sort !== 'combination.id_product_attribute') {
            $this->sql .= ', combination.id_product_attribute ASC';
        }

        $this->sql .= ' LIMIT ' . $this->offset . ', ' . $this->limit;

//        die($this->sql);
        return Db::getInstance()->executeS($this->sql);
    }

    protected function writeToCsv()
    {
        $handle = $this->openCsvFile();
        foreach ($this->data as $value) {
            if (!empty($value[$this->selectedColumns['image_urls']])) {
                $link = '';
                foreach (explode($this->multivalueSeparator, $value[$this->selectedColumns['image_urls']]) as $v) {
                    $link .= $this->getImageLink(trim($v)) . $this->multivalueSeparator;
                }
                $value[$this->selectedColumns['image_urls']] = rtrim($link, $this->multivalueSeparator);
            }
            fputcsv($handle, $value, $this->dlm, $this->encl);
        }
        $this->closeCsvFile($handle);
    }
    
    protected function writeToJson()
    {
        if (file_exists($this->file)) {
            $data = json_decode(Tools::file_get_contents($this->file), true);
        } else {
            $data = [];
        }
        foreach ($this->data as &$value) {
            if (!empty($value[$this->selectedColumns['image_urls']])) {
                $link = '';
                foreach (explode($this->multivalueSeparator, $value[$this->selectedColumns['image_urls']]) as $v) {
                    $link .= $this->getImageLink(trim($v)) . $this->multivalueSeparator;
                }
                $value[$this->selectedColumns['image_urls']] = rtrim($link, $this->multivalueSeparator);
            }
        }
        $data = array_merge($data, $this->data);
        file_put_contents($this->file, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    }

    protected function writeToXml()
    {
        foreach ($this->data as &$value) {
            if (!empty($value['Image_URLs'])) {
                $link = '';
                foreach (explode($this->multivalueSeparator, $value['Image_URLs']) as $v) {
                    $link .= $this->getImageLink(trim($v)) . $this->multivalueSeparator;
                }
                $value['Image_URLs'] = rtrim($link, $this->multivalueSeparator);
            }
        }
//        ddd($this->data);
        $this->makeXmlHierarchy();
        if (file_exists($this->file)) {
            $data = $this->arrayToXml(array_merge(array('arrType' => $this->xmlMainTag), $this->data), null, simplexml_load_file($this->file));
        } else {
            $data = $this->arrayToXml(array_merge(array('arrType' => $this->xmlMainTag), $this->data), '<?xml version="1.0" encoding="UTF-8"?><' . $this->xmlMainTagPl . ' />');
        }
        $domxml = new DOMDocument('1.0');
        $domxml->preserveWhiteSpace = false;
        $domxml->formatOutput = true;
        /* @var $xml SimpleXMLElement */
        $domxml->loadXML($data);

        $domxml->save($this->file, LIBXML_NOEMPTYTAG);
    }

    protected function writeToExcel()
    {
        require_once dirname(__FILE__) . '/../../vendor/autoload.php';

        if (file_exists($this->file)) {
            $spreadsheet = IOFactory::load($this->file);
            $sheet = $spreadsheet->getActiveSheet();
            $excelColumns = EIAHelper::createColumnsArray(count($this->data[0]));
        } else {
            $spreadsheet = new Spreadsheet();
            $sheet = $spreadsheet->getActiveSheet();

            // Set document properties
            $spreadsheet->getProperties()->setCreator('Tehran Alishov')
                ->setLastModifiedBy('Tehran Alishov')
                ->setTitle('Office 2007 XLSX Combinations Document')
                ->setSubject('Office 2007 XLSX Combinations Document')
                ->setDescription('Combinations document for Office 2007 XLSX, generated using PHP classes.')
                ->setKeywords('office 2007 openxml php')
                ->setCategory('Combinations result file');
            $spreadsheet->setActiveSheetIndex(0);

            if (empty($this->data)) {
                $sheet->setCellValue('A1', $this->module->l('No Data', 'EIACombinationsExport'));
            } else {
                $excelColumns = EIAHelper::createColumnsArray(count($this->data[0]));
                $sheet->getDefaultColumnDimension()->setWidth(21);
                $sheet->getDefaultRowDimension()->setRowHeight(30);

                $spreadsheet->getDefaultStyle()->getAlignment()
                    ->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER)
                    ->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER);

                $sheet->getStyle('A1:' . end($excelColumns) . (count($this->data)))
                    ->getAlignment()->setWrapText(true);

                $sheet->getStyle('A1:' . end($excelColumns) . '1')
                    ->getFont()->setBold(true);
                $sheet->getStyle('A1:' . end($excelColumns) . '1')
                    ->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
                    ->getStartColor()->setARGB('FFDCF0FF');
                $sheet->getStyle('A1:' . end($excelColumns) . '1')->getBorders()
                    ->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);

                // Rename worksheet
                $sheet->setTitle($this->module->l('Combinations', 'EIACombinationsExport'));

                $headers = array_keys($this->data[0]);
                foreach ($headers as $key => $header) {
                    $sheet->setCellValue($excelColumns[$key] . '1', $header);
                }

                if (isset($this->selectedColumns['image_urls'])) {
                    $sheet->getColumnDimension($excelColumns[array_search($this->selectedColumns['image_urls'], $headers)])->setWidth(40);
                }
            }
        }

        foreach ($this->data as $key => $value) {
            $i = 0;
            foreach ($value as $k => $val) {
                if ($k === $this->selectedColumns['image_urls'] && $val) {
                    $link = '';
                    $val = explode($this->multivalueSeparator, $val);
                    foreach ($val as $v) {
                        $link .= $this->getImageLink(trim($v)) . $this->multivalueSeparator;
                    }
                    $link = rtrim($link, $this->multivalueSeparator);
                    $cell = $excelColumns[$i] . ($this->offset + $key + 2);
                    $sheet->setCellValue($cell, $link);
                    if (count($val) === 1 && $link) {
                        $sheet->getCell($cell)->getHyperlink()->setUrl($link);
                        $sheet->getStyle($cell)->getFont()->getColor()->setARGB('FF0000FF');
                    }
                } elseif ($k === $this->selectedColumns['combination.ean13'] && $val) {
                    $sheet->setCellValueExplicit($excelColumns[$i] . ($this->offset + $key + 2), $val, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
                } else {
                    $sheet->setCellValue($excelColumns[$i] . ($this->offset + $key + 2), $val);
                }
                $i++;
            }
        }

        $sheet->setSelectedCell('A1');

        // Write to file
        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
        $writer->save($this->file);
    }
}