?? GreyFile — Mystic File Browser

Current path: home/webdevt/www/schtroumpf.fr/modules/an_stickyaddtocart/



?? Go up: /home/webdevt/www/schtroumpf.fr/modules

?? Viewing: an_stickyaddtocart.php

<?php
/**
* 2022 Anvanto
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
*
*  @author    Anvanto <anvantoco@gmail.com>
*  @copyright 2022 Anvanto
*  @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
*/

if (!defined('_PS_VERSION_')) {
    exit;
}
//
class an_stickyaddtocart extends Module
{
    const PREFIX = "an_satc_";
	
	protected $animate = array(
			'none',
            'bounce',
            'flash',
            'pulse',
            'rubberBand',
            'shake',
            'swing',
            'tada',
			'wobble',
			'jello',
			'heartBeat'
		);

    public function __construct()
    {
        $this->name = 'an_stickyaddtocart';
        $this->tab = 'front_office_features';
        $this->version = '1.0.15';
        $this->author = 'anvanto';
        $this->need_instance = 0;
        $this->ps_versions_compliancy = array('min' => '1.7', 'max' => _PS_VERSION_);
        $this->bootstrap = true;
        $this->module_key = '3055eb6b3d11b3cfa639f5e487f494a3';
		$this->addons_product_id = '48292';
		$this->url_rate = 'http://bit.ly/2WGXfp0';
		$this->url_contact_us = 'http://bit.ly/3c9ocKD';		

        parent::__construct();

        $this->displayName = $this->l('Ultimate Sticky add to cart');
        $this->description = $this->l('Raise conversions by adding Add to Cart bar — it appears when the page is scrolled down and the common button is invisible');

        $this->confirmUninstall = $this->l('Are you sure you want to uninstall?');
    }

    public function install()
    {
        Configuration::updateValue(self::PREFIX.'type_view', 'standart');
		Configuration::updateValue(self::PREFIX.'display_add_to_cart', 1);
        Configuration::updateValue(self::PREFIX.'display_quantity', 1);
		Configuration::updateValue(self::PREFIX.'display_labels', 0);
		Configuration::updateValue(self::PREFIX.'separator', ' / ');
		Configuration::updateValue(self::PREFIX.'background_sold_out', '#ffc427');
		Configuration::updateValue(self::PREFIX.'color_sold_out', '#ffffff');
		Configuration::updateValue(self::PREFIX.'background_sale', '#e53d60');
		Configuration::updateValue(self::PREFIX.'color_sale', '#ffffff');
		Configuration::updateValue(self::PREFIX.'display_prices', 1);
		Configuration::updateValue(self::PREFIX.'effect', 'none');
		Configuration::updateValue(self::PREFIX.'interalEffect', '2500');
		
        if (parent::install()) {
            return $this->registerHook('displayHeader')
				&& $this->registerHook('displayFooterProduct')
				&& $this->registerHook('displayBackOfficeHeader');
        }

        return false;
    }

    public function uninstall()
    {
        $paramList = $this->getParamList();
        $this->deleteParams($paramList);

        return parent::uninstall();
    }

    public function getParamList()
    {
        return array(
            'type_view',
            'display_add_to_cart',
            'display_quantity',
			'display_labels',
			'separator',
			'background_sold_out',
			'color_sold_out',
			'background_sale',
			'color_sale',		
			'display_prices',
			'effect',
			'interalEffect',
        );
    }

    public function getParam($key, $id_lang = 0)
    {
        return Configuration::get(self::PREFIX.$key, $id_lang);
    }

    protected function deleteParams($keys)
    {
        foreach ($keys as $key) {
            $this->deleteParam($key);
        }
    }

    protected function deleteParam($key)
    {
        return Configuration::deleteByName(self::PREFIX.$key);
    }

    protected function updateParam($key, $value)
    {
        return Configuration::updateValue(self::PREFIX.$key, $value);
    }
	
	public function getConfig(){
		$config = array();
		$paramList = $this->getParamList();
		foreach ($paramList as $key) {
			$config[$key] = $this->getParam($key);
		}
		return $config;
	}
	


    /// CONTENT

    public function getContent()
    {
        $output = null;

        if (Tools::isSubmit('submit'.$this->name)) {
            $output = $this->getSubmitOutput();
        }
		
		$this->context->smarty->assign('theme', $this->getThemeInfo());
		
        return $this->display(__FILE__, 'views/templates/admin/config_top.tpl').$output.$this->displayForm();

    }

    protected function getSubmitOutput()
    {
        $params = array();
        $paramList = $this->getParamList();

        foreach ($paramList as $key) {
            $params[$key] = Tools::getValue(self::PREFIX.$key);
        }

        if (Tools::getValue('an_satc_type_view') == 'select' && !$this->isReceivedParamsValid($params)) {
            return $this->displayError($this->l('Invalid Configuration value'));
        }

        foreach ($paramList as $key) {
            $this->updateParam($key, $params[$key]);
        }

        return $this->displayConfirmation($this->l('Settings updated'));
    }


    public function displayForm()
    {
        $default_lang = (int)Configuration::get('PS_LANG_DEFAULT');
        $fields_form = array();
		
		$animateFormated = array();
		foreach ($this->animate as $item){
			$animateFormated[] = array(
									'id' => $item,
									'name' => $item,
								);
		}
		


        $fields_form[0]['form'] = array(
            'legend' => array(
                'title' => $this->l('Settings'),
            ),
            'input' => array(
						
               array(
                    'type' => 'radio',
                    'label' => 'View type',
                    'name' => self::PREFIX.'type_view',
                    'class' => 'an-pa-type-view',
                    'values' => array(
						array(
							'id' => 'type_standart',
							'value' => 'standart',
							'label' => 'Standard'
						), 
						array(
							'id' => 'type_select',
							'value' => 'select',
							'label' => 'Select'
						), 
						array(
							'id' => 'type_none',
							'value' => 'None',
							'label' => 'None'
						)
                    )
                ),
				
               array(
                    'type' => 'text',
                    'label' => 'Separator',
                    'name' => self::PREFIX.'separator',
                    'values' => ' / ',
					'col' => '5',
					'class' => 'an-pa-type-select',
                ),
				
               array(
                    'type' => 'color',
                    'label' => '«Sold Out» background',
                    'name' => self::PREFIX.'background_sold_out',
                    'values' => '#ffc427',
					'class' => 'an-pa-type-select',
                ),

               array(
                    'type' => 'color',
                    'label' => '«Sold Out» color',
                    'name' => self::PREFIX.'color_sold_out',
                    'values' => '#ffffff',
					'class' => 'an-pa-type-select',
                ),				
				
               array(
                    'type' => 'color',
                    'label' => '«Sale» background',
                    'name' => self::PREFIX.'background_sale',
                    'values' => '#e53d60',
					'class' => 'an-pa-type-select',
                ),

               array(
                    'type' => 'color',
                    'label' => '«Sale» color',
                    'name' => self::PREFIX.'color_sale',
                    'values' => '#ffffff',
					'class' => 'an-pa-type-select',
                ),				
				
                array(
                    'type' => 'switch',
                    'label' => $this->l('Display combination price'),
                    'name' => self::PREFIX.'display_prices',
                    'is_bool' => true,
					'class' => 'an-pa-type-select',
                    'values' => array(
                        array(
                            'id' => 'is_enabled_on',
                            'value' => 1
                        ),
                        array(
                            'id' => 'is_enabled_off',
                            'value' => 0
                        )
                    ),
                ),
				
                array(
                    'type' => 'switch',
                    'label' => $this->l('Display attribute public name'),
                    'name' => self::PREFIX.'display_labels',
                    'is_bool' => true,
                    'values' => array(
                        array(
                            'id' => 'is_enabled_on',
                            'value' => 1
                        ),
                        array(
                            'id' => 'is_enabled_off',
                            'value' => 0
                        )
                    ),
                ),

                array(
                    'type' => 'switch',
                    'label' => $this->l('Display «Add to cart»'),
                    'name' => self::PREFIX.'display_add_to_cart',
                    'is_bool' => true,
					'class' => 'an-pa-display_add_to_cart',
                    'values' => array(
                        array(
                            'id' => 'is_enabled_on',
                            'value' => 1
                        ),
                        array(
                            'id' => 'is_enabled_off',
                            'value' => 0
                        )
                    ),
                ),
				
				
                array(
                    'type' => 'switch',
                    'label' => $this->l('Display quantity'),
                    'name' => self::PREFIX.'display_quantity',
                    'is_bool' => true,
                    'values' => array(
                        array(
                            'id' => 'is_enabled_on',
                            'value' => 1
                        ),
                        array(
                            'id' => 'is_enabled_off',
                            'value' => 0
                        )
                    ),
                ),
				
               array(
                    'type' => 'select',
                    'label' => 'Effect for «Add to cart»  button',
                    'name' => self::PREFIX.'effect',
					'options' => array(
						'query' => $animateFormated,
						'name' => 'name',
						'id' => 'id',
					),
                ),	
				
               array(
                    'type' => 'number',
                    'label' => 'Interval for effect',
                    'name' => self::PREFIX.'interalEffect',
                    'values' => '2500',
                    'col' => '2',
                    'min' => 1,
					'desc' => 'Default: 2500'
                ),				
				
            ),
            'submit' => array(
                'title' => $this->l('Save'),
            )
        );	

        $helper = new HelperForm();

        $helper->module = $this;
        $helper->name_controller = $this->name;
        $helper->token = Tools::getAdminTokenLite('AdminModules');
        $helper->currentIndex = AdminController::$currentIndex.'&configure='.$this->name;

        $helper->default_form_language = $default_lang;
        $helper->allow_employee_form_lang = $default_lang;

        $helper->title = $this->displayName;
        $helper->show_toolbar = true;
        $helper->toolbar_scroll = true;
        $helper->submit_action = 'submit'.$this->name;
        $helper->toolbar_btn = array(
            'save' =>
                array(
                    'desc' => $this->l('Save'),
                    'href' => AdminController::$currentIndex.'&configure='.$this->name.'&save'.$this->name.
                        '&token='.Tools::getAdminTokenLite('AdminModules'),
                ),
            'back' => array(
                'href' => AdminController::$currentIndex.'&token='.Tools::getAdminTokenLite('AdminModules'),
                'desc' => $this->l('Back to list')
            )
        );
		


        $paramList = $this->getParamList();

        foreach ($paramList as $key) {
            $helper->fields_value[self::PREFIX.$key] = $this->getParam($key);
        }

        return $helper->generateForm($fields_form);
    }
	
    public function hookBackOfficeHeader($params)
    {
        $this->hookDisplayBackOfficeHeader($params);
    }

    public function hookDisplayBackOfficeHeader($params)
    {
        if (in_array($this->name, array(Tools::getValue('configure', ''), Tools::getValue('module_name', '')))) {
			$this->context->controller->addJquery();
			$this->context->controller->addJS($this->_path.'views/js/back.js');
		}
    }

    public function hookDisplayHeader($params)
    {
        if (Tools::getValue('controller') == 'product' && !(bool)Configuration::isCatalogMode()) {
			$config = array();
			$paramList = $this->getParamList();
			foreach ($paramList as $key) {
				$config[$key] = $this->getParam($key);
			}

			$this->context->smarty->assign('config', json_encode($config));	
		
			$this->context->controller->addCSS($this->_path .'views/css/front.css');
			$this->context->controller->addCSS($this->_path .'views/css/animate.css');
			$this->context->controller->addJS($this->_path .'views/js/front.js');
			return $this->display(__FILE__, 'views/templates/front/js_header.tpl');
		}
    }

	public function hookDisplayFooterProduct($params)
	{
		if (!isset($params['product']) || !(($params['product'] instanceof PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductLazyArray) || is_array($params['product']))){
			return 'The $product does not exist or it has incorrect type';
		}
        
		$productObj = new Product($params['product']['id_product']);
		$product = $this->productPrepare($productObj, $params['product']['id_product_attribute'], $params['product']['quantity']);	
	
		if ($this->getParam('type_view') == 'select'){
		//	Select
			$attributeCombinations = array();
			$productData = array();
			$attributeCombinations = $productObj->getAttributeCombinations((int)$this->context->language->id);
			$productData = $this->attributeCombinationForSelect($attributeCombinations, $productObj, $product);

			$attributeGroupsSelect = array();
			foreach ($attributeCombinations as $item){
				$attributeGroupsSelect[$item['id_product_attribute']][] = array(
					'id_attribute_group' => $item['id_attribute_group'],
					'id_attribute' => $item['id_attribute'],
				);
			}
			$this->context->smarty->assign('attributeGroups', json_encode($attributeGroupsSelect));
			$this->context->smarty->assign('productData', $productData);
		} else {
		//	Standart
			$product_full = Product::getProductProperties($this->context->language->id, $product);
			$attributesGroups = $this->assignAttributesGroups($productObj, $product_full);
			if (isset($attributesGroups['groups'])){
				$this->context->smarty->assign('groups', $attributesGroups['groups']);
			} else {
				$this->context->smarty->assign('groups', array());
			}
		}
		
		$orderOutOfStock = (bool)Configuration::get('PS_STOCK_MANAGEMENT') && !Product::isAvailableWhenOutOfStock($product['out_of_stock']);
		
		$this->context->smarty->assign(array(	
			'cover' => $params['product']['cover'],
			'product' => $params['product'],
			'config' => $this->getConfig(),
			
			'cart' => $this->context->link->getPageLink('cart'),
			'token' => Tools::getToken(false),
			
			'productId' => (int) $productObj->id,
			'id_product_attribute' => $params['product']['id_product_attribute'],	

			'order_out_of_stock' => $orderOutOfStock,
			
			'quantity' => $product['quantity'],
			'quantity_wanted' => $product['quantity_wanted'],
			'minimal_quantity' => $product['minimal_quantity'],
			'availableForOrder' => intval($product['availableForOrder']),
		));				
		
		if (!(bool)Configuration::isCatalogMode()){
			return $this->display(__FILE__, 'views/templates/front/an-sticky-add-to-cart.tpl');
		}
	}	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
    protected function isReceivedParamsValid($params)
    { 
        return Validate::isString($params['type_view'])
			&& $this->isColor($params['background_sold_out'])
			&& $this->isColor($params['color_sold_out'])
			&& $this->isColor($params['background_sale'])
			&& $this->isColor($params['color_sale']);
		
    }

		
		
	
	protected function isColor($string){
		$string = htmlspecialchars($string);
        $customvalarray = str_split('#0123456789aAbBcCdDeEfF');
        foreach (str_split($string) as $val) {
            if (!in_array($val, $customvalarray)) {
                return false;
            }
        }
        return true;
	}


    /// SYSTEM

    protected function isNewSystem()
    {
        return !$this->isOldSystem();
    }

    protected function isOldSystem()
    {
        return version_compare(_PS_VERSION_, '1.7.0.0', '<');
    }	
	
	public function attributeCombinationForSelect($attributeCombinations, $productObj)
	{
		$productsAttr = array();
		foreach ($attributeCombinations as $attributeCombination) {
			
			$product = $this->productPrepare($productObj, $attributeCombination['id_product_attribute']);
			$prices = $this->getPrices($productObj, $product);
			
			$productsAttr[$attributeCombination['id_product_attribute']]['availableForOrder'] = $product['availableForOrder'];
			$productsAttr[$attributeCombination['id_product_attribute']]['default_on'] = (int)$attributeCombination['default_on'];
			$productsAttr[$attributeCombination['id_product_attribute']]['prices'] = $prices;
			$productsAttr[$attributeCombination['id_product_attribute']]['comb'][] = $attributeCombination;			
		}
		return $productsAttr;
	}

	public function getPrices($productObj, $product){
		
		$prices = array();
		$taxConfiguration = new TaxConfiguration();		
        if ($taxConfiguration->includeTaxes()) {
            $price = $productObj->getPrice(true, $product['id_product_attribute'], 2);
			$prices['regular_price_amount'] = $productObj->getPriceWithoutReduct(true, $product['id_product_attribute'], 2);
        } else {
            $price = $productObj->getPrice(false, $product['id_product_attribute'], 2);
			$prices['regular_price_amount'] = $productObj->getPriceWithoutReduct(false, $product['id_product_attribute'], 2);
        }

		$productProperties = Product::getProductProperties($this->context->language->id, $product, $this->context);

	    if ($productProperties['specific_prices']) {
 	        $prices['has_discount'] = (0 != $productProperties['reduction']);
	        $prices['discount_type'] = $productProperties['specific_prices']['reduction_type'];
	        $prices['discount_percentage'] = -round(100 * $productProperties['specific_prices']['reduction']).'%';
	        $prices['discount_percentage_absolute'] = round(100 * $productProperties['specific_prices']['reduction']).'%';
	        $prices['discount_amount'] = Tools::displayPrice($productProperties['reduction']);
	        $prices['regular_price'] = Tools::displayPrice($productProperties['price_without_reduction']); 
	    }
		
		$prices['price_amount'] = $price;
		$prices['price'] = Tools::displayPrice($price); 
		
		return $prices;
	}
	
	
	
	public function productPrepare($productObj, $id_product_attribute = false, 	$quantity = '')
	{
		$productObj->loadStockData();
		$product = (array)$productObj;
		$product['id_product_attribute'] = $this->getIdProductAttributeByRequestOrGroup($productObj, $productObj->id);

		if ($id_product_attribute | (!$product['id_product_attribute'] && $id_product_attribute)){
			$product['id_product_attribute'] = $id_product_attribute;
		}

		$product['images'] = $productObj->getImages($this->context->language->id);
		$product['id_product'] = (int) $productObj->id;
		$product['out_of_stock'] = (int) $productObj->out_of_stock;
		$product['new'] = (int) $productObj->new;
		$product['id_category_default'] = '';
		$product['link_rewrite'] = $this->checkLinkRewrite($productObj->link_rewrite);
		$product['ean13'] = $productObj->ean13;
		$product['price'] = $productObj->price;
		$product['wholesale_price'] = $productObj->wholesale_price;
		$product['unit_price_ratio'] = $productObj->unit_price_ratio;
		
		if ($quantity !== ''){
			$product['quantity'] = $quantity; 
		} else {
			$product['quantity'] = Product::getQuantity(
				(int) $productObj->id,
				(int) $product['id_product_attribute'],
				isset($product['cache_is_pack']) ? $product['cache_is_pack'] : null
			);
		}
		$product['minimal_quantity'] = $this->getProductMinimalQuantity($productObj, $product);
		$product['quantity_wanted'] = $this->getRequiredQuantity($productObj, $product);		
		$product['availableForOrder'] = $this->isAvailableForOrder($product);
		
		return $product;
	}
	
	public function isAvailableForOrder($product)
	{
		$availableForOrder = true;
		
		// If Enable stock management = off and Some Produc ->  Options -> Available for order -> off
		if (!(bool)Configuration::get('PS_STOCK_MANAGEMENT') && !$product['available_for_order']){
			return false;
		}

		if ((bool)Configuration::get('PS_STOCK_MANAGEMENT') && 
		!an_stickyaddtocart::isAvailableWhenOutOfStock($product['out_of_stock']) && 
		isset($product['quantity_wanted']) && ($product['quantity'] <= 0 || $product['quantity'] < $product['quantity_wanted'])
		){
			$availableForOrder = false;
		}

		//customizable
		//	Учесть вариант, когда костомизация заполнена
		$customization_required = false;
		if (isset($product['customizable']) && $product['customizable'] && Customization::isFeatureActive()) {
			if (count(Product::getRequiredCustomizableFieldsStatic((int)$product['id_product']))){
				$customization_required = true;
			}
		}		
		if ($customization_required){
			$availableForOrder = false;
		}

		return $availableForOrder;
	}
	
    public static function isAvailableWhenOutOfStock($out_of_stock)
    {
        /** @TODO 1.5.0 Update of STOCK_MANAGEMENT & ORDER_OUT_OF_STOCK */
        $ps_stock_management = Configuration::get('PS_STOCK_MANAGEMENT');

        if (!$ps_stock_management) {
            return true;
        }

        $ps_order_out_of_stock = Configuration::get('PS_ORDER_OUT_OF_STOCK');

        return (int) $out_of_stock == 2 ? (int) $ps_order_out_of_stock : (int) $out_of_stock;
    }	
	
	
	
    /**
     * Assign template vars related to attribute groups and colors.
     */
    public function assignAttributesGroups($product, $product_for_template = null)
    {
        $colors = array();
        $groups = array();
        $this->combinations = array();
		
		

        // @todo (RM) should only get groups and not all declination ?
        $attributes_groups = $product->getAttributesGroups($this->context->language->id);

        if (is_array($attributes_groups) && $attributes_groups) {
            $combination_images = $product->getCombinationImages($this->context->language->id);

            $combination_prices_set = array();
            foreach ($attributes_groups as $k => $row) {
                // Color management
                if (isset($row['is_color_group']) && $row['is_color_group'] && (isset($row['attribute_color']) && $row['attribute_color']) || (file_exists(_PS_COL_IMG_DIR_ . $row['id_attribute'] . '.jpg'))) {
                    $colors[$row['id_attribute']]['value'] = $row['attribute_color'];
                    $colors[$row['id_attribute']]['name'] = $row['attribute_name'];
                    if (!isset($colors[$row['id_attribute']]['attributes_quantity'])) {
                        $colors[$row['id_attribute']]['attributes_quantity'] = 0;
                    }
                    $colors[$row['id_attribute']]['attributes_quantity'] += (int) $row['quantity'];
                }
                if (!isset($groups[$row['id_attribute_group']])) {
                    $groups[$row['id_attribute_group']] = array(
                        'group_name' => $row['group_name'],
                        'name' => $row['public_group_name'],
                        'group_type' => $row['group_type'],
                        'default' => -1,
                    );
                }

                $groups[$row['id_attribute_group']]['attributes'][$row['id_attribute']] = array(
                    'name' => $row['attribute_name'],
                    'html_color_code' => $row['attribute_color'],
                    'texture' => (@filemtime(_PS_COL_IMG_DIR_ . $row['id_attribute'] . '.jpg')) ? _THEME_COL_DIR_ . $row['id_attribute'] . '.jpg' : '',
                    'selected' => (isset($product_for_template['attributes'][$row['id_attribute_group']]['id_attribute']) && $product_for_template['attributes'][$row['id_attribute_group']]['id_attribute'] == $row['id_attribute']) ? true : false,
                );

                //$product.attributes.$id_attribute_group.id_attribute eq $id_attribute
                if ($row['default_on'] && $groups[$row['id_attribute_group']]['default'] == -1) {
                    $groups[$row['id_attribute_group']]['default'] = (int) $row['id_attribute'];
                }
                if (!isset($groups[$row['id_attribute_group']]['attributes_quantity'][$row['id_attribute']])) {
                    $groups[$row['id_attribute_group']]['attributes_quantity'][$row['id_attribute']] = 0;
                }
                $groups[$row['id_attribute_group']]['attributes_quantity'][$row['id_attribute']] += (int) $row['quantity'];

                $this->combinations[$row['id_product_attribute']]['attributes_values'][$row['id_attribute_group']] = $row['attribute_name'];
                $this->combinations[$row['id_product_attribute']]['attributes'][] = (int) $row['id_attribute'];
                $this->combinations[$row['id_product_attribute']]['price'] = (float) $row['price'];

                // Call getPriceStatic in order to set $combination_specific_price
                if (!isset($combination_prices_set[(int) $row['id_product_attribute']])) {
                    $combination_specific_price = null;
                    Product::getPriceStatic((int) $product->id, false, $row['id_product_attribute'], 6, null, false, true, 1, false, null, null, null, $combination_specific_price);
                    $combination_prices_set[(int) $row['id_product_attribute']] = true;
                    $this->combinations[$row['id_product_attribute']]['specific_price'] = $combination_specific_price;
                }
                $this->combinations[$row['id_product_attribute']]['ecotax'] = (float) $row['ecotax'];
                $this->combinations[$row['id_product_attribute']]['weight'] = (float) $row['weight'];
                $this->combinations[$row['id_product_attribute']]['quantity'] = (int) $row['quantity'];
                $this->combinations[$row['id_product_attribute']]['reference'] = $row['reference'];
                $this->combinations[$row['id_product_attribute']]['unit_impact'] = $row['unit_price_impact'];
                $this->combinations[$row['id_product_attribute']]['minimal_quantity'] = $row['minimal_quantity'];
                if ($row['available_date'] != '0000-00-00' && Validate::isDate($row['available_date'])) {
                    $this->combinations[$row['id_product_attribute']]['available_date'] = $row['available_date'];
                    $this->combinations[$row['id_product_attribute']]['date_formatted'] = Tools::displayDate($row['available_date']);
                } else {
                    $this->combinations[$row['id_product_attribute']]['available_date'] = $this->combinations[$row['id_product_attribute']]['date_formatted'] = '';
                }

                if (!isset($combination_images[$row['id_product_attribute']][0]['id_image'])) {
                    $this->combinations[$row['id_product_attribute']]['id_image'] = -1;
                } else {
                    $this->combinations[$row['id_product_attribute']]['id_image'] = (int) $combination_images[$row['id_product_attribute']][0]['id_image'];
                } 
            }

            // wash attributes list depending on available attributes depending on selected preceding attributes
            $current_selected_attributes = array();
            $count = 0;
            foreach ($groups as &$group) {
                ++$count;
                if ($count > 1) {
                    //find attributes of current group, having a possible combination with current selected
                    $id_product_attributes = array(0);
                    $query = 'SELECT pac.`id_product_attribute`
                        FROM `' . _DB_PREFIX_ . 'product_attribute_combination` pac
                        INNER JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON pa.id_product_attribute = pac.id_product_attribute
                        WHERE id_product = ' . (int)$product->id . ' AND id_attribute IN (' . implode(',', array_map('intval', $current_selected_attributes)) . ')
                        GROUP BY id_product_attribute
                        HAVING COUNT(id_product) = ' . count($current_selected_attributes);
                    if ($results = Db::getInstance()->executeS($query)) {
                        foreach ($results as $row) {
                            $id_product_attributes[] = $row['id_product_attribute'];
                        }
                    }
                    $id_attributes = Db::getInstance()->executeS('SELECT `id_attribute` FROM `' . _DB_PREFIX_ . 'product_attribute_combination` pac2
                        WHERE `id_product_attribute` IN (' . implode(',', array_map('intval', $id_product_attributes)) . ')
                        AND id_attribute NOT IN (' . implode(',', array_map('intval', $current_selected_attributes)) . ')');
                    foreach ($id_attributes as $k => $row) {
                        $id_attributes[$k] = (int) $row['id_attribute'];
                    }
                    foreach ($group['attributes'] as $key => $attribute) {
                        if (!in_array((int) $key, $id_attributes)) {
                            unset($group['attributes'][$key]);
                            unset($group['attributes_quantity'][$key]);
                        }
                    }
                }
                //find selected attribute or first of group
                $index = 0;
                $current_selected_attribute = 0;
                foreach ($group['attributes'] as $key => $attribute) {
                    if ($index === 0) {
                        $current_selected_attribute = $key;
                    }
                    if ($attribute['selected']) {
                        $current_selected_attribute = $key;
                        break;
                    }
                }
                if ($current_selected_attribute > 0) {
                    $current_selected_attributes[] = $current_selected_attribute;
                }
            }

            // wash attributes list (if some attributes are unavailables and if allowed to wash it)
            if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && Configuration::get('PS_DISP_UNAVAILABLE_ATTR') == 0) {
                foreach ($groups as &$group) {
                    foreach ($group['attributes_quantity'] as $key => &$quantity) {
                        if ($quantity <= 0) {
                            unset($group['attributes'][$key]);
                        }
                    }
                }

                foreach ($colors as $key => $color) {
                    if ($color['attributes_quantity'] <= 0) {
                        unset($colors[$key]);
                    }
                }
            }
             foreach ($this->combinations as $id_product_attribute => $comb) {
                $attribute_list = '';
                foreach ($comb['attributes'] as $id_attribute) {
                    $attribute_list .= '\'' . (int) $id_attribute . '\',';
                }
                $attribute_list = rtrim($attribute_list, ',');
                $this->combinations[$id_product_attribute]['list'] = $attribute_list;
            }			

			$return = array();
			$return['groups'] = $groups;
 			$return['combinations'] = $this->combinations; 
			$return['combination_images'] = $combination_images;
			return $return;
        } else {
			return array();
        }
    }	
		
    private function getIdProductAttributeByGroup($id_product)
    {
        $groups = Tools::getValue('group');
		

        if (empty($groups)) {
            return null;
        }

        return (int) $this->getIdProductAttributeByIdAttributes(
            $id_product,
            $groups,
            true
        );
    }
	
    public static function getIdProductAttributeByIdAttributes($idProduct, $idAttributes, $findBest = false)
    {
        $idProduct = (int) $idProduct;

        if (!is_array($idAttributes) && is_numeric($idAttributes)) {
            $idAttributes = array((int) $idAttributes);
        }

        if (!is_array($idAttributes) || empty($idAttributes)) {
            throw new PrestaShopException(
                sprintf(
                    'Invalid parameter $idAttributes with value: "%s"',
                    print_r($idAttributes, true)
                )
            );
        }

        $idAttributesImploded = implode(',', array_map('intval', $idAttributes));
        $idProductAttribute = Db::getInstance()->getValue('
            SELECT
                pac.`id_product_attribute`
            FROM
                `' . _DB_PREFIX_ . 'product_attribute_combination` pac
                INNER JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON pa.id_product_attribute = pac.id_product_attribute
            WHERE
                pa.id_product = ' . (int)$idProduct . '
                AND pac.id_attribute IN (' .pSQL($idAttributesImploded) . ')
            GROUP BY
                pac.`id_product_attribute`
            HAVING
                COUNT(pa.id_product) = ' . count($idAttributes)
        );

        if ($idProductAttribute === false && $findBest) {
            //find the best possible combination
            //first we order $idAttributes by the group position
            $orderred = array();
            $result = Db::getInstance()->executeS('
                SELECT
                    a.`id_attribute`
                FROM
                    `' . _DB_PREFIX_ . 'attribute` a
                    INNER JOIN `' . _DB_PREFIX_ . 'attribute_group` g ON a.`id_attribute_group` = g.`id_attribute_group`
                WHERE
                    a.`id_attribute` IN (' .pSQL($idAttributesImploded) . ')
                ORDER BY
                    g.`position` ASC'
            );

            foreach ($result as $row) {
                $orderred[] = $row['id_attribute'];
            }

            while ($idProductAttribute === false && count($orderred) > 0) {
                array_pop($orderred);
                $idProductAttribute = Db::getInstance()->getValue('
                    SELECT
                        pac.`id_product_attribute`
                    FROM
                        `' . _DB_PREFIX_ . 'product_attribute_combination` pac
                        INNER JOIN `' . _DB_PREFIX_ . 'product_attribute` pa ON pa.id_product_attribute = pac.id_product_attribute
                    WHERE
                        pa.id_product = ' . (int) $idProduct . '
                        AND pac.id_attribute IN (' . implode(',', array_map('intval', $orderred)) . ')
                    GROUP BY
                        pac.id_product_attribute
                    HAVING
                        COUNT(pa.id_product) = ' . count($orderred)
                );
            }
        }

        if (empty($idProductAttribute)) {
            throw new PrestaShopObjectNotFoundException('Can not retrieve the id_product_attribute');
        }

        return $idProductAttribute;
    }
	
	
    public function getIdProductAttributeByRequestOrGroup($product, $id_product)
    { 
        $requestedIdProductAttribute = (int) Tools::getValue('id_product_attribute');
		
        $groupIdProductAttribute = $this->getIdProductAttributeByGroup($id_product); 
        $requestedIdProductAttribute = null !== $groupIdProductAttribute ? $groupIdProductAttribute : $requestedIdProductAttribute;
		
        return $this->tryToGetAvailableIdProductAttribute($product, $requestedIdProductAttribute);
    }
	
	
    public function tryToGetAvailableIdProductAttribute($product, $checkedIdProductAttribute)
    {
        if (!Configuration::get('PS_DISP_UNAVAILABLE_ATTR')) {
            $availableProductAttributes = array_filter(
                $product->getAttributeCombinations(),
                function ($elem) {
                    return $elem['quantity'] > 0;
                }
            );

            $availableProductAttribute = array_filter(
                $availableProductAttributes,
                function ($elem) use ($checkedIdProductAttribute) {
                    return $elem['id_product_attribute'] == $checkedIdProductAttribute;
                }
            );

            if (empty($availableProductAttribute) && count($availableProductAttributes)) {
                return (int) array_shift($availableProductAttributes)['id_product_attribute'];
            }
        }

        return $checkedIdProductAttribute;
    }
	
    public function findProductCombinationById($product, $combinationId)
    {
        $foundCombination = null;
        $combinations = $product->getAttributesGroups($this->context->language->id);
        foreach ($combinations as $combination) {
            if ((int) ($combination['id_product_attribute']) === $combinationId) {
                $foundCombination = $combination;

                break;
            }
        }

        return $foundCombination;
    }	
	
    public function getProductMinimalQuantity($product, $productArray)
    {
        $minimal_quantity = 1;
		
        if (isset($productArray['id_product_attribute']) && $productArray['id_product_attribute']) {
            $combination = $this->findProductCombinationById($product, $productArray['id_product_attribute']);
            if (isset($combination['minimal_quantity']) && $combination['minimal_quantity']) {
                $minimal_quantity = $combination['minimal_quantity'];
            }
        } else {
            $minimal_quantity = $product->minimal_quantity;
        }

        return $minimal_quantity;
    }
	
    /**
     * @param $product
     *
     * @return int
     */
    public function getRequiredQuantity($product, $productArray)
    {
        $requiredQuantity = (int) Tools::getValue('quantity_wanted', $this->getProductMinimalQuantity($product, $productArray));
        if ($requiredQuantity < $productArray['minimal_quantity']) {
            $requiredQuantity = $productArray['minimal_quantity'];
        }

        return $requiredQuantity;
    }
	
    public function getAttributesGroups($id_lang, $id_product, $groupIdProductAttribute = '')
    {
        if (!Combination::isFeatureActive()) {
            return array();
        }
		$filterByGroupIdProductAttribute = '';
		if ($groupIdProductAttribute != ''){
			$filterByGroupIdProductAttribute = 'AND pac.`id_product_attribute` = ' . (int) $groupIdProductAttribute . '';
		}
		
        $sql = 'SELECT ag.`id_attribute_group`, ag.`is_color_group`, agl.`name` AS group_name, agl.`public_name` AS public_group_name,
                    a.`id_attribute`, al.`name` AS attribute_name, a.`color` AS attribute_color, product_attribute_shop.`id_product_attribute`,
                    IFNULL(stock.quantity, 0) as quantity, product_attribute_shop.`price`, product_attribute_shop.`ecotax`, product_attribute_shop.`weight`,
                    product_attribute_shop.`default_on`, pa.`reference`, product_attribute_shop.`unit_price_impact`,
                    product_attribute_shop.`minimal_quantity`, product_attribute_shop.`available_date`, ag.`group_type`
                FROM `' . _DB_PREFIX_ . 'product_attribute` pa
                ' . Shop::addSqlAssociation('product_attribute', 'pa') . '
                ' . Product::sqlStock('pa', 'pa') . '
                LEFT JOIN `' . _DB_PREFIX_ . 'product_attribute_combination` pac ON (pac.`id_product_attribute` = pa.`id_product_attribute`)
                LEFT JOIN `' . _DB_PREFIX_ . 'attribute` a ON (a.`id_attribute` = pac.`id_attribute`)
                LEFT JOIN `' . _DB_PREFIX_ . 'attribute_group` ag ON (ag.`id_attribute_group` = a.`id_attribute_group`)
                LEFT JOIN `' . _DB_PREFIX_ . 'attribute_lang` al ON (a.`id_attribute` = al.`id_attribute`)
                LEFT JOIN `' . _DB_PREFIX_ . 'attribute_group_lang` agl ON (ag.`id_attribute_group` = agl.`id_attribute_group`)
                ' . Shop::addSqlAssociation('attribute', 'a') . '
                WHERE pa.`id_product` = ' . (int) $id_product . '
                    AND al.`id_lang` = ' . (int) $id_lang . '
                    AND agl.`id_lang` = ' . (int) $id_lang . '
					' . pSQL($filterByGroupIdProductAttribute) . '
                GROUP BY id_attribute_group, id_product_attribute
                ORDER BY ag.`position` ASC, a.`position` ASC, agl.`name` ASC';

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

	
	
    /**
     * Allow to check if $link_rewrite is an array or not and only return a valid value
     *
     * @param array|string $link_rewrite
     *
     * @return string
     */
    public function checkLinkRewrite($link_rewrite)
    {
        $link_rewrite = $link_rewrite;

        if (is_array($link_rewrite)) {
            $filteredArray = array_filter($link_rewrite);
            $link_rewrite = current($filteredArray);
        }

        return $link_rewrite;
    }
	
	public function getThemeInfo()
	{
		$theme = [];
		$themeFileJson = _PS_THEME_DIR_.'/config/theme.json';
		if (Tools::file_exists_no_cache($themeFileJson)) {
			$theme = (array)json_decode(Tools::file_get_contents($themeFileJson), 1);			
		}

		if (!isset($theme['url_contact_us']) || $theme['url_contact_us'] == ''){
			
			$urlContactUs = 'https://addons.prestashop.com/contact-form.php';

			if (isset($theme['addons_id']) && $theme['addons_id'] != ''){
				$urlContactUs .= '?id_product=' .$theme['addons_id'];
			} elseif (isset($this->url_contact_us) && $this->url_contact_us != ''){
				$urlContactUs = $this->url_contact_us;
			} elseif (isset($this->addons_product_id) && $this->addons_product_id != ''){
				$urlContactUs .= '?id_product=' .$this->addons_product_id;
			}
			
			$theme['url_contact_us'] = $urlContactUs;
		}
		
		if (!isset($theme['url_rate']) || $theme['url_rate'] == ''){
			
			$urlRate = 'https://addons.prestashop.com/ratings.php';

			if (isset($theme['addons_id']) && $theme['addons_id'] != ''){
				$urlRate .= '?id_product=' .$theme['addons_id'];
			} elseif (isset($this->url_rate) && $this->url_rate != ''){
				$urlRate = $this->url_rate;
			} elseif (isset($this->addons_product_id) && $this->addons_product_id != ''){
				$urlRate .= '?id_product=' .$this->addons_product_id;
			}
			
			$theme['url_rate'] = $urlRate;
		}		
		
		return $theme;
	}	
	
}


??

??