Add module antadisconfigurator + specific
This commit is contained in:
parent
3c9a8fa5cf
commit
21cd725307
@ -43,7 +43,8 @@ class Adapter_ProductPriceCalculator
|
||||
$with_ecotax = true,
|
||||
$use_group_reduction = true,
|
||||
Context $context = null,
|
||||
$use_customer_price = true
|
||||
$use_customer_price = true,
|
||||
$id_configurator = null
|
||||
) {
|
||||
return Product::getPriceStatic(
|
||||
$id_product,
|
||||
@ -62,7 +63,8 @@ class Adapter_ProductPriceCalculator
|
||||
$with_ecotax,
|
||||
$use_group_reduction,
|
||||
$context,
|
||||
$use_customer_price
|
||||
$use_customer_price,
|
||||
$id_configurator
|
||||
);
|
||||
}
|
||||
}
|
||||
|
49
www/modules/antadisconfigurator/README.md
Normal file
49
www/modules/antadisconfigurator/README.md
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
# Install
|
||||
|
||||
|
||||
# Documentation
|
||||
|
||||
* Configuration d'une liste d'options (group)
|
||||
- type, reference, name
|
||||
|
||||
* Configuration des valeurs
|
||||
- name, price, position
|
||||
|
||||
* Association au produit
|
||||
- Group : required, position
|
||||
- Impact : name with price
|
||||
|
||||
|
||||
Lors de la sélection du choix des options pour le panier
|
||||
Group avec texte libre (text, date)
|
||||
optgroup-{id} = value
|
||||
|
||||
Group avec option "list"
|
||||
optgroup-{id} = {id_optimpact}
|
||||
|
||||
Attention les valeurs du groupes peuvent être multiples
|
||||
|
||||
Désactivé le panier en ajax
|
||||
Attention même id_cart - id_product mais options différentes
|
||||
Associations ps_cart_product <= id_configurator
|
||||
ALTER TABLE `ps_cart_product` ADD `id_configurator` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `id_product_attribute`;
|
||||
+ ajouter id_configurator a PRIMARY KEY
|
||||
|
||||
Associations ps_order_detail <= id_configurator
|
||||
|
||||
Table stockage des options id_configurator | id_product | id_product_configurator_opt_group | value | price
|
||||
|
||||
|
||||
|
||||
Modifier l'Adapter
|
||||
Adapter_ProductPriceCalculator
|
||||
|
||||
* Panier
|
||||
- Stockage des valeurs selectionnées dans une table
|
||||
id + id_option + value + price
|
||||
|
||||
* TODO
|
||||
- Afficher le détail des options choisies dans le panier, dans la commande
|
||||
- Question : dans le stockage des options quid des éléments text, date, fichier
|
||||
id_option_group + id_option + value + priceImpact
|
155
www/modules/antadisconfigurator/antadisconfigurator.php
Normal file
155
www/modules/antadisconfigurator/antadisconfigurator.php
Normal file
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
if (!defined('_PS_VERSION_')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once dirname(__FILE__).'/classes/ConfiguratorOptGroup.php';
|
||||
require_once dirname(__FILE__).'/classes/ConfiguratorOpt.php';
|
||||
require_once dirname(__FILE__).'/classes/ProductConfiguratorOptGroup.php';
|
||||
require_once dirname(__FILE__).'/classes/ProductConfiguratorOptImpact.php';
|
||||
|
||||
class AntadisConfigurator extends Module
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->name = 'antadisconfigurator';
|
||||
$this->tab = 'front_office_features';
|
||||
$this->version = '0.1';
|
||||
$this->author = 'antadis';
|
||||
$this->bootstrap = true;
|
||||
parent::__construct();
|
||||
|
||||
$this->displayName = $this->l('Product Options');
|
||||
$this->description = $this->l('Add options on product');
|
||||
|
||||
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => _PS_VERSION_);
|
||||
|
||||
$this->confirmUninstall = $this->l('Are you sure you want to uninstall this module?');
|
||||
}
|
||||
|
||||
public function install()
|
||||
{
|
||||
// Call install parent method
|
||||
if (!parent::install()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Menu
|
||||
if (!$this->installTab('AdminCatalog', 'AdminAntadisConfigurator', 'Configurator Options')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Install AdminAntadisConfiguratorProduct
|
||||
if (!$this->installTab('AdminCatalog', 'AdminAntadisConfiguratorProduct', 'Configurator Product', 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hook
|
||||
if (!$this->registerHook('displayAdminProductsExtra') ||
|
||||
!$this->registerHook('displayProductTabContent') ||
|
||||
!$this->registerHook('displayProductForm')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All went well!
|
||||
return true;
|
||||
}
|
||||
|
||||
public function uninstall()
|
||||
{
|
||||
// Call uninstall parent method
|
||||
if (!parent::uninstall()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Menu
|
||||
if (!$this->uninstallTab('AdminAntadisConfigurator') ||
|
||||
!$this->uninstallTab('AdminAntadisConfiguratorProduct')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hook
|
||||
if (!$this->unregisterHook('displayAdminProductsExtra') ||
|
||||
!$this->unregisterHook('displayProductTabContent') ||
|
||||
!$this->unregisterHook('displayProductForm')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// All went well!
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
$ajax_hook = Tools::getValue('ajax_hook');
|
||||
if ($ajax_hook != '') {
|
||||
$ajax_method = 'hook'.ucfirst($ajax_hook);
|
||||
if (method_exists($this, $ajax_method)) {
|
||||
die($this->{$ajax_method}(array()));
|
||||
}
|
||||
}
|
||||
|
||||
$controller = $this->getHookController('getContent');
|
||||
return $controller->run();
|
||||
}
|
||||
|
||||
public function installTab($parent, $class_name, $name, $active = 1)
|
||||
{
|
||||
// Create new admin tab
|
||||
$tab = new Tab();
|
||||
$tab->id_parent = (int)Tab::getIdFromClassName($parent);
|
||||
$tab->name = array();
|
||||
foreach (Language::getLanguages(true) as $lang) {
|
||||
$tab->name[$lang['id_lang']] = $name;
|
||||
$tab->class_name = $class_name;
|
||||
$tab->module = $this->name;
|
||||
$tab->active = $active;
|
||||
return $tab->add();
|
||||
}
|
||||
}
|
||||
|
||||
public function uninstallTab($class_name)
|
||||
{
|
||||
// Retrieve Tab ID
|
||||
$id_tab = (int)Tab::getIdFromClassName($class_name);
|
||||
|
||||
// Load tab
|
||||
$tab = new Tab((int)$id_tab);
|
||||
|
||||
// Delete it
|
||||
return $tab->delete();
|
||||
}
|
||||
|
||||
public function getHookController($hook_name)
|
||||
{
|
||||
// Include the controller file
|
||||
require_once(dirname(__FILE__).'/controllers/hook/'. $hook_name.'.php');
|
||||
|
||||
// Build dynamically the controller name
|
||||
$controller_name = $this->name.$hook_name.'Controller';
|
||||
|
||||
// Instantiate controller
|
||||
$controller = new $controller_name($this, __FILE__, $this->_path);
|
||||
|
||||
// Return the controller
|
||||
return $controller;
|
||||
}
|
||||
|
||||
public function hookDisplayAdminProductsExtra($params)
|
||||
{
|
||||
$controller = $this->getHookController('displayAdminProductsExtra');
|
||||
return $controller->run();
|
||||
}
|
||||
|
||||
public function hookDisplayProductTabContent($params)
|
||||
{
|
||||
$controller = $this->getHookController('displayProductTabContent');
|
||||
return $controller->run();
|
||||
}
|
||||
|
||||
public function hookDisplayProductForm($params)
|
||||
{
|
||||
$controller = $this->getHookController('displayProductForm');
|
||||
return $controller->run();
|
||||
}
|
||||
}
|
123
www/modules/antadisconfigurator/classes/ConfiguratorOpt.php
Normal file
123
www/modules/antadisconfigurator/classes/ConfiguratorOpt.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
class ConfiguratorOpt extends ObjectModel
|
||||
{
|
||||
public $id_configurator_opt_group;
|
||||
public $price;
|
||||
public $position;
|
||||
|
||||
public $name;
|
||||
|
||||
public static $definition = array(
|
||||
'table' => 'configurator_opt',
|
||||
'primary' => 'id_configurator_opt',
|
||||
'multilang' => true,
|
||||
'fields' => array(
|
||||
'id_configurator_opt_group' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
|
||||
|
||||
'price' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice', 'required' => true),
|
||||
'position' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
|
||||
|
||||
/* Lang fields */
|
||||
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 255),
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Move an attribute inside its group
|
||||
* @param bool $way Up (1) or Down (0)
|
||||
* @param int $position
|
||||
* @return bool Update result
|
||||
*/
|
||||
public function updatePosition($way, $position)
|
||||
{
|
||||
if (!$id_configurator_opt_group = (int)Tools::getValue('id_configurator_opt_group')) {
|
||||
$id_configurator_opt_group = (int)$this->id_configurator_opt_group;
|
||||
}
|
||||
|
||||
$sql = '
|
||||
SELECT a.`id_configurator_opt`, a.`position`, a.`id_configurator_opt_group`
|
||||
FROM `'._DB_PREFIX_.'configurator_opt` a
|
||||
WHERE a.`id_configurator_opt_group` = '.(int)$id_configurator_opt_group.'
|
||||
ORDER BY a.`position` ASC';
|
||||
|
||||
if (!$res = Db::getInstance()->executeS($sql)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($res as $attribute) {
|
||||
if ((int)$attribute['id_configurator_opt'] == (int)$this->id) {
|
||||
$moved_attribute = $attribute;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($moved_attribute) || !isset($position)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// < and > statements rather than BETWEEN operator
|
||||
// since BETWEEN is treated differently according to databases
|
||||
|
||||
$res1 = Db::getInstance()->execute('
|
||||
UPDATE `'._DB_PREFIX_.'configurator_opt`
|
||||
SET `position`= `position` '.($way ? '- 1' : '+ 1').'
|
||||
WHERE `position`
|
||||
'.($way
|
||||
? '> '.(int)$moved_attribute['position'].' AND `position` <= '.(int)$position
|
||||
: '< '.(int)$moved_attribute['position'].' AND `position` >= '.(int)$position).'
|
||||
AND `id_configurator_opt_group`='.(int)$moved_attribute['id_configurator_opt_group']
|
||||
);
|
||||
|
||||
$res2 = Db::getInstance()->execute('
|
||||
UPDATE `'._DB_PREFIX_.'configurator_opt`
|
||||
SET `position` = '.(int)$position.'
|
||||
WHERE `id_configurator_opt` = '.(int)$moved_attribute['id_configurator_opt'].'
|
||||
AND `id_configurator_opt_group`='.(int)$moved_attribute['id_configurator_opt_group']
|
||||
);
|
||||
|
||||
return ($res1 && $res2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder attribute position in group $id_attribute_group.
|
||||
* Call it after deleting an attribute from a group.
|
||||
*
|
||||
* @param int $id_attribute_group
|
||||
* @param bool $use_last_attribute
|
||||
* @return bool $return
|
||||
*/
|
||||
public function cleanPositions($id_configurator_opt_group, $use_last = true)
|
||||
{
|
||||
Db::getInstance()->execute('SET @i = -1', false);
|
||||
$sql = 'UPDATE `'._DB_PREFIX_.'configurator_opt` SET `position` = @i:=@i+1 WHERE';
|
||||
|
||||
if ($use_last) {
|
||||
$sql .= ' `id_configurator_opt` != '.(int)$this->id.' AND';
|
||||
}
|
||||
|
||||
$sql .= ' `id_configurator_opt_group` = '.(int)$id_configurator_opt_group.' ORDER BY `position` ASC';
|
||||
|
||||
$return = Db::getInstance()->execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* getHigherPosition
|
||||
*
|
||||
* Get the higher attribute position from a group attribute
|
||||
*
|
||||
* @param int $id_attribute_group
|
||||
* @return int $position
|
||||
*/
|
||||
public static function getHigherPosition($id_configurator_opt_group)
|
||||
{
|
||||
$sql = 'SELECT MAX(`position`)
|
||||
FROM `'._DB_PREFIX_.'configurator_opt`
|
||||
WHERE id_configurator_opt_group = '.(int)$id_configurator_opt_group;
|
||||
|
||||
$position = DB::getInstance()->getValue($sql);
|
||||
|
||||
return (is_numeric($position)) ? $position : -1;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
class ConfiguratorOptGroup extends ObjectModel
|
||||
{
|
||||
public $id_configurator_opt_group;
|
||||
public $type;
|
||||
public $reference;
|
||||
|
||||
public $name;
|
||||
|
||||
public static $definition = array(
|
||||
'table' => 'configurator_opt_group',
|
||||
'primary' => 'id_configurator_opt_group',
|
||||
'multilang' => true,
|
||||
'fields' => array(
|
||||
'type' => array('type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true),
|
||||
'reference' => array('type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true),
|
||||
|
||||
/* Lang fields */
|
||||
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 255),
|
||||
),
|
||||
|
||||
'associations' => array(
|
||||
'options' => array('type' => self::HAS_MANY, 'field' => 'id_configurator_opt_group', 'object' => 'ConfiguratorOpt', 'association' => 'configurator_opt'),
|
||||
),
|
||||
);
|
||||
|
||||
public function getConfiguratorOptName()
|
||||
{
|
||||
$id_lang = (int)Context::getContext()->language->id;
|
||||
return $this->name[$id_lang];
|
||||
}
|
||||
|
||||
public static function getAll()
|
||||
{
|
||||
$id_lang = (int)Context::getContext()->language->id;
|
||||
|
||||
$opts = Db::getInstance()->executeS('
|
||||
SELECT cog.*, cogl.name
|
||||
FROM `'._DB_PREFIX_.'configurator_opt_group` cog, `'._DB_PREFIX_.'configurator_opt_group_lang` cogl
|
||||
WHERE cog.id_configurator_opt_group = cogl.id_configurator_opt_group AND cogl.id_lang = '.(int)$id_lang);
|
||||
|
||||
return $opts;
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
// Supprimer les Opt associés
|
||||
}
|
||||
|
||||
|
||||
public static function getValues($id_configurator_opt_group)
|
||||
{
|
||||
$id_lang = (int)Context::getContext()->language->id;
|
||||
|
||||
$sql = 'SELECT co.*, col.name
|
||||
FROM `'._DB_PREFIX_.'configurator_opt` co
|
||||
LEFT JOIN `'._DB_PREFIX_.'configurator_opt_lang` col ON co.`id_configurator_opt` = col.`id_configurator_opt`
|
||||
WHERE co.`id_configurator_opt_group` = '.(int)$id_configurator_opt_group.' AND col.`id_lang` = '.(int)$id_lang;
|
||||
|
||||
$result = Db::getInstance()->executeS($sql);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
class ProductConfiguratorOptGroup extends ObjectModel
|
||||
{
|
||||
public $id_product_configurator_opt_group;
|
||||
public $id_product;
|
||||
public $id_configurator_opt_group;
|
||||
public $required;
|
||||
public $position;
|
||||
|
||||
|
||||
public static $definition = array(
|
||||
'table' => 'product_configurator_opt_group',
|
||||
'primary' => 'id_product_configurator_opt_group',
|
||||
'multilang' => false,
|
||||
'fields' => array(
|
||||
'id_product' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
|
||||
'id_configurator_opt_group' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
|
||||
'required' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'required' => true),
|
||||
'position' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
|
||||
),
|
||||
);
|
||||
|
||||
public static function getProductConfiguratorOptGroup($id_product)
|
||||
{
|
||||
$id_lang = (int)Context::getContext()->language->id;
|
||||
|
||||
$opts = Db::getInstance()->executeS('
|
||||
SELECT pcog.*, col.`name` FROM `'._DB_PREFIX_.'product_configurator_opt_group` pcog, `'._DB_PREFIX_.'configurator_opt_group_lang` col
|
||||
WHERE pcog.`id_product` = '.(int)$id_product.'
|
||||
AND pcog.`id_configurator_opt_group` = col.`id_configurator_opt_group`
|
||||
AND col.`id_lang` = '.(int)$id_lang.'
|
||||
ORDER BY pcog.`position` ASC');
|
||||
|
||||
return $opts;
|
||||
}
|
||||
|
||||
public function getConfiguratorOptGroupName()
|
||||
{
|
||||
$id_lang = (int)Context::getContext()->language->id;
|
||||
return Db::getInstance()->getValue('
|
||||
SELECT `name`
|
||||
FROM `'._DB_PREFIX_.'configurator_opt_group_lang`
|
||||
WHERE `id_configurator_opt_group` = '.(int)$this->id_configurator_opt_group.' AND `id_lang` = '.(int)$id_lang);
|
||||
}
|
||||
|
||||
/**
|
||||
* getHigherPosition
|
||||
*
|
||||
* Get the higher position
|
||||
*
|
||||
* @param int $id_product
|
||||
* @return int $position
|
||||
*/
|
||||
public static function getHigherPosition($id_product)
|
||||
{
|
||||
$sql = 'SELECT MAX(`position`)
|
||||
FROM `'._DB_PREFIX_.'product_configurator_opt_group`
|
||||
WHERE id_product = '.(int)$id_product;
|
||||
|
||||
$position = DB::getInstance()->getValue($sql);
|
||||
|
||||
return (is_numeric($position)) ? $position : -1;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
class ProductConfiguratorOptImpact extends ObjectModel
|
||||
{
|
||||
public $id_product_configurator_opt_impact;
|
||||
public $id_product;
|
||||
public $id_product_configurator_opt_group;
|
||||
public $id_configurator_opt;
|
||||
public $price;
|
||||
|
||||
public static $definition = array(
|
||||
'table' => 'product_configurator_opt_impact',
|
||||
'primary' => 'id_product_configurator_opt_impact',
|
||||
'multilang' => false,
|
||||
'fields' => array(
|
||||
'id_product' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
|
||||
'id_product_configurator_opt_group' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
|
||||
'id_configurator_opt' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true),
|
||||
'price' => array('type' => self::TYPE_FLOAT, 'validate' => 'isPrice', 'required' => true),
|
||||
),
|
||||
);
|
||||
|
||||
public static function getProductOptImpact($id_product)
|
||||
{
|
||||
$context = Context::getContext();
|
||||
|
||||
$result = Db::getInstance()->executeS('
|
||||
SELECT pcoi.*, co.*, col.name FROM `ps_product_configurator_opt_impact` pcoi, ps_configurator_opt co
|
||||
LEFT JOIN ps_configurator_opt_lang col ON (col.id_configurator_opt = co.id_configurator_opt AND col.id_lang = 1)
|
||||
WHERE pcoi.id_product = 1 AND pcoi.id_configurator_opt = co.id_configurator_opt
|
||||
ORDER BY position ASC');
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@ -0,0 +1,468 @@
|
||||
<?php
|
||||
|
||||
class AdminAntadisConfiguratorController extends ModuleAdminController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->table = 'configurator_opt_group';
|
||||
$this->className = 'ConfiguratorOptGroup';
|
||||
$this->lang = true;
|
||||
|
||||
// Set fields list
|
||||
$this->fields_list = array(
|
||||
'id_configurator_opt_group' => array(
|
||||
'title' => $this->l('ID'),
|
||||
'align' => 'center',
|
||||
'width' => 25
|
||||
),
|
||||
'name' => array(
|
||||
'title' => $this->l('Nom')
|
||||
),
|
||||
'type' => array(
|
||||
'title' => $this->l('Type')
|
||||
),
|
||||
'reference' => array(
|
||||
'title' => $this->l('Reference')
|
||||
),
|
||||
);
|
||||
|
||||
// Enable bootstrap
|
||||
$this->bootstrap = true;
|
||||
|
||||
// Call of the parent constructor method
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* AdminController::renderList() override
|
||||
* @see AdminController::renderList()
|
||||
*/
|
||||
public function renderList()
|
||||
{
|
||||
$this->addRowAction('view');
|
||||
$this->addRowAction('edit');
|
||||
$this->addRowAction('delete');
|
||||
|
||||
return parent::renderList();
|
||||
}
|
||||
|
||||
public function renderView()
|
||||
{
|
||||
// Afficher la liste des valeurs de l'option
|
||||
if (($id = Tools::getValue('id_configurator_opt_group'))) {
|
||||
$this->table = 'configurator_opt';
|
||||
$this->className = 'ConfiguratorOpt';
|
||||
$this->identifier = 'id_configurator_opt';
|
||||
$this->position_identifier = 'id_configurator_opt';
|
||||
$this->list_id = 'values';
|
||||
$this->lang = true;
|
||||
|
||||
$this->context->smarty->assign(array(
|
||||
'current' => self::$currentIndex.'&id_configurator_opt_group='.(int)$id.'&viewconfigurator_opt_group'
|
||||
));
|
||||
|
||||
if (!Validate::isLoadedObject($obj = new ConfiguratorOptGroup((int)$id))) {
|
||||
$this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
|
||||
return;
|
||||
}
|
||||
|
||||
/*if ($obj->type == 'label') {
|
||||
$tpl = $this->context->smarty->createTemplate(dirname(__FILE__).'/../../views/templates/admin/antadisconfiguratorView.tpl');
|
||||
$tpl->assign('message', $this->l("Les options de type '' ne peuvent avoir de valeurs."));
|
||||
return $tpl->fetch();
|
||||
}*/
|
||||
|
||||
$this->fields_list = array(
|
||||
'id_configurator_opt' => array(
|
||||
'title' => $this->l('ID'),
|
||||
'align' => 'center',
|
||||
'class' => 'fixed-width-xs'
|
||||
),
|
||||
'name' => array(
|
||||
'title' => $this->l('Name'),
|
||||
'width' => 'auto',
|
||||
),
|
||||
'price' => array(
|
||||
'title' => $this->l('Price'),
|
||||
'type' => 'price',
|
||||
),
|
||||
);
|
||||
|
||||
switch($obj->type) {
|
||||
case 'radio':
|
||||
case 'checkbox':
|
||||
case 'select':
|
||||
$this->fields_list['position'] = array(
|
||||
'title' => $this->l('Position'),
|
||||
'filter_key' => 'a!position',
|
||||
'position' => 'position',
|
||||
'class' => 'fixed-width-md'
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->_where = 'AND a.`id_configurator_opt_group` = '.(int)$id;
|
||||
$this->_orderBy = 'position';
|
||||
|
||||
$this->addRowAction('edit');
|
||||
$this->addRowAction('delete');
|
||||
|
||||
self::$currentIndex = self::$currentIndex.'&id_configurator_opt_group='.(int)$id.'&viewconfigurator_opt_group';
|
||||
$this->processFilter();
|
||||
return parent::renderList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AdminController::init() override
|
||||
* @see AdminController::init()
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if (Tools::isSubmit('updateconfigurator_opt')) {
|
||||
$this->display = 'editValues';
|
||||
} elseif (Tools::isSubmit('submitAddconfigurator_opt')) {
|
||||
$this->display = 'editValues';
|
||||
} elseif (Tools::isSubmit('submitAddconfigurator_opt_group')) {
|
||||
$this->display = 'add';
|
||||
}
|
||||
|
||||
parent::init();
|
||||
}
|
||||
|
||||
public function initContent()
|
||||
{
|
||||
$this->initToolbar();
|
||||
$this->initPageHeaderToolbar();
|
||||
|
||||
if ($this->display == 'edit' || $this->display == 'add') {
|
||||
if (!($this->object = $this->loadObject(true))) {
|
||||
return;
|
||||
}
|
||||
$this->content .= $this->renderForm();
|
||||
} elseif ($this->display == 'editValues') {
|
||||
if (!$this->object = new ConfiguratorOpt((int)Tools::getValue('id_configurator_opt'))) {
|
||||
return;
|
||||
}
|
||||
$this->content .= $this->renderFormOpt();
|
||||
} elseif ($this->display != 'view' && !$this->ajax) {
|
||||
$this->content .= $this->renderList();
|
||||
//$this->content .= $this->renderOptions();
|
||||
} elseif ($this->display == 'view' && !$this->ajax) {
|
||||
$this->content = $this->renderView();
|
||||
}
|
||||
|
||||
$this->context->smarty->assign(array(
|
||||
'table' => $this->table,
|
||||
'current' => self::$currentIndex,
|
||||
'token' => $this->token,
|
||||
'content' => $this->content,
|
||||
'url_post' => self::$currentIndex.'&token='.$this->token,
|
||||
'show_page_header_toolbar' => $this->show_page_header_toolbar,
|
||||
'page_header_toolbar_title' => $this->page_header_toolbar_title,
|
||||
'page_header_toolbar_btn' => $this->page_header_toolbar_btn
|
||||
));
|
||||
}
|
||||
|
||||
public function initPageHeaderToolbar()
|
||||
{
|
||||
if (empty($this->display)) {
|
||||
$this->page_header_toolbar_btn['new_configurator_opt_group'] = array(
|
||||
'href' => self::$currentIndex.'&addconfigurator_opt_group&token='.$this->token,
|
||||
'desc' => $this->l('Add New Option', null, null, false),
|
||||
'icon' => 'process-icon-new'
|
||||
);
|
||||
}
|
||||
|
||||
parent::initPageHeaderToolbar();
|
||||
}
|
||||
|
||||
public function initToolbar()
|
||||
{
|
||||
switch ($this->display) {
|
||||
case 'add':
|
||||
case 'edit':
|
||||
case 'editValues':
|
||||
// Default save button - action dynamically handled in javascript
|
||||
$this->toolbar_btn['save'] = array(
|
||||
'href' => '#',
|
||||
'desc' => $this->l('Save')
|
||||
);
|
||||
|
||||
$this->toolbar_btn['back'] = array(
|
||||
'href' => self::$currentIndex.'&token='.$this->token,
|
||||
'desc' => $this->l('Back to list', null, null, false)
|
||||
);
|
||||
break;
|
||||
break;
|
||||
case 'view':
|
||||
$this->toolbar_btn['new'] = array(
|
||||
'href' => self::$currentIndex.'&updateconfigurator_opt&id_configurator_opt_group='.(int)Tools::getValue('id_configurator_opt_group').'&token='.$this->token,
|
||||
'desc' => $this->l('Add New Value', null, null, false),
|
||||
'class' => 'toolbar-new'
|
||||
);
|
||||
|
||||
$this->toolbar_btn['back'] = array(
|
||||
'href' => self::$currentIndex.'&token='.$this->token,
|
||||
'desc' => $this->l('Back to list', null, null, false)
|
||||
);
|
||||
break;
|
||||
default: // list
|
||||
$this->toolbar_btn['new'] = array(
|
||||
'href' => self::$currentIndex.'&add'.$this->table.'&token='.$this->token,
|
||||
'desc' => $this->l('Add New Option', null, null, false)
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function initProcess()
|
||||
{
|
||||
$this->setTypeOpt();
|
||||
|
||||
if (Tools::getIsset('viewconfigurator_opt_group')) {
|
||||
$this->list_id = 'values';
|
||||
|
||||
if (isset($_POST['submitReset'.$this->list_id])) {
|
||||
$this->processResetFilters();
|
||||
}
|
||||
} else {
|
||||
$this->list_id = 'group';
|
||||
}
|
||||
|
||||
parent::initProcess();
|
||||
|
||||
if ($this->table == 'configurator_opt') {
|
||||
$this->display = 'editValues';
|
||||
$this->id_configurator_opt = (int)Tools::getValue('id_configurator_opt');
|
||||
}
|
||||
}
|
||||
|
||||
protected function setTypeOpt()
|
||||
{
|
||||
if (Tools::isSubmit('updateconfigurator_opt') || Tools::isSubmit('deleteconfigurator_opt') ||
|
||||
Tools::isSubmit('submitAddconfigurator_opt')) {
|
||||
$this->table = 'configurator_opt';
|
||||
$this->className = 'ConfiguratorOpt';
|
||||
$this->identifier = 'id_configurator_opt';
|
||||
|
||||
if ($this->display == 'edit') {
|
||||
$this->display = 'editValues';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Form option
|
||||
* {@inheritDoc}
|
||||
* @see AdminControllerCore::renderForm()
|
||||
*/
|
||||
public function renderForm()
|
||||
{
|
||||
$this->table = 'configurator_opt_group';
|
||||
$this->identifier = 'id_configurator_opt_group';
|
||||
|
||||
$this->show_form_cancel_button = true;
|
||||
|
||||
$this->fields_form = array(
|
||||
'legend' => array('title' => $this->l('Add / Edit')),
|
||||
'input' => array(
|
||||
array('type' => 'text', 'label' => $this->l('Name'), 'name' => 'name', 'required' => true, 'lang' => true),
|
||||
array('type' => 'select', 'label' => $this->l('Type'), 'name' => 'type', 'required' => true,
|
||||
'options' => array(
|
||||
'id' => 'id',
|
||||
'name' => 'name',
|
||||
'query' => array(
|
||||
array('id' => 'text', 'name' => 'Texte saisie'),
|
||||
array('id' => 'date', 'name' => 'Date'),
|
||||
array('id' => 'select', 'name' => 'Selection'),
|
||||
array('id' => 'radio', 'name' => 'Choix unique'),
|
||||
array('id' => 'checkbox', 'name' => 'Choix multiple'),
|
||||
),
|
||||
),
|
||||
),
|
||||
array('type' => 'text', 'label' => $this->l('Reference'), 'name' => 'reference', 'required' => true),
|
||||
),
|
||||
'submit' => array('title' => $this->l('Save'))
|
||||
);
|
||||
|
||||
return parent::renderForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Form option value
|
||||
* @return string
|
||||
*/
|
||||
public function renderFormOpt()
|
||||
{
|
||||
$this->table = 'configurator_opt';
|
||||
$this->identifier = 'id_configurator_opt';
|
||||
|
||||
$this->show_form_cancel_button = true;
|
||||
$this->fields_form = array(
|
||||
'legend' => array('title' => $this->l('Add / Edit')),
|
||||
'input' => array(
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'id_configurator_opt_group',
|
||||
'required' => true,
|
||||
),
|
||||
array(
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Name'),
|
||||
'name' => 'name',
|
||||
'required' => true,
|
||||
'lang' => true
|
||||
),
|
||||
array(
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Value'),
|
||||
'name' => 'value',
|
||||
'required' => true,
|
||||
),
|
||||
array(
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Price'),
|
||||
'name' => 'price',
|
||||
'required' => true
|
||||
),
|
||||
),
|
||||
'submit' => array(
|
||||
'title' => $this->l('Save')
|
||||
),
|
||||
);
|
||||
|
||||
$this->fields_value['id_configurator_opt_group'] = (int)Tools::getValue('id_configurator_opt_group');
|
||||
|
||||
// Override var of Controller
|
||||
$this->table = 'configurator_opt';
|
||||
$this->className = 'ConfiguratorOpt';
|
||||
$this->identifier = 'id_configurator_opt';
|
||||
$this->lang = true;
|
||||
|
||||
// Create object Attribute
|
||||
if (!$obj = new ConfiguratorOpt((int)Tools::getValue($this->identifier))) {
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::renderForm();
|
||||
}
|
||||
|
||||
public function postProcess()
|
||||
{
|
||||
if (!Tools::getValue($this->identifier) && Tools::getValue('id_configurator_opt') && !Tools::getValue('attributeOrderby')) {
|
||||
// Override var of Controller
|
||||
$this->table = 'configurator_opt';
|
||||
$this->className = 'ConfiguratorOpt';
|
||||
$this->identifier = 'id_configurator_opt';
|
||||
}
|
||||
|
||||
// If Opt, load object
|
||||
if (Tools::getValue('updateconfigurator_opt') || Tools::isSubmit('deleteconfigurator_opt') || Tools::isSubmit('submitAddconfigurator_opt')) {
|
||||
if (!$object = new ConfiguratorOpt((int)Tools::getValue($this->identifier))) {
|
||||
$this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
|
||||
}
|
||||
if (Tools::getValue('position') !== false && Tools::getValue('id_configurator_opt')) {
|
||||
$_POST['id_configurator_opt_group'] = $object->id_configurator_opt_group;
|
||||
if (!$object->updatePosition((int)Tools::getValue('way'), (int)Tools::getValue('position'))) {
|
||||
$this->errors[] = Tools::displayError('Failed to update the position.');
|
||||
} else {
|
||||
Tools::redirectAdmin(self::$currentIndex.'&conf=5&token='.Tools::getAdminTokenLite('AdminAntadisConfigurator').'#details_details_'.$object->id_configurator_opt_group);
|
||||
}
|
||||
} elseif (Tools::isSubmit('deleteconfigurator_opt') && Tools::getValue('id_configurator_opt')) {
|
||||
if (!$object->delete()) {
|
||||
$this->errors[] = Tools::displayError('Failed to delete the attribute.');
|
||||
} else {
|
||||
Tools::redirectAdmin(self::$currentIndex.'&conf=1&token='.Tools::getAdminTokenLite('AdminAntadisConfigurator'));
|
||||
}
|
||||
} elseif (Tools::isSubmit('submitAddconfigurator_opt')) {
|
||||
Hook::exec('actionObjectConfiguratorOptAddBefore');
|
||||
$this->action = 'save';
|
||||
$id_configurator_opt = (int)Tools::getValue('id_configurator_opt');
|
||||
// Adding last position to the attribute if not exist
|
||||
if ($id_configurator_opt <= 0) {
|
||||
$sql = 'SELECT `position`+1
|
||||
FROM `'._DB_PREFIX_.'configurator_opt`
|
||||
WHERE `id_configurator_opt_group` = '.(int)Tools::getValue('id_configurator_opt_group').'
|
||||
ORDER BY position DESC';
|
||||
// set the position of the new group attribute in $_POST for postProcess() method
|
||||
$_POST['position'] = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
|
||||
}
|
||||
$_POST['id_parent'] = 0;
|
||||
$this->processSave($this->token);
|
||||
}
|
||||
|
||||
} else {
|
||||
parent::postProcess();
|
||||
}
|
||||
}
|
||||
|
||||
public function processSave()
|
||||
{
|
||||
if ($this->display == 'add' || $this->display == 'edit') {
|
||||
$this->identifier = 'id_configurator_opt_group';
|
||||
}
|
||||
|
||||
if (!$this->id_object) {
|
||||
return $this->processAdd();
|
||||
} else {
|
||||
return $this->processUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public function processDelete()
|
||||
{
|
||||
Tools::dieObject("@todo : Gérer la suppression avec les sous éléments");
|
||||
}
|
||||
|
||||
public function processPosition()
|
||||
{
|
||||
if (Tools::getIsset('viewconfigurator_opt_group')) {
|
||||
$object = new ConfiguratorOpt((int)Tools::getValue('id_configurator_opt'));
|
||||
self::$currentIndex = self::$currentIndex.'&viewconfigurator_opt_group';
|
||||
}
|
||||
|
||||
if (!Validate::isLoadedObject($object)) {
|
||||
$this->errors[] = Tools::displayError('An error occurred while updating the status for an object.').
|
||||
' <b>'.$this->table.'</b> '.Tools::displayError('(cannot load object)');
|
||||
} elseif (!$object->updatePosition((int)Tools::getValue('way'), (int)Tools::getValue('position'))) {
|
||||
$this->errors[] = Tools::displayError('Failed to update the position.');
|
||||
} else {
|
||||
$id_identifier_str = ($id_identifier = (int)Tools::getValue($this->identifier)) ? '&'.$this->identifier.'='.$id_identifier : '';
|
||||
$redirect = self::$currentIndex.'&'.$this->table.'Orderby=position&'.$this->table.'Orderway=asc&conf=5'.$id_identifier_str.'&token='.$this->token;
|
||||
$this->redirect_after = $redirect;
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify position
|
||||
*/
|
||||
public function ajaxProcessUpdatePositions()
|
||||
{
|
||||
$way = (int)Tools::getValue('way');
|
||||
$id_configurator_opt = (int)Tools::getValue('id_configurator_opt');
|
||||
$id_configurator_opt_group = (int)Tools::getValue('id_configurator_opt_group');
|
||||
$positions = Tools::getValue('configurator_opt');
|
||||
|
||||
if (is_array($positions)) {
|
||||
foreach ($positions as $position => $value) {
|
||||
$pos = explode('_', $value);
|
||||
|
||||
if ((isset($pos[1]) && isset($pos[2])) && (int)$pos[2] === $id_configurator_opt) {
|
||||
if ($opt = new ConfiguratorOpt((int)$pos[2])) {
|
||||
if (isset($position) && $opt->updatePosition($way, $position)) {
|
||||
echo 'ok position '.(int)$position.' for values '.(int)$pos[2].'\r\n';
|
||||
} else {
|
||||
echo '{"hasError" : true, "errors" : "Can not update the '.(int)$id_configurator_opt.' values to position '.(int)$position.' "}';
|
||||
}
|
||||
} else {
|
||||
echo '{"hasError" : true, "errors" : "The ('.(int)$id_configurator_opt.') values cannot be loaded"}';
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
<?php
|
||||
class AdminAntadisConfiguratorProductController extends ModuleAdminController
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->module = 'antadisconfigurator';
|
||||
$this->context = Context::getContext();
|
||||
|
||||
$this->table = 'product_configurator_opt_impact';
|
||||
$this->className = 'ProductConfiguratorOptImpact';
|
||||
|
||||
// Enable bootstrap
|
||||
$this->bootstrap = true;
|
||||
|
||||
// Call of the parent constructor method
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Associe l'option et les valeurs au produit
|
||||
*/
|
||||
public function ajaxProcessAdd()
|
||||
{
|
||||
$id_configurator_opt_group = Tools::getValue('id_configurator_opt_group');
|
||||
$id_product = Tools::getValue('id_product');
|
||||
|
||||
// Associer OptGroup
|
||||
$result = Db::getInstance()->insert('product_configurator_opt_group', array(
|
||||
'id_product' => $id_product,
|
||||
'id_configurator_opt_group' => $id_configurator_opt_group,
|
||||
'required' => 0,
|
||||
'position' => ProductConfiguratorOptGroup::getHigherPosition($id_product) + 1,
|
||||
));
|
||||
if ($result) {
|
||||
$id_product_configurator_opt_group = Db::getInstance()->Insert_ID();
|
||||
|
||||
// Get OptGroup values
|
||||
$values = ConfiguratorOptGroup::getValues($id_configurator_opt_group);
|
||||
// Associer OptImpact
|
||||
foreach($values as $v) {
|
||||
$impact = new ProductConfiguratorOptImpact();
|
||||
$impact->id_product = $id_product;
|
||||
$impact->id_product_configurator_opt_group = $id_product_configurator_opt_group;
|
||||
$impact->id_configurator_opt = $v['id_configurator_opt'];
|
||||
$impact->price = $v['price'];
|
||||
$impact->save();
|
||||
}
|
||||
|
||||
$return = array(
|
||||
'result' => $result,
|
||||
);
|
||||
} else {
|
||||
$return = array(
|
||||
'hasError' => true,
|
||||
'errors' => $this->l("Insert error : ".Db::getInstance()->getMsgError()),
|
||||
);
|
||||
}
|
||||
|
||||
echo Tools::jsonEncode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set required status
|
||||
*/
|
||||
public function ajaxProcessStatusProductConfiguratorOptGroup()
|
||||
{
|
||||
if (!$id_product_configurator_opt_group = Tools::getValue('id_product_configurator_opt_group')) {
|
||||
die(Tools::jsonEncode(array('success' => false, 'error' => 'true', 'text' => $this->l('Failed to update the required status'))));
|
||||
} else {
|
||||
$optGroup = new ProductConfiguratorOptGroup((int)$id_product_configurator_opt_group);
|
||||
if (Validate::isLoadedObject($optGroup)) {
|
||||
$optGroup->required = $optGroup->required == 1 ? 0 : 1;
|
||||
$optGroup->save() ?
|
||||
die(Tools::jsonEncode(array('success' => true, 'text' => $this->l('The required status has been updated successfully')))) :
|
||||
die(Tools::jsonEncode(array('success' => false, 'error' => true, 'text' => $this->l('Failed to update the required status'))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function processDelete()
|
||||
{
|
||||
Tools::d("@todo : Gérer la suppression");
|
||||
}
|
||||
|
||||
/**
|
||||
* Display impact list
|
||||
* {@inheritDoc}
|
||||
* @see AdminControllerCore::renderList()
|
||||
*/
|
||||
public function renderList()
|
||||
{
|
||||
$id_product = Tools::getValue('id_product');
|
||||
$id_product_configurator_opt_group = Tools::getValue('id_product_configurator_opt_group');
|
||||
|
||||
$optGroup = new ProductConfiguratorOptGroup($id_product_configurator_opt_group);
|
||||
$this->toolbar_title = Product::getProductName($id_product) . ' - ' . $optGroup->getConfiguratorOptGroupName() . ' - Options Impact';
|
||||
$this->toolbar_btn['back'] = array(
|
||||
'href' => $this->context->link->getAdminLink('AdminProducts', true).'&updateproduct&id_product='.(int)$id_product,
|
||||
'desc' => $this->l('Back to product', null, null, false)
|
||||
);
|
||||
|
||||
// Set fields list
|
||||
$this->fields_list = array(
|
||||
'id_product_configurator_opt_impact' => array(
|
||||
'title' => $this->l('ID'),
|
||||
'align' => 'center',
|
||||
'width' => 25,
|
||||
'search' => false,
|
||||
),
|
||||
'name' => array(
|
||||
'title' => $this->l('Value'),
|
||||
'search' => false,
|
||||
),
|
||||
'price' => array(
|
||||
'title' => $this->l('Price impact'),
|
||||
'search' => false,
|
||||
'type' => 'price',
|
||||
),
|
||||
);
|
||||
|
||||
$this->_select = 'col.`name` AS name';
|
||||
$this->_join = '
|
||||
LEFT JOIN `'._DB_PREFIX_.'configurator_opt_lang` col ON (col.`id_configurator_opt` = a.`id_configurator_opt` AND col.`id_lang` = '.(int)$this->context->language->id.')';
|
||||
|
||||
$this->_where = ' AND a.`id_product` = '.(int)$id_product.' AND a.`id_product_configurator_opt_group` = '.(int)$id_product_configurator_opt_group;
|
||||
|
||||
self::$currentIndex = self::$currentIndex.'&id_product='.$id_product;
|
||||
$this->addRowAction('edit');
|
||||
|
||||
return parent::renderList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change price impact
|
||||
* {@inheritDoc}
|
||||
* @see AdminControllerCore::renderForm()
|
||||
*/
|
||||
public function renderForm()
|
||||
{
|
||||
$id_product_configurator_opt_impact= Tools::getValue('id_product_configurator_opt_impact');
|
||||
|
||||
$optImpact = new ProductConfiguratorOptImpact($id_product_configurator_opt_impact);
|
||||
|
||||
$this->fields_form = array(
|
||||
'legend' => array('title' => $this->l('Edit price impact')),
|
||||
'input' => array(
|
||||
'id_product_configurator_opt_impact' => array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'id_product_configurator_opt_impact',
|
||||
),
|
||||
'id_product' => array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'id_product',
|
||||
),
|
||||
'id_product_configurator_opt_group' => array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'id_product_configurator_opt_group',
|
||||
),
|
||||
'id_configurator_opt' => array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'id_configurator_opt',
|
||||
),
|
||||
'price' => array(
|
||||
'type' => 'text',
|
||||
'label' => $this->l('Price'),
|
||||
'name' => 'price',
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
'submit' => array('title' => $this->l('Save')),
|
||||
);
|
||||
|
||||
// Override cancel
|
||||
self::$currentIndex = $this->context->link->getAdminLink('AdminAntadisConfiguratorProduct', false).
|
||||
'&id_product='.$optImpact->id_product.'&id_product_configurator_opt_group='.$optImpact->id_product_configurator_opt_group;
|
||||
|
||||
|
||||
$this->fields_value = array(
|
||||
'id_product_configurator_opt_impact' => $optImpact->id_product_configurator_opt_impact,
|
||||
'id_product' => $optImpact->id_product,
|
||||
'id_product_configurator_opt_group' => $optImpact->id_product_configurator_opt_group,
|
||||
'id_configurator_opt' => $optImpact->id_configurator_opt,
|
||||
'price' => $optImpact->price,
|
||||
);
|
||||
|
||||
return parent::renderForm();
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
class AntadisConfiguratorDisplayAdminProductsExtraController
|
||||
{
|
||||
/**
|
||||
* @var ModuleAdminController
|
||||
*/
|
||||
protected $module;
|
||||
|
||||
/**
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
public function __construct($module, $file, $path)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->module = $module;
|
||||
$this->context = Context::getContext();
|
||||
$this->_path = $path;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
// Display list of option
|
||||
|
||||
$id_product = (int)Tools::getValue('id_product');
|
||||
|
||||
$fields_list = array(
|
||||
'id_product_configurator_opt_group' => array(
|
||||
'title' => $this->module->l('ID')
|
||||
),
|
||||
'name' => array(
|
||||
'title' => $this->module->l('Option Name'),
|
||||
),
|
||||
'required' => array(
|
||||
'title' => $this->module->l('Required'),
|
||||
'active' => 'status',
|
||||
'type' => 'bool',
|
||||
'ajax' => true,
|
||||
),
|
||||
'position' => array(
|
||||
'title' => $this->module->l('Position'),
|
||||
'filter_key' => 'a!position',
|
||||
'position' => 'position',
|
||||
'class' => 'fixed-width-md'
|
||||
),
|
||||
);
|
||||
|
||||
// Get option group
|
||||
$productOptGroupList = ProductConfiguratorOptGroup::getProductConfiguratorOptGroup($id_product);
|
||||
|
||||
// Helper list
|
||||
$helper = new HelperList();
|
||||
$helper->simple_header = true;
|
||||
$helper->bootstrap = true;
|
||||
$helper->table = 'product_configurator_opt_group';
|
||||
$helper->identifier = 'id_product_configurator_opt_group';
|
||||
$helper->title = $this->module->l('Product Options');
|
||||
$helper->position_identifier = 'id_product_configurator_opt_group';
|
||||
$helper->orderBy = 'position';
|
||||
|
||||
$helper->actions = array('delete');
|
||||
|
||||
$helper->token = Tools::getAdminTokenLite('AdminAntadisConfiguratorProduct');
|
||||
$helper->currentIndex = $this->context->link->getAdminLink('AdminAntadisConfiguratorProduct').'&id_product='.(int)$id_product;
|
||||
|
||||
// Available options
|
||||
$optGroupList = ConfiguratorOptGroup::getAll();
|
||||
|
||||
$this->context->smarty->assign(array(
|
||||
'token' => Tools::getAdminTokenLite('AdminAntadisConfiguratorProduct'),
|
||||
'id_product' => $id_product,
|
||||
'OptGroupList' => $optGroupList,
|
||||
'OptGroupListFormLink' => $this->context->link->getAdminLink('AdminProducts').'&id_product='.(int)$id_product,
|
||||
'ProductOptGroupList' => $helper->generateList($productOptGroupList, $fields_list),
|
||||
));
|
||||
|
||||
return $this->module->display($this->file, 'displayAdminProductsExtra.tpl');
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
class AntadisConfiguratorDisplayProductFormController
|
||||
{
|
||||
/**
|
||||
* @var ModuleAdminController
|
||||
*/
|
||||
protected $module;
|
||||
|
||||
/**
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
public function __construct($module, $file, $path)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->module = $module;
|
||||
$this->context = Context::getContext();
|
||||
$this->_path = $path;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$id_product = Tools::getValue('id_product');
|
||||
|
||||
// Get Product
|
||||
// Get Options associées au produit
|
||||
// Tableau Multi Niveau
|
||||
// => Option Group : label / name / ref
|
||||
// => Liste des Valeurs : name / value / price
|
||||
|
||||
$optGroupList = Product::getConfiguratorOptGroup($id_product);
|
||||
$optImpact = Product::getConfiguratorOptImpact($id_product);
|
||||
$optImpactList = array();
|
||||
if (count($optImpact) > 0) {
|
||||
foreach ($optImpact as $o) {
|
||||
$optImpactList[$o['id_product_configurator_opt_group']][] = $o;
|
||||
}
|
||||
}
|
||||
|
||||
$this->context->smarty->assign('token', Tools::getToken(false));
|
||||
$this->context->smarty->assign('optGroupList', $optGroupList);
|
||||
$this->context->smarty->assign('optImpactList', $optImpactList);
|
||||
|
||||
return $this->module->display($this->file, 'displayProductForm.tpl');
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
class AntadisConfiguratorDisplayProductTabContentController
|
||||
{
|
||||
/**
|
||||
* @var ModuleAdminController
|
||||
*/
|
||||
protected $module;
|
||||
|
||||
/**
|
||||
* @var Context
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
public function __construct($module, $file, $path)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->module = $module;
|
||||
$this->context = Context::getContext();
|
||||
$this->_path = $path;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$isActivated = false;
|
||||
if($isActivated === true) {
|
||||
$id_product = Tools::getValue('id_product');
|
||||
|
||||
// Get Product
|
||||
// Get Options associées au produit
|
||||
// Tableau Multi Niveau
|
||||
// => Option Group : label / name / ref
|
||||
// => Liste des Valeurs : name / value / price
|
||||
|
||||
$optGroupList = Product::getConfiguratorOptGroup($id_product);
|
||||
$optImpact = Product::getConfiguratorOptImpact($id_product);
|
||||
$optImpactList = array();
|
||||
if (count($optImpact) > 0) {
|
||||
foreach ($optImpact as $o) {
|
||||
$optImpactList[$o['id_product_configurator_opt_group']][] = $o;
|
||||
}
|
||||
}
|
||||
|
||||
$this->context->smarty->assign('token', Tools::getToken(false));
|
||||
$this->context->smarty->assign('optGroupList', $optGroupList);
|
||||
$this->context->smarty->assign('optImpactList', $optImpactList);
|
||||
|
||||
return $this->module->display($this->file, 'displayProductTabContent.tpl');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
class AntadisConfiguratorGetContentController
|
||||
{
|
||||
public function __construct($module, $file, $path)
|
||||
{
|
||||
$this->file = $file;
|
||||
$this->module = $module;
|
||||
$this->context = Context::getContext(); $this->_path = $path;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$html = $this->module->display($this->file, 'getContent.tpl');
|
||||
return $html;
|
||||
}
|
||||
}
|
35
www/modules/antadisconfigurator/index.php
Normal file
35
www/modules/antadisconfigurator/index.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
* 2007-2016 PrestaShop
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License (AFL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* http://opensource.org/licenses/afl-3.0.php
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2016 PrestaShop SA
|
||||
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*/
|
||||
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
|
||||
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
header("Location: ../");
|
||||
exit;
|
782
www/modules/antadisconfigurator/install/themes/product.tpl
Normal file
782
www/modules/antadisconfigurator/install/themes/product.tpl
Normal file
@ -0,0 +1,782 @@
|
||||
{*
|
||||
* 2007-2016 PrestaShop
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License (AFL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* http://opensource.org/licenses/afl-3.0.php
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2016 PrestaShop SA
|
||||
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*}
|
||||
{include file="$tpl_dir./errors.tpl"}
|
||||
{if $errors|@count == 0}
|
||||
{if !isset($priceDisplayPrecision)}
|
||||
{assign var='priceDisplayPrecision' value=2}
|
||||
{/if}
|
||||
{if !$priceDisplay || $priceDisplay == 2}
|
||||
{assign var='productPrice' value=$product->getPrice(true, $smarty.const.NULL, 6)}
|
||||
{assign var='productPriceWithoutReduction' value=$product->getPriceWithoutReduct(false, $smarty.const.NULL)}
|
||||
{elseif $priceDisplay == 1}
|
||||
{assign var='productPrice' value=$product->getPrice(false, $smarty.const.NULL, 6)}
|
||||
{assign var='productPriceWithoutReduction' value=$product->getPriceWithoutReduct(true, $smarty.const.NULL)}
|
||||
{/if}
|
||||
<div itemscope itemtype="https://schema.org/Product">
|
||||
<meta itemprop="url" content="{$link->getProductLink($product)}">
|
||||
<div class="primary_block row">
|
||||
{if !$content_only}
|
||||
<div class="container">
|
||||
<div class="top-hr"></div>
|
||||
</div>
|
||||
{/if}
|
||||
{if isset($adminActionDisplay) && $adminActionDisplay}
|
||||
<div id="admin-action" class="container">
|
||||
<p class="alert alert-info">{l s='This product is not visible to your customers.'}
|
||||
<input type="hidden" id="admin-action-product-id" value="{$product->id}" />
|
||||
<a id="publish_button" class="btn btn-default button button-small" href="#">
|
||||
<span>{l s='Publish'}</span>
|
||||
</a>
|
||||
<a id="lnk_view" class="btn btn-default button button-small" href="#">
|
||||
<span>{l s='Back'}</span>
|
||||
</a>
|
||||
</p>
|
||||
<p id="admin-action-result"></p>
|
||||
</div>
|
||||
{/if}
|
||||
{if isset($confirmation) && $confirmation}
|
||||
<p class="confirmation">
|
||||
{$confirmation}
|
||||
</p>
|
||||
{/if}
|
||||
<!-- left infos-->
|
||||
<div class="pb-left-column col-xs-12 col-sm-4 col-md-5">
|
||||
<!-- product img-->
|
||||
<div id="image-block" class="clearfix">
|
||||
{if $product->new}
|
||||
<span class="new-box">
|
||||
<span class="new-label">{l s='New'}</span>
|
||||
</span>
|
||||
{/if}
|
||||
{if $product->on_sale}
|
||||
<span class="sale-box no-print">
|
||||
<span class="sale-label">{l s='Sale!'}</span>
|
||||
</span>
|
||||
{elseif $product->specificPrice && $product->specificPrice.reduction && $productPriceWithoutReduction > $productPrice}
|
||||
<span class="discount">{l s='Reduced price!'}</span>
|
||||
{/if}
|
||||
{if $have_image}
|
||||
<span id="view_full_size">
|
||||
{if $jqZoomEnabled && $have_image && !$content_only}
|
||||
<a class="jqzoom" title="{if !empty($cover.legend)}{$cover.legend|escape:'html':'UTF-8'}{else}{$product->name|escape:'html':'UTF-8'}{/if}" rel="gal1" href="{$link->getImageLink($product->link_rewrite, $cover.id_image, 'thickbox_default')|escape:'html':'UTF-8'}">
|
||||
<img itemprop="image" src="{$link->getImageLink($product->link_rewrite, $cover.id_image, 'large_default')|escape:'html':'UTF-8'}" title="{if !empty($cover.legend)}{$cover.legend|escape:'html':'UTF-8'}{else}{$product->name|escape:'html':'UTF-8'}{/if}" alt="{if !empty($cover.legend)}{$cover.legend|escape:'html':'UTF-8'}{else}{$product->name|escape:'html':'UTF-8'}{/if}"/>
|
||||
</a>
|
||||
{else}
|
||||
<img id="bigpic" itemprop="image" src="{$link->getImageLink($product->link_rewrite, $cover.id_image, 'large_default')|escape:'html':'UTF-8'}" title="{if !empty($cover.legend)}{$cover.legend|escape:'html':'UTF-8'}{else}{$product->name|escape:'html':'UTF-8'}{/if}" alt="{if !empty($cover.legend)}{$cover.legend|escape:'html':'UTF-8'}{else}{$product->name|escape:'html':'UTF-8'}{/if}" width="{$largeSize.width}" height="{$largeSize.height}"/>
|
||||
{if !$content_only}
|
||||
<span class="span_link no-print">{l s='View larger'}</span>
|
||||
{/if}
|
||||
{/if}
|
||||
</span>
|
||||
{else}
|
||||
<span id="view_full_size">
|
||||
<img itemprop="image" src="{$img_prod_dir}{$lang_iso}-default-large_default.jpg" id="bigpic" alt="" title="{$product->name|escape:'html':'UTF-8'}" width="{$largeSize.width}" height="{$largeSize.height}"/>
|
||||
{if !$content_only}
|
||||
<span class="span_link">
|
||||
{l s='View larger'}
|
||||
</span>
|
||||
{/if}
|
||||
</span>
|
||||
{/if}
|
||||
</div> <!-- end image-block -->
|
||||
{if isset($images) && count($images) > 0}
|
||||
<!-- thumbnails -->
|
||||
<div id="views_block" class="clearfix {if isset($images) && count($images) < 2}hidden{/if}">
|
||||
{if isset($images) && count($images) > 2}
|
||||
<span class="view_scroll_spacer">
|
||||
<a id="view_scroll_left" class="" title="{l s='Other views'}" href="javascript:{ldelim}{rdelim}">
|
||||
{l s='Previous'}
|
||||
</a>
|
||||
</span>
|
||||
{/if}
|
||||
<div id="thumbs_list">
|
||||
<ul id="thumbs_list_frame">
|
||||
{if isset($images)}
|
||||
{foreach from=$images item=image name=thumbnails}
|
||||
{assign var=imageIds value="`$product->id`-`$image.id_image`"}
|
||||
{if !empty($image.legend)}
|
||||
{assign var=imageTitle value=$image.legend|escape:'html':'UTF-8'}
|
||||
{else}
|
||||
{assign var=imageTitle value=$product->name|escape:'html':'UTF-8'}
|
||||
{/if}
|
||||
<li id="thumbnail_{$image.id_image}"{if $smarty.foreach.thumbnails.last} class="last"{/if}>
|
||||
<a{if $jqZoomEnabled && $have_image && !$content_only} href="javascript:void(0);" rel="{literal}{{/literal}gallery: 'gal1', smallimage: '{$link->getImageLink($product->link_rewrite, $imageIds, 'large_default')|escape:'html':'UTF-8'}',largeimage: '{$link->getImageLink($product->link_rewrite, $imageIds, 'thickbox_default')|escape:'html':'UTF-8'}'{literal}}{/literal}"{else} href="{$link->getImageLink($product->link_rewrite, $imageIds, 'thickbox_default')|escape:'html':'UTF-8'}" data-fancybox-group="other-views" class="fancybox{if $image.id_image == $cover.id_image} shown{/if}"{/if} title="{$imageTitle}">
|
||||
<img class="img-responsive" id="thumb_{$image.id_image}" src="{$link->getImageLink($product->link_rewrite, $imageIds, 'cart_default')|escape:'html':'UTF-8'}" alt="{$imageTitle}" title="{$imageTitle}"{if isset($cartSize)} height="{$cartSize.height}" width="{$cartSize.width}"{/if} itemprop="image" />
|
||||
</a>
|
||||
</li>
|
||||
{/foreach}
|
||||
{/if}
|
||||
</ul>
|
||||
</div> <!-- end thumbs_list -->
|
||||
{if isset($images) && count($images) > 2}
|
||||
<a id="view_scroll_right" title="{l s='Other views'}" href="javascript:{ldelim}{rdelim}">
|
||||
{l s='Next'}
|
||||
</a>
|
||||
{/if}
|
||||
</div> <!-- end views-block -->
|
||||
<!-- end thumbnails -->
|
||||
{/if}
|
||||
{if isset($images) && count($images) > 1}
|
||||
<p class="resetimg clear no-print">
|
||||
<span id="wrapResetImages" style="display: none;">
|
||||
<a href="{$link->getProductLink($product)|escape:'html':'UTF-8'}" data-id="resetImages">
|
||||
<i class="icon-repeat"></i>
|
||||
{l s='Display all pictures'}
|
||||
</a>
|
||||
</span>
|
||||
</p>
|
||||
{/if}
|
||||
</div> <!-- end pb-left-column -->
|
||||
<!-- end left infos-->
|
||||
<!-- center infos -->
|
||||
<div class="pb-center-column col-xs-12 col-sm-4">
|
||||
{if $product->online_only}
|
||||
<p class="online_only">{l s='Online only'}</p>
|
||||
{/if}
|
||||
<h1 itemprop="name">{$product->name|escape:'html':'UTF-8'}</h1>
|
||||
<p id="product_reference"{if empty($product->reference) || !$product->reference} style="display: none;"{/if}>
|
||||
<label>{l s='Reference:'} </label>
|
||||
<span class="editable" itemprop="sku"{if !empty($product->reference) && $product->reference} content="{$product->reference}"{/if}>{if !isset($groups)}{$product->reference|escape:'html':'UTF-8'}{/if}</span>
|
||||
</p>
|
||||
{if !$product->is_virtual && $product->condition}
|
||||
<p id="product_condition">
|
||||
<label>{l s='Condition:'} </label>
|
||||
{if $product->condition == 'new'}
|
||||
<link itemprop="itemCondition" href="https://schema.org/NewCondition"/>
|
||||
<span class="editable">{l s='New product'}</span>
|
||||
{elseif $product->condition == 'used'}
|
||||
<link itemprop="itemCondition" href="https://schema.org/UsedCondition"/>
|
||||
<span class="editable">{l s='Used'}</span>
|
||||
{elseif $product->condition == 'refurbished'}
|
||||
<link itemprop="itemCondition" href="https://schema.org/RefurbishedCondition"/>
|
||||
<span class="editable">{l s='Refurbished'}</span>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
{if $product->description_short || $packItems|@count > 0}
|
||||
<div id="short_description_block">
|
||||
{if $product->description_short}
|
||||
<div id="short_description_content" class="rte align_justify" itemprop="description">{$product->description_short}</div>
|
||||
{/if}
|
||||
|
||||
{if $product->description}
|
||||
<p class="buttons_bottom_block">
|
||||
<a href="javascript:{ldelim}{rdelim}" class="button">
|
||||
{l s='More details'}
|
||||
</a>
|
||||
</p>
|
||||
{/if}
|
||||
<!--{if $packItems|@count > 0}
|
||||
<div class="short_description_pack">
|
||||
<h3>{l s='Pack content'}</h3>
|
||||
{foreach from=$packItems item=packItem}
|
||||
|
||||
<div class="pack_content">
|
||||
{$packItem.pack_quantity} x <a href="{$link->getProductLink($packItem.id_product, $packItem.link_rewrite, $packItem.category)|escape:'html':'UTF-8'}">{$packItem.name|escape:'html':'UTF-8'}</a>
|
||||
<p>{$packItem.description_short}</p>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
{/if}-->
|
||||
</div> <!-- end short_description_block -->
|
||||
{/if}
|
||||
{if ($display_qties == 1 && !$PS_CATALOG_MODE && $PS_STOCK_MANAGEMENT && $product->available_for_order)}
|
||||
<!-- number of item in stock -->
|
||||
<p id="pQuantityAvailable"{if $product->quantity <= 0} style="display: none;"{/if}>
|
||||
<span id="quantityAvailable">{$product->quantity|intval}</span>
|
||||
<span {if $product->quantity > 1} style="display: none;"{/if} id="quantityAvailableTxt">{l s='Item'}</span>
|
||||
<span {if $product->quantity == 1} style="display: none;"{/if} id="quantityAvailableTxtMultiple">{l s='Items'}</span>
|
||||
</p>
|
||||
{/if}
|
||||
<!-- availability or doesntExist -->
|
||||
<p id="availability_statut"{if !$PS_STOCK_MANAGEMENT || ($product->quantity <= 0 && !$product->available_later && $allow_oosp) || ($product->quantity > 0 && !$product->available_now) || !$product->available_for_order || $PS_CATALOG_MODE} style="display: none;"{/if}>
|
||||
{*<span id="availability_label">{l s='Availability:'}</span>*}
|
||||
<span id="availability_value" class="label{if $product->quantity <= 0 && !$allow_oosp} label-danger{elseif $product->quantity <= 0} label-warning{else} label-success{/if}">{if $product->quantity <= 0}{if $PS_STOCK_MANAGEMENT && $allow_oosp}{$product->available_later}{else}{l s='This product is no longer in stock'}{/if}{elseif $PS_STOCK_MANAGEMENT}{$product->available_now}{/if}</span>
|
||||
</p>
|
||||
{if $PS_STOCK_MANAGEMENT}
|
||||
{if !$product->is_virtual}{hook h="displayProductDeliveryTime" product=$product}{/if}
|
||||
<p class="warning_inline" id="last_quantities"{if ($product->quantity > $last_qties || $product->quantity <= 0) || $allow_oosp || !$product->available_for_order || $PS_CATALOG_MODE} style="display: none"{/if} >{l s='Warning: Last items in stock!'}</p>
|
||||
{/if}
|
||||
<p id="availability_date"{if ($product->quantity > 0) || !$product->available_for_order || $PS_CATALOG_MODE || !isset($product->available_date) || $product->available_date < $smarty.now|date_format:'%Y-%m-%d'} style="display: none;"{/if}>
|
||||
<span id="availability_date_label">{l s='Availability date:'}</span>
|
||||
<span id="availability_date_value">{if Validate::isDate($product->available_date)}{dateFormat date=$product->available_date full=false}{/if}</span>
|
||||
</p>
|
||||
<!-- Out of stock hook -->
|
||||
<div id="oosHook"{if $product->quantity > 0} style="display: none;"{/if}>
|
||||
{$HOOK_PRODUCT_OOS}
|
||||
</div>
|
||||
{if isset($HOOK_EXTRA_RIGHT) && $HOOK_EXTRA_RIGHT}{$HOOK_EXTRA_RIGHT}{/if}
|
||||
{if !$content_only}
|
||||
<!-- usefull links-->
|
||||
<ul id="usefull_link_block" class="clearfix no-print">
|
||||
{if $HOOK_EXTRA_LEFT}{$HOOK_EXTRA_LEFT}{/if}
|
||||
<li class="print">
|
||||
<a href="javascript:print();">
|
||||
{l s='Print'}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
{/if}
|
||||
</div>
|
||||
<!-- end center infos-->
|
||||
<!-- pb-right-column-->
|
||||
<div class="pb-right-column col-xs-12 col-sm-4 col-md-3">
|
||||
{if ($product->show_price && !isset($restricted_country_mode)) || isset($groups) || $product->reference || (isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS)}
|
||||
<!-- add to cart form-->
|
||||
<form id="buy_block"{if $PS_CATALOG_MODE && !isset($groups) && $product->quantity > 0} class="hidden"{/if} action="{$link->getPageLink('cart')|escape:'html':'UTF-8'}" method="post">
|
||||
<!-- hidden datas -->
|
||||
<p class="hidden">
|
||||
<input type="hidden" name="token" value="{$static_token}" />
|
||||
<input type="hidden" name="id_product" value="{$product->id|intval}" id="product_page_product_id" />
|
||||
<input type="hidden" name="add" value="1" />
|
||||
<input type="hidden" name="id_product_attribute" id="idCombination" value="" />
|
||||
</p>
|
||||
<div class="box-info-product">
|
||||
<div class="content_prices clearfix">
|
||||
{if $product->show_price && !isset($restricted_country_mode) && !$PS_CATALOG_MODE}
|
||||
<!-- prices -->
|
||||
<div>
|
||||
<p class="our_price_display" itemprop="offers" itemscope itemtype="https://schema.org/Offer">{strip}
|
||||
{if $product->quantity > 0}<link itemprop="availability" href="https://schema.org/InStock"/>{/if}
|
||||
{if $priceDisplay >= 0 && $priceDisplay <= 2}
|
||||
<span id="our_price_display" class="price" itemprop="price" content="{$productPrice}">{convertPrice price=$productPrice|floatval}</span>
|
||||
{if $tax_enabled && ((isset($display_tax_label) && $display_tax_label == 1) || !isset($display_tax_label))}
|
||||
{if $priceDisplay == 1} {l s='tax excl.'}{else} {l s='tax incl.'}{/if}
|
||||
{/if}
|
||||
<meta itemprop="priceCurrency" content="{$currency->iso_code}" />
|
||||
{hook h="displayProductPriceBlock" product=$product type="price"}
|
||||
{/if}
|
||||
{/strip}</p>
|
||||
<p id="reduction_percent" {if $productPriceWithoutReduction <= 0 || !$product->specificPrice || $product->specificPrice.reduction_type != 'percentage'} style="display:none;"{/if}>{strip}
|
||||
<span id="reduction_percent_display">
|
||||
{if $product->specificPrice && $product->specificPrice.reduction_type == 'percentage'}-{$product->specificPrice.reduction*100}%{/if}
|
||||
</span>
|
||||
{/strip}</p>
|
||||
<p id="reduction_amount" {if $productPriceWithoutReduction <= 0 || !$product->specificPrice || $product->specificPrice.reduction_type != 'amount' || $product->specificPrice.reduction|floatval ==0} style="display:none"{/if}>{strip}
|
||||
<span id="reduction_amount_display">
|
||||
{if $product->specificPrice && $product->specificPrice.reduction_type == 'amount' && $product->specificPrice.reduction|floatval !=0}
|
||||
-{convertPrice price=$productPriceWithoutReduction|floatval-$productPrice|floatval}
|
||||
{/if}
|
||||
</span>
|
||||
{/strip}</p>
|
||||
<p id="old_price"{if (!$product->specificPrice || !$product->specificPrice.reduction)} class="hidden"{/if}>{strip}
|
||||
{if $priceDisplay >= 0 && $priceDisplay <= 2}
|
||||
{hook h="displayProductPriceBlock" product=$product type="old_price"}
|
||||
<span id="old_price_display"><span class="price">{if $productPriceWithoutReduction > $productPrice}{convertPrice price=$productPriceWithoutReduction|floatval}{/if}</span>{if $productPriceWithoutReduction > $productPrice && $tax_enabled && $display_tax_label == 1} {if $priceDisplay == 1}{l s='tax excl.'}{else}{l s='tax incl.'}{/if}{/if}</span>
|
||||
{/if}
|
||||
{/strip}</p>
|
||||
{if $priceDisplay == 2}
|
||||
<br />
|
||||
<span id="pretaxe_price">{strip}
|
||||
<span id="pretaxe_price_display">{convertPrice price=$product->getPrice(false, $smarty.const.NULL)}</span> {l s='tax excl.'}
|
||||
{/strip}</span>
|
||||
{/if}
|
||||
</div> <!-- end prices -->
|
||||
{if $packItems|@count && $productPrice < $product->getNoPackPrice()}
|
||||
<p class="pack_price">{l s='Instead of'} <span style="text-decoration: line-through;">{convertPrice price=$product->getNoPackPrice()}</span></p>
|
||||
{/if}
|
||||
{if $product->ecotax != 0}
|
||||
<p class="price-ecotax">{l s='Including'} <span id="ecotax_price_display">{if $priceDisplay == 2}{$ecotax_tax_exc|convertAndFormatPrice}{else}{$ecotax_tax_inc|convertAndFormatPrice}{/if}</span> {l s='for ecotax'}
|
||||
{if $product->specificPrice && $product->specificPrice.reduction}
|
||||
<br />{l s='(not impacted by the discount)'}
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
{if !empty($product->unity) && $product->unit_price_ratio > 0.000000}
|
||||
{math equation="pprice / punit_price" pprice=$productPrice punit_price=$product->unit_price_ratio assign=unit_price}
|
||||
<p class="unit-price"><span id="unit_price_display">{convertPrice price=$unit_price}</span> {l s='per'} {$product->unity|escape:'html':'UTF-8'}</p>
|
||||
{hook h="displayProductPriceBlock" product=$product type="unit_price"}
|
||||
{/if}
|
||||
{/if} {*close if for show price*}
|
||||
{hook h="displayProductPriceBlock" product=$product type="weight" hook_origin='product_sheet'}
|
||||
{hook h="displayProductPriceBlock" product=$product type="after_price"}
|
||||
<div class="clear"></div>
|
||||
</div> <!-- end content_prices -->
|
||||
<div class="product_attributes clearfix">
|
||||
<!-- quantity wanted -->
|
||||
{if !$PS_CATALOG_MODE}
|
||||
<p id="quantity_wanted_p"{if (!$allow_oosp && $product->quantity <= 0) || !$product->available_for_order || $PS_CATALOG_MODE} style="display: none;"{/if}>
|
||||
<label for="quantity_wanted">{l s='Quantity'}</label>
|
||||
<input type="number" min="1" name="qty" id="quantity_wanted" class="text" value="{if isset($quantityBackup)}{$quantityBackup|intval}{else}{if $product->minimal_quantity > 1}{$product->minimal_quantity}{else}1{/if}{/if}" />
|
||||
<a href="#" data-field-qty="qty" class="btn btn-default button-minus product_quantity_down">
|
||||
<span><i class="icon-minus"></i></span>
|
||||
</a>
|
||||
<a href="#" data-field-qty="qty" class="btn btn-default button-plus product_quantity_up">
|
||||
<span><i class="icon-plus"></i></span>
|
||||
</a>
|
||||
<span class="clearfix"></span>
|
||||
</p>
|
||||
{/if}
|
||||
<!-- minimal quantity wanted -->
|
||||
<p id="minimal_quantity_wanted_p"{if $product->minimal_quantity <= 1 || !$product->available_for_order || $PS_CATALOG_MODE} style="display: none;"{/if}>
|
||||
{l s='The minimum purchase order quantity for the product is'} <b id="minimal_quantity_label">{$product->minimal_quantity}</b>
|
||||
</p>
|
||||
{if isset($groups)}
|
||||
<!-- attributes -->
|
||||
<div id="attributes">
|
||||
<div class="clearfix"></div>
|
||||
{foreach from=$groups key=id_attribute_group item=group}
|
||||
{if $group.attributes|@count}
|
||||
<fieldset class="attribute_fieldset">
|
||||
<label class="attribute_label" {if $group.group_type != 'color' && $group.group_type != 'radio'}for="group_{$id_attribute_group|intval}"{/if}>{$group.name|escape:'html':'UTF-8'} </label>
|
||||
{assign var="groupName" value="group_$id_attribute_group"}
|
||||
<div class="attribute_list">
|
||||
{if ($group.group_type == 'select')}
|
||||
<select name="{$groupName}" id="group_{$id_attribute_group|intval}" class="form-control attribute_select no-print">
|
||||
{foreach from=$group.attributes key=id_attribute item=group_attribute}
|
||||
<option value="{$id_attribute|intval}"{if (isset($smarty.get.$groupName) && $smarty.get.$groupName|intval == $id_attribute) || $group.default == $id_attribute} selected="selected"{/if} title="{$group_attribute|escape:'html':'UTF-8'}">{$group_attribute|escape:'html':'UTF-8'}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
{elseif ($group.group_type == 'color')}
|
||||
<ul id="color_to_pick_list" class="clearfix">
|
||||
{assign var="default_colorpicker" value=""}
|
||||
{foreach from=$group.attributes key=id_attribute item=group_attribute}
|
||||
{assign var='img_color_exists' value=file_exists($col_img_dir|cat:$id_attribute|cat:'.jpg')}
|
||||
<li{if $group.default == $id_attribute} class="selected"{/if}>
|
||||
<a href="{$link->getProductLink($product)|escape:'html':'UTF-8'}" id="color_{$id_attribute|intval}" name="{$colors.$id_attribute.name|escape:'html':'UTF-8'}" class="color_pick{if ($group.default == $id_attribute)} selected{/if}"{if !$img_color_exists && isset($colors.$id_attribute.value) && $colors.$id_attribute.value} style="background:{$colors.$id_attribute.value|escape:'html':'UTF-8'};"{/if} title="{$colors.$id_attribute.name|escape:'html':'UTF-8'}">
|
||||
{if $img_color_exists}
|
||||
<img src="{$img_col_dir}{$id_attribute|intval}.jpg" alt="{$colors.$id_attribute.name|escape:'html':'UTF-8'}" title="{$colors.$id_attribute.name|escape:'html':'UTF-8'}" width="20" height="20" />
|
||||
{/if}
|
||||
</a>
|
||||
</li>
|
||||
{if ($group.default == $id_attribute)}
|
||||
{$default_colorpicker = $id_attribute}
|
||||
{/if}
|
||||
{/foreach}
|
||||
</ul>
|
||||
<input type="hidden" class="color_pick_hidden" name="{$groupName|escape:'html':'UTF-8'}" value="{$default_colorpicker|intval}" />
|
||||
{elseif ($group.group_type == 'radio')}
|
||||
<ul>
|
||||
{foreach from=$group.attributes key=id_attribute item=group_attribute}
|
||||
<li>
|
||||
<input type="radio" class="attribute_radio" name="{$groupName|escape:'html':'UTF-8'}" value="{$id_attribute}" {if ($group.default == $id_attribute)} checked="checked"{/if} />
|
||||
<span>{$group_attribute|escape:'html':'UTF-8'}</span>
|
||||
</li>
|
||||
{/foreach}
|
||||
</ul>
|
||||
{/if}
|
||||
</div> <!-- end attribute_list -->
|
||||
</fieldset>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</div> <!-- end attributes -->
|
||||
{/if}
|
||||
</div> <!-- end product_attributes -->
|
||||
|
||||
{hook h='displayProductForm' mod='antadisconfigurator'}
|
||||
|
||||
<div class="box-cart-bottom">
|
||||
<div{if (!$allow_oosp && $product->quantity <= 0) || !$product->available_for_order || (isset($restricted_country_mode) && $restricted_country_mode) || $PS_CATALOG_MODE} class="unvisible"{/if}>
|
||||
<p id="add_to_cart" class="buttons_bottom_block no-print">
|
||||
<button type="submit" name="Submit" class="exclusive">
|
||||
<span>{if $content_only && (isset($product->customization_required) && $product->customization_required)}{l s='Customize'}{else}{l s='Add to cart'}{/if}</span>
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
{if isset($HOOK_PRODUCT_ACTIONS) && $HOOK_PRODUCT_ACTIONS}{$HOOK_PRODUCT_ACTIONS}{/if}
|
||||
</div> <!-- end box-cart-bottom -->
|
||||
</div> <!-- end box-info-product -->
|
||||
</form>
|
||||
{/if}
|
||||
</div> <!-- end pb-right-column-->
|
||||
</div> <!-- end primary_block -->
|
||||
{if !$content_only}
|
||||
{if (isset($quantity_discounts) && count($quantity_discounts) > 0)}
|
||||
<!-- quantity discount -->
|
||||
<section class="page-product-box">
|
||||
<h3 class="page-product-heading">{l s='Volume discounts'}</h3>
|
||||
<div id="quantityDiscount">
|
||||
<table class="std table-product-discounts">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{l s='Quantity'}</th>
|
||||
<th>{if $display_discount_price}{l s='Price'}{else}{l s='Discount'}{/if}</th>
|
||||
<th>{l s='You Save'}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{foreach from=$quantity_discounts item='quantity_discount' name='quantity_discounts'}
|
||||
{if $quantity_discount.price >= 0 || $quantity_discount.reduction_type == 'amount'}
|
||||
{$realDiscountPrice=$quantity_discount.base_price|floatval-$quantity_discount.real_value|floatval}
|
||||
{else}
|
||||
{$realDiscountPrice=$quantity_discount.base_price|floatval*(1 - $quantity_discount.reduction)|floatval}
|
||||
{/if}
|
||||
<tr class="quantityDiscount_{$quantity_discount.id_product_attribute}" data-real-discount-value="{convertPrice price = $realDiscountPrice}" data-discount-type="{$quantity_discount.reduction_type}" data-discount="{$quantity_discount.real_value|floatval}" data-discount-quantity="{$quantity_discount.quantity|intval}">
|
||||
<td>
|
||||
{$quantity_discount.quantity|intval}
|
||||
</td>
|
||||
<td>
|
||||
{if $quantity_discount.price >= 0 || $quantity_discount.reduction_type == 'amount'}
|
||||
{if $display_discount_price}
|
||||
{if $quantity_discount.reduction_tax == 0 && !$quantity_discount.price}
|
||||
{convertPrice price = $productPriceWithoutReduction|floatval-($productPriceWithoutReduction*$quantity_discount.reduction_with_tax)|floatval}
|
||||
{else}
|
||||
{convertPrice price=$productPriceWithoutReduction|floatval-$quantity_discount.real_value|floatval}
|
||||
{/if}
|
||||
{else}
|
||||
{convertPrice price=$quantity_discount.real_value|floatval}
|
||||
{/if}
|
||||
{else}
|
||||
{if $display_discount_price}
|
||||
{if $quantity_discount.reduction_tax == 0}
|
||||
{convertPrice price = $productPriceWithoutReduction|floatval-($productPriceWithoutReduction*$quantity_discount.reduction_with_tax)|floatval}
|
||||
{else}
|
||||
{convertPrice price = $productPriceWithoutReduction|floatval-($productPriceWithoutReduction*$quantity_discount.reduction)|floatval}
|
||||
{/if}
|
||||
{else}
|
||||
{$quantity_discount.real_value|floatval}%
|
||||
{/if}
|
||||
{/if}
|
||||
</td>
|
||||
<td>
|
||||
<span>{l s='Up to'}</span>
|
||||
{if $quantity_discount.price >= 0 || $quantity_discount.reduction_type == 'amount'}
|
||||
{$discountPrice=$productPriceWithoutReduction|floatval-$quantity_discount.real_value|floatval}
|
||||
{else}
|
||||
{$discountPrice=$productPriceWithoutReduction|floatval-($productPriceWithoutReduction*$quantity_discount.reduction)|floatval}
|
||||
{/if}
|
||||
{$discountPrice=$discountPrice * $quantity_discount.quantity}
|
||||
{$qtyProductPrice=$productPriceWithoutReduction|floatval * $quantity_discount.quantity}
|
||||
{convertPrice price=$qtyProductPrice - $discountPrice}
|
||||
</td>
|
||||
</tr>
|
||||
{/foreach}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
{if isset($features) && $features}
|
||||
<!-- Data sheet -->
|
||||
<section class="page-product-box">
|
||||
<h3 class="page-product-heading">{l s='Data sheet'}</h3>
|
||||
<table class="table-data-sheet">
|
||||
{foreach from=$features item=feature}
|
||||
<tr class="{cycle values="odd,even"}">
|
||||
{if isset($feature.value)}
|
||||
<td>{$feature.name|escape:'html':'UTF-8'}</td>
|
||||
<td>{$feature.value|escape:'html':'UTF-8'}</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/foreach}
|
||||
</table>
|
||||
</section>
|
||||
<!--end Data sheet -->
|
||||
{/if}
|
||||
{if isset($product) && $product->description}
|
||||
<!-- More info -->
|
||||
<section class="page-product-box">
|
||||
<h3 class="page-product-heading">{l s='More info'}</h3>
|
||||
<!-- full description -->
|
||||
<div class="rte">{$product->description}</div>
|
||||
</section>
|
||||
<!--end More info -->
|
||||
{/if}
|
||||
{if isset($packItems) && $packItems|@count > 0}
|
||||
<section id="blockpack">
|
||||
<h3 class="page-product-heading">{l s='Pack content'}</h3>
|
||||
{include file="$tpl_dir./product-list.tpl" products=$packItems}
|
||||
</section>
|
||||
{/if}
|
||||
{if (isset($HOOK_PRODUCT_TAB) && $HOOK_PRODUCT_TAB) || (isset($HOOK_PRODUCT_TAB_CONTENT) && $HOOK_PRODUCT_TAB_CONTENT)}
|
||||
<!--HOOK_PRODUCT_TAB -->
|
||||
<section class="page-product-box">
|
||||
{$HOOK_PRODUCT_TAB}
|
||||
{if isset($HOOK_PRODUCT_TAB_CONTENT) && $HOOK_PRODUCT_TAB_CONTENT}{$HOOK_PRODUCT_TAB_CONTENT}{/if}
|
||||
</section>
|
||||
<!--end HOOK_PRODUCT_TAB -->
|
||||
{/if}
|
||||
{if isset($accessories) && $accessories}
|
||||
<!--Accessories -->
|
||||
<section class="page-product-box">
|
||||
<h3 class="page-product-heading">{l s='Accessories'}</h3>
|
||||
<div class="block products_block accessories-block clearfix">
|
||||
<div class="block_content">
|
||||
<ul id="bxslider" class="bxslider clearfix">
|
||||
{foreach from=$accessories item=accessory name=accessories_list}
|
||||
{if ($accessory.allow_oosp || $accessory.quantity_all_versions > 0 || $accessory.quantity > 0) && $accessory.available_for_order && !isset($restricted_country_mode)}
|
||||
{assign var='accessoryLink' value=$link->getProductLink($accessory.id_product, $accessory.link_rewrite, $accessory.category)}
|
||||
<li class="item product-box ajax_block_product{if $smarty.foreach.accessories_list.first} first_item{elseif $smarty.foreach.accessories_list.last} last_item{else} item{/if} product_accessories_description">
|
||||
<div class="product_desc">
|
||||
<a href="{$accessoryLink|escape:'html':'UTF-8'}" title="{$accessory.legend|escape:'html':'UTF-8'}" class="product-image product_image">
|
||||
<img class="lazyOwl" src="{$link->getImageLink($accessory.link_rewrite, $accessory.id_image, 'home_default')|escape:'html':'UTF-8'}" alt="{$accessory.legend|escape:'html':'UTF-8'}" width="{$homeSize.width}" height="{$homeSize.height}"/>
|
||||
</a>
|
||||
<div class="block_description">
|
||||
<a href="{$accessoryLink|escape:'html':'UTF-8'}" title="{l s='More'}" class="product_description">
|
||||
{$accessory.description_short|strip_tags|truncate:25:'...'}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="s_title_block">
|
||||
<h5 class="product-name">
|
||||
<a href="{$accessoryLink|escape:'html':'UTF-8'}">
|
||||
{$accessory.name|truncate:20:'...':true|escape:'html':'UTF-8'}
|
||||
</a>
|
||||
</h5>
|
||||
{if $accessory.show_price && !isset($restricted_country_mode) && !$PS_CATALOG_MODE}
|
||||
<span class="price">
|
||||
{if $priceDisplay != 1}
|
||||
{displayWtPrice p=$accessory.price}
|
||||
{else}
|
||||
{displayWtPrice p=$accessory.price_tax_exc}
|
||||
{/if}
|
||||
{hook h="displayProductPriceBlock" product=$accessory type="price"}
|
||||
</span>
|
||||
{/if}
|
||||
{hook h="displayProductPriceBlock" product=$accessory type="after_price"}
|
||||
</div>
|
||||
<div class="clearfix" style="margin-top:5px">
|
||||
{if !$PS_CATALOG_MODE && ($accessory.allow_oosp || $accessory.quantity > 0) && isset($add_prod_display) && $add_prod_display == 1}
|
||||
<div class="no-print">
|
||||
<a class="exclusive button ajax_add_to_cart_button" href="{$link->getPageLink('cart', true, NULL, "qty=1&id_product={$accessory.id_product|intval}&token={$static_token}&add")|escape:'html':'UTF-8'}" data-id-product="{$accessory.id_product|intval}" title="{l s='Add to cart'}">
|
||||
<span>{l s='Add to cart'}</span>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</li>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!--end Accessories -->
|
||||
{/if}
|
||||
{if isset($HOOK_PRODUCT_FOOTER) && $HOOK_PRODUCT_FOOTER}{$HOOK_PRODUCT_FOOTER}{/if}
|
||||
<!-- description & features -->
|
||||
{if (isset($product) && $product->description) || (isset($features) && $features) || (isset($accessories) && $accessories) || (isset($HOOK_PRODUCT_TAB) && $HOOK_PRODUCT_TAB) || (isset($attachments) && $attachments) || isset($product) && $product->customizable}
|
||||
{if isset($attachments) && $attachments}
|
||||
<!--Download -->
|
||||
<section class="page-product-box">
|
||||
<h3 class="page-product-heading">{l s='Download'}</h3>
|
||||
{foreach from=$attachments item=attachment name=attachements}
|
||||
{if $smarty.foreach.attachements.iteration %3 == 1}<div class="row">{/if}
|
||||
<div class="col-lg-4">
|
||||
<h4><a href="{$link->getPageLink('attachment', true, NULL, "id_attachment={$attachment.id_attachment}")|escape:'html':'UTF-8'}">{$attachment.name|escape:'html':'UTF-8'}</a></h4>
|
||||
<p class="text-muted">{$attachment.description|escape:'html':'UTF-8'}</p>
|
||||
<a class="btn btn-default btn-block" href="{$link->getPageLink('attachment', true, NULL, "id_attachment={$attachment.id_attachment}")|escape:'html':'UTF-8'}">
|
||||
<i class="icon-download"></i>
|
||||
{l s="Download"} ({Tools::formatBytes($attachment.file_size, 2)})
|
||||
</a>
|
||||
<hr />
|
||||
</div>
|
||||
{if $smarty.foreach.attachements.iteration %3 == 0 || $smarty.foreach.attachements.last}</div>{/if}
|
||||
{/foreach}
|
||||
</section>
|
||||
<!--end Download -->
|
||||
{/if}
|
||||
{if isset($product) && $product->customizable}
|
||||
<!--Customization -->
|
||||
<section class="page-product-box">
|
||||
<h3 class="page-product-heading">{l s='Product customization'}</h3>
|
||||
<!-- Customizable products -->
|
||||
<form method="post" action="{$customizationFormTarget}" enctype="multipart/form-data" id="customizationForm" class="clearfix">
|
||||
<p class="infoCustomizable">
|
||||
{l s='After saving your customized product, remember to add it to your cart.'}
|
||||
{if $product->uploadable_files}
|
||||
<br />
|
||||
{l s='Allowed file formats are: GIF, JPG, PNG'}{/if}
|
||||
</p>
|
||||
{if $product->uploadable_files|intval}
|
||||
<div class="customizableProductsFile">
|
||||
<h5 class="product-heading-h5">{l s='Pictures'}</h5>
|
||||
<ul id="uploadable_files" class="clearfix">
|
||||
{counter start=0 assign='customizationField'}
|
||||
{foreach from=$customizationFields item='field' name='customizationFields'}
|
||||
{if $field.type == 0}
|
||||
<li class="customizationUploadLine{if $field.required} required{/if}">{assign var='key' value='pictures_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field}
|
||||
{if isset($pictures.$key)}
|
||||
<div class="customizationUploadBrowse">
|
||||
<img src="{$pic_dir}{$pictures.$key}_small" alt="" />
|
||||
<a href="{$link->getProductDeletePictureLink($product, $field.id_customization_field)|escape:'html':'UTF-8'}" title="{l s='Delete'}" >
|
||||
<img src="{$img_dir}icon/delete.gif" alt="{l s='Delete'}" class="customization_delete_icon" width="11" height="13" />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="customizationUploadBrowse form-group">
|
||||
<label class="customizationUploadBrowseDescription">
|
||||
{if !empty($field.name)}
|
||||
{$field.name}
|
||||
{else}
|
||||
{l s='Please select an image file from your computer'}
|
||||
{/if}
|
||||
{if $field.required}<sup>*</sup>{/if}
|
||||
</label>
|
||||
<input type="file" name="file{$field.id_customization_field}" id="img{$customizationField}" class="form-control customization_block_input {if isset($pictures.$key)}filled{/if}" />
|
||||
</div>
|
||||
</li>
|
||||
{counter}
|
||||
{/if}
|
||||
{/foreach}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
{if $product->text_fields|intval}
|
||||
<div class="customizableProductsText">
|
||||
<h5 class="product-heading-h5">{l s='Text'}</h5>
|
||||
<ul id="text_fields">
|
||||
{counter start=0 assign='customizationField'}
|
||||
{foreach from=$customizationFields item='field' name='customizationFields'}
|
||||
{if $field.type == 1}
|
||||
<li class="customizationUploadLine{if $field.required} required{/if}">
|
||||
<label for ="textField{$customizationField}">
|
||||
{assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field}
|
||||
{if !empty($field.name)}
|
||||
{$field.name}
|
||||
{/if}
|
||||
{if $field.required}<sup>*</sup>{/if}
|
||||
</label>
|
||||
<textarea name="textField{$field.id_customization_field}" class="form-control customization_block_input" id="textField{$customizationField}" rows="3" cols="20">{strip}
|
||||
{if isset($textFields.$key)}
|
||||
{$textFields.$key|stripslashes}
|
||||
{/if}
|
||||
{/strip}</textarea>
|
||||
</li>
|
||||
{counter}
|
||||
{/if}
|
||||
{/foreach}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
<p id="customizedDatas">
|
||||
<input type="hidden" name="quantityBackup" id="quantityBackup" value="" />
|
||||
<input type="hidden" name="submitCustomizedDatas" value="1" />
|
||||
<button class="button btn btn-default button button-small" name="saveCustomization">
|
||||
<span>{l s='Save'}</span>
|
||||
</button>
|
||||
<span id="ajax-loader" class="unvisible">
|
||||
<img src="{$img_ps_dir}loader.gif" alt="loader" />
|
||||
</span>
|
||||
</p>
|
||||
</form>
|
||||
<p class="clear required"><sup>*</sup> {l s='required fields'}</p>
|
||||
</section>
|
||||
<!--end Customization -->
|
||||
{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
</div> <!-- itemscope product wrapper -->
|
||||
{strip}
|
||||
{if isset($smarty.get.ad) && $smarty.get.ad}
|
||||
{addJsDefL name=ad}{$base_dir|cat:$smarty.get.ad|escape:'html':'UTF-8'}{/addJsDefL}
|
||||
{/if}
|
||||
{if isset($smarty.get.adtoken) && $smarty.get.adtoken}
|
||||
{addJsDefL name=adtoken}{$smarty.get.adtoken|escape:'html':'UTF-8'}{/addJsDefL}
|
||||
{/if}
|
||||
{addJsDef allowBuyWhenOutOfStock=$allow_oosp|boolval}
|
||||
{addJsDef availableNowValue=$product->available_now|escape:'quotes':'UTF-8'}
|
||||
{addJsDef availableLaterValue=$product->available_later|escape:'quotes':'UTF-8'}
|
||||
{addJsDef attribute_anchor_separator=$attribute_anchor_separator|escape:'quotes':'UTF-8'}
|
||||
{addJsDef attributesCombinations=$attributesCombinations}
|
||||
{addJsDef currentDate=$smarty.now|date_format:'%Y-%m-%d %H:%M:%S'}
|
||||
{if isset($combinations) && $combinations}
|
||||
{addJsDef combinations=$combinations}
|
||||
{addJsDef combinationsFromController=$combinations}
|
||||
{addJsDef displayDiscountPrice=$display_discount_price}
|
||||
{addJsDefL name='upToTxt'}{l s='Up to' js=1}{/addJsDefL}
|
||||
{/if}
|
||||
{if isset($combinationImages) && $combinationImages}
|
||||
{addJsDef combinationImages=$combinationImages}
|
||||
{/if}
|
||||
{addJsDef customizationId=$id_customization}
|
||||
{addJsDef customizationFields=$customizationFields}
|
||||
{addJsDef default_eco_tax=$product->ecotax|floatval}
|
||||
{addJsDef displayPrice=$priceDisplay|intval}
|
||||
{addJsDef ecotaxTax_rate=$ecotaxTax_rate|floatval}
|
||||
{if isset($cover.id_image_only)}
|
||||
{addJsDef idDefaultImage=$cover.id_image_only|intval}
|
||||
{else}
|
||||
{addJsDef idDefaultImage=0}
|
||||
{/if}
|
||||
{addJsDef img_ps_dir=$img_ps_dir}
|
||||
{addJsDef img_prod_dir=$img_prod_dir}
|
||||
{addJsDef id_product=$product->id|intval}
|
||||
{addJsDef jqZoomEnabled=$jqZoomEnabled|boolval}
|
||||
{addJsDef maxQuantityToAllowDisplayOfLastQuantityMessage=$last_qties|intval}
|
||||
{addJsDef minimalQuantity=$product->minimal_quantity|intval}
|
||||
{addJsDef noTaxForThisProduct=$no_tax|boolval}
|
||||
{if isset($customer_group_without_tax)}
|
||||
{addJsDef customerGroupWithoutTax=$customer_group_without_tax|boolval}
|
||||
{else}
|
||||
{addJsDef customerGroupWithoutTax=false}
|
||||
{/if}
|
||||
{if isset($group_reduction)}
|
||||
{addJsDef groupReduction=$group_reduction|floatval}
|
||||
{else}
|
||||
{addJsDef groupReduction=false}
|
||||
{/if}
|
||||
{addJsDef oosHookJsCodeFunctions=Array()}
|
||||
{addJsDef productHasAttributes=isset($groups)|boolval}
|
||||
{addJsDef productPriceTaxExcluded=($product->getPriceWithoutReduct(true)|default:'null' - $product->ecotax)|floatval}
|
||||
{addJsDef productPriceTaxIncluded=($product->getPriceWithoutReduct(false)|default:'null' - $product->ecotax * (1 + $ecotaxTax_rate / 100))|floatval}
|
||||
{addJsDef productBasePriceTaxExcluded=($product->getPrice(false, null, 6, null, false, false) - $product->ecotax)|floatval}
|
||||
{addJsDef productBasePriceTaxExcl=($product->getPrice(false, null, 6, null, false, false)|floatval)}
|
||||
{addJsDef productBasePriceTaxIncl=($product->getPrice(true, null, 6, null, false, false)|floatval)}
|
||||
{addJsDef productReference=$product->reference|escape:'html':'UTF-8'}
|
||||
{addJsDef productAvailableForOrder=$product->available_for_order|boolval}
|
||||
{addJsDef productPriceWithoutReduction=$productPriceWithoutReduction|floatval}
|
||||
{addJsDef productPrice=$productPrice|floatval}
|
||||
{addJsDef productUnitPriceRatio=$product->unit_price_ratio|floatval}
|
||||
{addJsDef productShowPrice=(!$PS_CATALOG_MODE && $product->show_price)|boolval}
|
||||
{addJsDef PS_CATALOG_MODE=$PS_CATALOG_MODE}
|
||||
{if $product->specificPrice && $product->specificPrice|@count}
|
||||
{addJsDef product_specific_price=$product->specificPrice}
|
||||
{else}
|
||||
{addJsDef product_specific_price=array()}
|
||||
{/if}
|
||||
{if $display_qties == 1 && $product->quantity}
|
||||
{addJsDef quantityAvailable=$product->quantity}
|
||||
{else}
|
||||
{addJsDef quantityAvailable=0}
|
||||
{/if}
|
||||
{addJsDef quantitiesDisplayAllowed=$display_qties|boolval}
|
||||
{if $product->specificPrice && $product->specificPrice.reduction && $product->specificPrice.reduction_type == 'percentage'}
|
||||
{addJsDef reduction_percent=$product->specificPrice.reduction*100|floatval}
|
||||
{else}
|
||||
{addJsDef reduction_percent=0}
|
||||
{/if}
|
||||
{if $product->specificPrice && $product->specificPrice.reduction && $product->specificPrice.reduction_type == 'amount'}
|
||||
{addJsDef reduction_price=$product->specificPrice.reduction|floatval}
|
||||
{else}
|
||||
{addJsDef reduction_price=0}
|
||||
{/if}
|
||||
{if $product->specificPrice && $product->specificPrice.price}
|
||||
{addJsDef specific_price=$product->specificPrice.price|floatval}
|
||||
{else}
|
||||
{addJsDef specific_price=0}
|
||||
{/if}
|
||||
{addJsDef specific_currency=($product->specificPrice && $product->specificPrice.id_currency)|boolval} {* TODO: remove if always false *}
|
||||
{addJsDef stock_management=$PS_STOCK_MANAGEMENT|intval}
|
||||
{addJsDef taxRate=$tax_rate|floatval}
|
||||
{addJsDefL name=doesntExist}{l s='This combination does not exist for this product. Please select another combination.' js=1}{/addJsDefL}
|
||||
{addJsDefL name=doesntExistNoMore}{l s='This product is no longer in stock' js=1}{/addJsDefL}
|
||||
{addJsDefL name=doesntExistNoMoreBut}{l s='with those attributes but is available with others.' js=1}{/addJsDefL}
|
||||
{addJsDefL name=fieldRequired}{l s='Please fill in all the required fields before saving your customization.' js=1}{/addJsDefL}
|
||||
{addJsDefL name=uploading_in_progress}{l s='Uploading in progress, please be patient.' js=1}{/addJsDefL}
|
||||
{addJsDefL name='product_fileDefaultHtml'}{l s='No file selected' js=1}{/addJsDefL}
|
||||
{addJsDefL name='product_fileButtonHtml'}{l s='Choose File' js=1}{/addJsDefL}
|
||||
{/strip}
|
||||
{/if}
|
@ -0,0 +1,151 @@
|
||||
{*
|
||||
* 2007-2016 PrestaShop
|
||||
*
|
||||
* NOTICE OF LICENSE
|
||||
*
|
||||
* This source file is subject to the Academic Free License (AFL 3.0)
|
||||
* that is bundled with this package in the file LICENSE.txt.
|
||||
* It is also available through the world-wide-web at this URL:
|
||||
* http://opensource.org/licenses/afl-3.0.php
|
||||
* If you did not receive a copy of the license and are unable to
|
||||
* obtain it through the world-wide-web, please send an email
|
||||
* to license@prestashop.com so we can send you a copy immediately.
|
||||
*
|
||||
* DISCLAIMER
|
||||
*
|
||||
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
||||
* versions in the future. If you wish to customize PrestaShop for your
|
||||
* needs please refer to http://www.prestashop.com for more information.
|
||||
*
|
||||
* @author PrestaShop SA <contact@prestashop.com>
|
||||
* @copyright 2007-2016 PrestaShop SA
|
||||
* @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
|
||||
* International Registered Trademark & Property of PrestaShop SA
|
||||
*}
|
||||
<tr id="product_{$product.id_product}_{$product.id_product_attribute}_{if $quantityDisplayed > 0}nocustom{else}0{/if}_{$product.id_address_delivery|intval}{if !empty($product.gift)}_gift{/if}" class="cart_item{if isset($productLast) && $productLast && (!isset($ignoreProductLast) || !$ignoreProductLast)} last_item{/if}{if isset($productFirst) && $productFirst} first_item{/if}{if isset($customizedDatas.$productId.$productAttributeId) AND $quantityDisplayed == 0} alternate_item{/if} address_{$product.id_address_delivery|intval} {if $odd}odd{else}even{/if}">
|
||||
<td class="cart_product">
|
||||
<a href="{$link->getProductLink($product.id_product, $product.link_rewrite, $product.category, null, null, $product.id_shop, $product.id_product_attribute, false, false, true)|escape:'html':'UTF-8'}"><img src="{$link->getImageLink($product.link_rewrite, $product.id_image, 'small_default')|escape:'html':'UTF-8'}" alt="{$product.name|escape:'html':'UTF-8'}" {if isset($smallSize)}width="{$smallSize.width}" height="{$smallSize.height}" {/if} /></a>
|
||||
</td>
|
||||
<td class="cart_description">
|
||||
{capture name=sep} : {/capture}
|
||||
{capture}{l s=' : '}{/capture}
|
||||
<p class="product-name"><a href="{$link->getProductLink($product.id_product, $product.link_rewrite, $product.category, null, null, $product.id_shop, $product.id_product_attribute, false, false, true)|escape:'html':'UTF-8'}">{$product.name|escape:'html':'UTF-8'}</a></p>
|
||||
{if $product.reference}<small class="cart_ref">{l s='SKU'}{$smarty.capture.default}{$product.reference|escape:'html':'UTF-8'}</small>{/if}
|
||||
{if isset($product.attributes) && $product.attributes}<small><a href="{$link->getProductLink($product.id_product, $product.link_rewrite, $product.category, null, null, $product.id_shop, $product.id_product_attribute, false, false, true)|escape:'html':'UTF-8'}">{$product.attributes|@replace: $smarty.capture.sep:$smarty.capture.default|escape:'html':'UTF-8'}</a></small>{/if}
|
||||
|
||||
{if isset($product.configurator_opt)}
|
||||
{foreach item=group from=$product.configurator_opt}
|
||||
<small>
|
||||
{$group['name']} :
|
||||
{foreach item=i from=$group['value'] name=opt}
|
||||
{$i} {if !$smarty.foreach.opt.last},{/if}
|
||||
{/foreach}
|
||||
</small>
|
||||
{/foreach}
|
||||
{/if}
|
||||
|
||||
</td>
|
||||
{if $PS_STOCK_MANAGEMENT}
|
||||
<td class="cart_avail"><span class="label{if $product.quantity_available <= 0 && isset($product.allow_oosp) && !$product.allow_oosp} label-danger{elseif $product.quantity_available <= 0} label-warning{else} label-success{/if}">{if $product.quantity_available <= 0}{if isset($product.allow_oosp) && $product.allow_oosp}{if isset($product.available_later) && $product.available_later}{$product.available_later}{else}{l s='In Stock'}{/if}{else}{l s='Out of stock'}{/if}{else}{if isset($product.available_now) && $product.available_now}{$product.available_now}{else}{l s='In Stock'}{/if}{/if}</span>{if !$product.is_virtual}{hook h="displayProductDeliveryTime" product=$product}{/if}</td>
|
||||
{/if}
|
||||
<td class="cart_unit" data-title="{l s='Unit price'}">
|
||||
<ul class="price text-right" id="product_price_{$product.id_product}_{$product.id_product_attribute}{if $quantityDisplayed > 0}_nocustom{/if}_{$product.id_address_delivery|intval}{if !empty($product.gift)}_gift{/if}">
|
||||
{if !empty($product.gift)}
|
||||
<li class="gift-icon">{l s='Gift!'}</li>
|
||||
{else}
|
||||
{if !$priceDisplay}
|
||||
<li class="price{if isset($product.is_discounted) && $product.is_discounted && isset($product.reduction_applies) && $product.reduction_applies} special-price{/if}">{convertPrice price=$product.price_wt}</li>
|
||||
{else}
|
||||
<li class="price{if isset($product.is_discounted) && $product.is_discounted && isset($product.reduction_applies) && $product.reduction_applies} special-price{/if}">{convertPrice price=$product.price}</li>
|
||||
{/if}
|
||||
{if isset($product.is_discounted) && $product.is_discounted && isset($product.reduction_applies) && $product.reduction_applies}
|
||||
<li class="price-percent-reduction small">
|
||||
{if !$priceDisplay}
|
||||
{if isset($product.reduction_type) && $product.reduction_type == 'amount'}
|
||||
{assign var='priceReduction' value=($product.price_wt - $product.price_without_specific_price)}
|
||||
{assign var='symbol' value=$currency->sign}
|
||||
{else}
|
||||
{assign var='priceReduction' value=(($product.price_without_specific_price - $product.price_wt)/$product.price_without_specific_price) * 100 * -1}
|
||||
{assign var='symbol' value='%'}
|
||||
{/if}
|
||||
{else}
|
||||
{if isset($product.reduction_type) && $product.reduction_type == 'amount'}
|
||||
{assign var='priceReduction' value=($product.price - $product.price_without_specific_price)}
|
||||
{assign var='symbol' value=$currency->sign}
|
||||
{else}
|
||||
{assign var='priceReduction' value=(($product.price_without_specific_price - $product.price)/$product.price_without_specific_price) * -100}
|
||||
{assign var='symbol' value='%'}
|
||||
{/if}
|
||||
{/if}
|
||||
{if $symbol == '%'}
|
||||
{$priceReduction|string_format:"%.2f"|regex_replace:"/[^\d]0+$/":""}{$symbol}
|
||||
{else}
|
||||
{convertPrice price=$priceReduction}
|
||||
{/if}
|
||||
</li>
|
||||
<li class="old-price">{convertPrice price=$product.price_without_specific_price}</li>
|
||||
{/if}
|
||||
{/if}
|
||||
</ul>
|
||||
</td>
|
||||
|
||||
<td class="cart_quantity text-center" data-title="{l s='Quantity'}">
|
||||
{if (isset($cannotModify) && $cannotModify == 1)}
|
||||
<span>
|
||||
{if $quantityDisplayed == 0 AND isset($customizedDatas.$productId.$productAttributeId)}
|
||||
{$product.customizationQuantityTotal}
|
||||
{else}
|
||||
{$product.cart_quantity-$quantityDisplayed}
|
||||
{/if}
|
||||
</span>
|
||||
{else}
|
||||
{if isset($customizedDatas.$productId.$productAttributeId) AND $quantityDisplayed == 0}
|
||||
<span id="cart_quantity_custom_{$product.id_product}_{$product.id_product_attribute}_{$product.id_address_delivery|intval}" >{$product.customizationQuantityTotal}</span>
|
||||
{/if}
|
||||
{if !isset($customizedDatas.$productId.$productAttributeId) OR $quantityDisplayed > 0}
|
||||
|
||||
<input type="hidden" value="{if $quantityDisplayed == 0 AND isset($customizedDatas.$productId.$productAttributeId)}{$customizedDatas.$productId.$productAttributeId|@count}{else}{$product.cart_quantity-$quantityDisplayed}{/if}" name="quantity_{$product.id_product}_{$product.id_product_attribute}_{if $quantityDisplayed > 0}nocustom{else}0{/if}_{$product.id_address_delivery|intval}_hidden" />
|
||||
<input size="2" type="text" autocomplete="off" class="cart_quantity_input form-control grey" value="{if $quantityDisplayed == 0 AND isset($customizedDatas.$productId.$productAttributeId)}{$customizedDatas.$productId.$productAttributeId|@count}{else}{$product.cart_quantity-$quantityDisplayed}{/if}" name="quantity_{$product.id_product}_{$product.id_product_attribute}_{if $quantityDisplayed > 0}nocustom{else}0{/if}_{$product.id_address_delivery|intval}" />
|
||||
<div class="cart_quantity_button clearfix">
|
||||
{if $product.minimal_quantity < ($product.cart_quantity-$quantityDisplayed) OR $product.minimal_quantity <= 1}
|
||||
<a rel="nofollow" class="cart_quantity_down btn btn-default button-minus" id="cart_quantity_down_{$product.id_product}_{$product.id_product_attribute}_{if $quantityDisplayed > 0}nocustom{else}0{/if}_{$product.id_address_delivery|intval}" href="{$link->getPageLink('cart', true, NULL, "add=1&id_product={$product.id_product|intval}&ipa={$product.id_product_attribute|intval}&id_address_delivery={$product.id_address_delivery|intval}&op=down&token={$token_cart}")|escape:'html':'UTF-8'}" title="{l s='Subtract'}">
|
||||
<span><i class="icon-minus"></i></span>
|
||||
</a>
|
||||
{else}
|
||||
<a class="cart_quantity_down btn btn-default button-minus disabled" href="#" id="cart_quantity_down_{$product.id_product}_{$product.id_product_attribute}_{if $quantityDisplayed > 0}nocustom{else}0{/if}_{$product.id_address_delivery|intval}" title="{l s='You must purchase a minimum of %d of this product.' sprintf=$product.minimal_quantity}">
|
||||
<span><i class="icon-minus"></i></span>
|
||||
</a>
|
||||
{/if}
|
||||
<a rel="nofollow" class="cart_quantity_up btn btn-default button-plus" id="cart_quantity_up_{$product.id_product}_{$product.id_product_attribute}_{if $quantityDisplayed > 0}nocustom{else}0{/if}_{$product.id_address_delivery|intval}" href="{$link->getPageLink('cart', true, NULL, "add=1&id_product={$product.id_product|intval}&ipa={$product.id_product_attribute|intval}&id_address_delivery={$product.id_address_delivery|intval}&token={$token_cart}")|escape:'html':'UTF-8'}" title="{l s='Add'}"><span><i class="icon-plus"></i></span></a>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</td>
|
||||
|
||||
{if !isset($noDeleteButton) || !$noDeleteButton}
|
||||
<td class="cart_delete text-center" data-title="{l s='Delete'}">
|
||||
{if (!isset($customizedDatas.$productId.$productAttributeId) OR $quantityDisplayed > 0) && empty($product.gift)}
|
||||
<div>
|
||||
<a rel="nofollow" title="{l s='Delete'}" class="cart_quantity_delete" id="{$product.id_product}_{$product.id_product_attribute}_{if $quantityDisplayed > 0}nocustom{else}0{/if}_{$product.id_address_delivery|intval}" href="{$link->getPageLink('cart', true, NULL, "delete=1&id_product={$product.id_product|intval}&ipa={$product.id_product_attribute|intval}&id_address_delivery={$product.id_address_delivery|intval}&token={$token_cart}")|escape:'html':'UTF-8'}"><i class="icon-trash"></i></a>
|
||||
</div>
|
||||
{else}
|
||||
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
<td class="cart_total" data-title="{l s='Total'}">
|
||||
<span class="price" id="total_product_price_{$product.id_product}_{$product.id_product_attribute}{if $quantityDisplayed > 0}_nocustom{/if}_{$product.id_address_delivery|intval}{if !empty($product.gift)}_gift{/if}">
|
||||
{if !empty($product.gift)}
|
||||
<span class="gift-icon">{l s='Gift!'}</span>
|
||||
{else}
|
||||
{if $quantityDisplayed == 0 AND isset($customizedDatas.$productId.$productAttributeId)}
|
||||
{if !$priceDisplay}{displayPrice price=$product.total_customization_wt}{else}{displayPrice price=$product.total_customization}{/if}
|
||||
{else}
|
||||
{if !$priceDisplay}{displayPrice price=$product.total_wt}{else}{displayPrice price=$product.total}{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
</span>
|
||||
{hook h='displayCartExtraProductActions' product=$product}
|
||||
</td>
|
||||
|
||||
</tr>
|
1105
www/modules/antadisconfigurator/override/classes/Cart.php
Normal file
1105
www/modules/antadisconfigurator/override/classes/Cart.php
Normal file
File diff suppressed because it is too large
Load Diff
483
www/modules/antadisconfigurator/override/classes/Product.php
Normal file
483
www/modules/antadisconfigurator/override/classes/Product.php
Normal file
@ -0,0 +1,483 @@
|
||||
<?php
|
||||
class Product extends ProductCore
|
||||
{
|
||||
/**
|
||||
* Product with configuration
|
||||
* @param int $id_product
|
||||
* @return boolean
|
||||
*/
|
||||
public static function hasConfiguratorOpt($id_product)
|
||||
{
|
||||
$result = Db::getInstance()->getValue('
|
||||
SELECT count(*) AS nb
|
||||
FROM `'._DB_PREFIX_.'product_configurator_opt_group` pcog,
|
||||
`'._DB_PREFIX_.'configurator_opt_group` cog
|
||||
WHERE pcog.`id_product` = '.(int)$id_product.'
|
||||
AND cog.`id_configurator_opt_group` = pcog.`id_configurator_opt_group`');
|
||||
|
||||
return ( $result > 0 ? true : false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne les groupes options
|
||||
* @param int $id_product
|
||||
* @return array|false|NULL|mysqli_result|PDOStatement|resource
|
||||
*/
|
||||
public static function getConfiguratorOptGroup($id_product)
|
||||
{
|
||||
$context = Context::getContext();
|
||||
$result = Db::getInstance()->executeS('
|
||||
SELECT pcog.*, col.`name`, cog.`type`
|
||||
FROM `'._DB_PREFIX_.'product_configurator_opt_group` pcog,
|
||||
`'._DB_PREFIX_.'configurator_opt_group` cog,
|
||||
`'._DB_PREFIX_.'configurator_opt_group_lang` col
|
||||
WHERE pcog.`id_product` = '.(int)$id_product.'
|
||||
AND cog.`id_configurator_opt_group` = col.`id_configurator_opt_group`
|
||||
AND pcog.`id_configurator_opt_group` = col.`id_configurator_opt_group`
|
||||
AND col.`id_lang` = '.(int)$context->language->id.'
|
||||
ORDER BY pcog.`position` ASC');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne les impacts
|
||||
* @param int $id_product
|
||||
* @return array|false|NULL|mysqli_result|PDOStatement|resource
|
||||
*/
|
||||
public static function getConfiguratorOptImpact($id_product)
|
||||
{
|
||||
$context = Context::getContext();
|
||||
$result = Db::getInstance()->executeS('
|
||||
SELECT pcoi.`id_product_configurator_opt_impact`, pcoi.`id_product_configurator_opt_group`, pcoi.`id_configurator_opt`, col.`name`, pcoi.`price`, co.`position`
|
||||
FROM `'._DB_PREFIX_.'product_configurator_opt_impact` pcoi
|
||||
LEFT JOIN `'._DB_PREFIX_.'configurator_opt` co ON co.`id_configurator_opt` = pcoi.`id_configurator_opt`
|
||||
LEFT JOIN `'._DB_PREFIX_.'configurator_opt_lang` col
|
||||
ON (col.`id_configurator_opt` = pcoi.`id_configurator_opt` AND col.`id_lang` = '.(int)$context->language->id.')
|
||||
WHERE pcoi.`id_product` = '.(int)$id_product.'
|
||||
ORDER BY co.`position` ASC');
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcul du prix d'impact suivant les éléments selectionnés
|
||||
*/
|
||||
public function getConfiguratorImpactPrice($params)
|
||||
{
|
||||
$priceImpact = 0;
|
||||
|
||||
// List id_product_configurator_opt_impact
|
||||
$impactId = array();
|
||||
if (count($params) > 0) {
|
||||
foreach ($params as $p) {
|
||||
if (is_numeric($p['id_product_configurator_opt_impact'])) {
|
||||
$impactId[] = $p['id_product_configurator_opt_impact'];
|
||||
} elseif (is_array($p['id_product_configurator_opt_impact'])) {
|
||||
foreach ($p['id_product_configurator_opt_impact'] as $v) {
|
||||
$impactId[] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sql = 'SELECT price FROM `'._DB_PREFIX_.'product_configurator_opt_impact` where id_product = '.$this->id.
|
||||
' AND id_product_configurator_opt_impact IN('.join(',', $impactId).')';
|
||||
$result = Db::getInstance()->executeS($sql);
|
||||
if (count($result) > 0) {
|
||||
foreach ($result as $item) {
|
||||
$priceImpact += $item['price'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $priceImpact;
|
||||
}
|
||||
|
||||
public function getConfiguratorOptSelected($id_configurator)
|
||||
{
|
||||
$sql = 'SELECT id_product_configurator_opt_group, id_product_configurator_opt_impact FROM ps_configurator_storage WHERE id_configurator = '.(int)$id_configurator;
|
||||
$optSelected = Db::getInstance()->executeS($sql);
|
||||
if (count($optSelected) > 0) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Price calculation / Get product price
|
||||
*
|
||||
* @param int $id_shop Shop id
|
||||
* @param int $id_product Product id
|
||||
* @param int $id_product_attribute Product attribute id
|
||||
* @param int $id_country Country id
|
||||
* @param int $id_state State id
|
||||
* @param string $zipcode
|
||||
* @param int $id_currency Currency id
|
||||
* @param int $id_group Group id
|
||||
* @param int $quantity Quantity Required for Specific prices : quantity discount application
|
||||
* @param bool $use_tax with (1) or without (0) tax
|
||||
* @param int $decimals Number of decimals returned
|
||||
* @param bool $only_reduc Returns only the reduction amount
|
||||
* @param bool $use_reduc Set if the returned amount will include reduction
|
||||
* @param bool $with_ecotax insert ecotax in price output.
|
||||
* @param null $specific_price If a specific price applies regarding the previous parameters,
|
||||
* this variable is filled with the corresponding SpecificPrice object
|
||||
* @param bool $use_group_reduction
|
||||
* @param int $id_customer
|
||||
* @param bool $use_customer_price
|
||||
* @param int $id_cart
|
||||
* @param int $real_quantity
|
||||
* @return float Product price
|
||||
**/
|
||||
public static function priceCalculation($id_shop, $id_product, $id_product_attribute, $id_country, $id_state, $zipcode, $id_currency,
|
||||
$id_group, $quantity, $use_tax, $decimals, $only_reduc, $use_reduc, $with_ecotax, &$specific_price, $use_group_reduction,
|
||||
$id_customer = 0, $use_customer_price = true, $id_cart = 0, $real_quantity = 0, $id_configurator = null)
|
||||
{
|
||||
static $address = null;
|
||||
static $context = null;
|
||||
|
||||
if ($address === null) {
|
||||
$address = new Address();
|
||||
}
|
||||
|
||||
if ($context == null) {
|
||||
$context = Context::getContext()->cloneContext();
|
||||
}
|
||||
|
||||
if ($id_shop !== null && $context->shop->id != (int)$id_shop) {
|
||||
$context->shop = new Shop((int)$id_shop);
|
||||
}
|
||||
|
||||
if (!$use_customer_price) {
|
||||
$id_customer = 0;
|
||||
}
|
||||
|
||||
if ($id_product_attribute === null) {
|
||||
$id_product_attribute = Product::getDefaultAttribute($id_product);
|
||||
}
|
||||
|
||||
$cache_id = (int)$id_product.'-'.(int)$id_shop.'-'.(int)$id_currency.'-'.(int)$id_country.'-'.$id_state.'-'.$zipcode.'-'.(int)$id_group.
|
||||
'-'.(int)$quantity.'-'.(int)$id_product_attribute.
|
||||
'-'.(int)$with_ecotax.'-'.(int)$id_customer.'-'.(int)$use_group_reduction.'-'.(int)$id_cart.'-'.(int)$real_quantity.
|
||||
'-'.($only_reduc?'1':'0').'-'.($use_reduc?'1':'0').'-'.($use_tax?'1':'0').'-'.(int)$decimals;
|
||||
|
||||
if($id_configurator !== null) {
|
||||
$cache_id.= '-'.$id_configurator;
|
||||
}
|
||||
|
||||
// reference parameter is filled before any returns
|
||||
$specific_price = SpecificPrice::getSpecificPrice(
|
||||
(int)$id_product,
|
||||
$id_shop,
|
||||
$id_currency,
|
||||
$id_country,
|
||||
$id_group,
|
||||
$quantity,
|
||||
$id_product_attribute,
|
||||
$id_customer,
|
||||
$id_cart,
|
||||
$real_quantity
|
||||
);
|
||||
|
||||
if (isset(self::$_prices[$cache_id])) {
|
||||
/* Affect reference before returning cache */
|
||||
if (isset($specific_price['price']) && $specific_price['price'] > 0) {
|
||||
$specific_price['price'] = self::$_prices[$cache_id];
|
||||
}
|
||||
return self::$_prices[$cache_id];
|
||||
}
|
||||
|
||||
// fetch price & attribute price
|
||||
$cache_id_2 = $id_product.'-'.$id_shop;
|
||||
if (!isset(self::$_pricesLevel2[$cache_id_2])) {
|
||||
$sql = new DbQuery();
|
||||
$sql->select('product_shop.`price`, product_shop.`ecotax`');
|
||||
$sql->from('product', 'p');
|
||||
$sql->innerJoin('product_shop', 'product_shop', '(product_shop.id_product=p.id_product AND product_shop.id_shop = '.(int)$id_shop.')');
|
||||
$sql->where('p.`id_product` = '.(int)$id_product);
|
||||
if (Combination::isFeatureActive()) {
|
||||
$sql->select('IFNULL(product_attribute_shop.id_product_attribute,0) id_product_attribute, product_attribute_shop.`price` AS attribute_price, product_attribute_shop.default_on');
|
||||
$sql->leftJoin('product_attribute_shop', 'product_attribute_shop', '(product_attribute_shop.id_product = p.id_product AND product_attribute_shop.id_shop = '.(int)$id_shop.')');
|
||||
} else {
|
||||
$sql->select('0 as id_product_attribute');
|
||||
}
|
||||
|
||||
$res = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql);
|
||||
|
||||
if (is_array($res) && count($res)) {
|
||||
foreach ($res as $row) {
|
||||
$array_tmp = array(
|
||||
'price' => $row['price'],
|
||||
'ecotax' => $row['ecotax'],
|
||||
'attribute_price' => (isset($row['attribute_price']) ? $row['attribute_price'] : null)
|
||||
);
|
||||
self::$_pricesLevel2[$cache_id_2][(int)$row['id_product_attribute']] = $array_tmp;
|
||||
|
||||
if (isset($row['default_on']) && $row['default_on'] == 1) {
|
||||
self::$_pricesLevel2[$cache_id_2][0] = $array_tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset(self::$_pricesLevel2[$cache_id_2][(int)$id_product_attribute])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$result = self::$_pricesLevel2[$cache_id_2][(int)$id_product_attribute];
|
||||
|
||||
if (!$specific_price || $specific_price['price'] < 0) {
|
||||
$price = (float)$result['price'];
|
||||
} else {
|
||||
$price = (float)$specific_price['price'];
|
||||
}
|
||||
// convert only if the specific price is in the default currency (id_currency = 0)
|
||||
if (!$specific_price || !($specific_price['price'] >= 0 && $specific_price['id_currency'])) {
|
||||
$price = Tools::convertPrice($price, $id_currency);
|
||||
if (isset($specific_price['price']) && $specific_price['price'] >= 0) {
|
||||
$specific_price['price'] = $price;
|
||||
}
|
||||
}
|
||||
|
||||
// Attribute price
|
||||
if (is_array($result) && (!$specific_price || !$specific_price['id_product_attribute'] || $specific_price['price'] < 0)) {
|
||||
$attribute_price = Tools::convertPrice($result['attribute_price'] !== null ? (float)$result['attribute_price'] : 0, $id_currency);
|
||||
// If you want the default combination, please use NULL value instead
|
||||
if ($id_product_attribute !== false) {
|
||||
$price += $attribute_price;
|
||||
}
|
||||
}
|
||||
|
||||
// Tax
|
||||
$address->id_country = $id_country;
|
||||
$address->id_state = $id_state;
|
||||
$address->postcode = $zipcode;
|
||||
|
||||
$tax_manager = TaxManagerFactory::getManager($address, Product::getIdTaxRulesGroupByIdProduct((int)$id_product, $context));
|
||||
$product_tax_calculator = $tax_manager->getTaxCalculator();
|
||||
|
||||
// Add Tax
|
||||
if ($use_tax) {
|
||||
$price = $product_tax_calculator->addTaxes($price);
|
||||
}
|
||||
|
||||
// Eco Tax
|
||||
if (($result['ecotax'] || isset($result['attribute_ecotax'])) && $with_ecotax) {
|
||||
$ecotax = $result['ecotax'];
|
||||
if (isset($result['attribute_ecotax']) && $result['attribute_ecotax'] > 0) {
|
||||
$ecotax = $result['attribute_ecotax'];
|
||||
}
|
||||
|
||||
if ($id_currency) {
|
||||
$ecotax = Tools::convertPrice($ecotax, $id_currency);
|
||||
}
|
||||
if ($use_tax) {
|
||||
// reinit the tax manager for ecotax handling
|
||||
$tax_manager = TaxManagerFactory::getManager(
|
||||
$address,
|
||||
(int)Configuration::get('PS_ECOTAX_TAX_RULES_GROUP_ID')
|
||||
);
|
||||
$ecotax_tax_calculator = $tax_manager->getTaxCalculator();
|
||||
$price += $ecotax_tax_calculator->addTaxes($ecotax);
|
||||
} else {
|
||||
$price += $ecotax;
|
||||
}
|
||||
}
|
||||
|
||||
// Configurator add price impact
|
||||
if ($id_configurator != null) {
|
||||
$sql = 'SELECT price FROM `'._DB_PREFIX_.'configurator_storage` WHERE id_configurator = '.(int)$id_configurator.
|
||||
' AND id_product = '.(int)$id_product;
|
||||
$priceResult = Db::getInstance()->executeS($sql);
|
||||
if (count($priceResult) > 0) {
|
||||
foreach($priceResult as $p) {
|
||||
$price+= $p['price'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reduction
|
||||
$specific_price_reduction = 0;
|
||||
if (($only_reduc || $use_reduc) && $specific_price) {
|
||||
if ($specific_price['reduction_type'] == 'amount') {
|
||||
$reduction_amount = $specific_price['reduction'];
|
||||
|
||||
if (!$specific_price['id_currency']) {
|
||||
$reduction_amount = Tools::convertPrice($reduction_amount, $id_currency);
|
||||
}
|
||||
|
||||
$specific_price_reduction = $reduction_amount;
|
||||
|
||||
// Adjust taxes if required
|
||||
|
||||
if (!$use_tax && $specific_price['reduction_tax']) {
|
||||
$specific_price_reduction = $product_tax_calculator->removeTaxes($specific_price_reduction);
|
||||
}
|
||||
if ($use_tax && !$specific_price['reduction_tax']) {
|
||||
$specific_price_reduction = $product_tax_calculator->addTaxes($specific_price_reduction);
|
||||
}
|
||||
} else {
|
||||
$specific_price_reduction = $price * $specific_price['reduction'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($use_reduc) {
|
||||
$price -= $specific_price_reduction;
|
||||
}
|
||||
|
||||
// Group reduction
|
||||
if ($use_group_reduction) {
|
||||
$reduction_from_category = GroupReduction::getValueForProduct($id_product, $id_group);
|
||||
if ($reduction_from_category !== false) {
|
||||
$group_reduction = $price * (float)$reduction_from_category;
|
||||
} else { // apply group reduction if there is no group reduction for this category
|
||||
$group_reduction = (($reduc = Group::getReductionByIdGroup($id_group)) != 0) ? ($price * $reduc / 100) : 0;
|
||||
}
|
||||
|
||||
$price -= $group_reduction;
|
||||
}
|
||||
|
||||
if ($only_reduc) {
|
||||
return Tools::ps_round($specific_price_reduction, $decimals);
|
||||
}
|
||||
|
||||
$price = Tools::ps_round($price, $decimals);
|
||||
|
||||
if ($price < 0) {
|
||||
$price = 0;
|
||||
}
|
||||
|
||||
self::$_prices[$cache_id] = $price;
|
||||
return self::$_prices[$cache_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Override product price
|
||||
*/
|
||||
public static function getPriceStatic($id_product, $usetax = true, $id_product_attribute = null, $decimals = 6, $divisor = null,
|
||||
$only_reduc = false, $usereduc = true, $quantity = 1, $force_associated_tax = false, $id_customer = null, $id_cart = null,
|
||||
$id_address = null, &$specific_price_output = null, $with_ecotax = true, $use_group_reduction = true, Context $context = null,
|
||||
$use_customer_price = true, $id_configurator = null)
|
||||
{
|
||||
if (!$context) {
|
||||
$context = Context::getContext();
|
||||
}
|
||||
|
||||
$cur_cart = $context->cart;
|
||||
|
||||
if ($divisor !== null) {
|
||||
Tools::displayParameterAsDeprecated('divisor');
|
||||
}
|
||||
|
||||
if (!Validate::isBool($usetax) || !Validate::isUnsignedId($id_product)) {
|
||||
die(Tools::displayError());
|
||||
}
|
||||
|
||||
// Initializations
|
||||
$id_group = null;
|
||||
if ($id_customer) {
|
||||
$id_group = Customer::getDefaultGroupId((int)$id_customer);
|
||||
}
|
||||
if (!$id_group) {
|
||||
$id_group = (int)Group::getCurrent()->id;
|
||||
}
|
||||
|
||||
// If there is cart in context or if the specified id_cart is different from the context cart id
|
||||
if (!is_object($cur_cart) || (Validate::isUnsignedInt($id_cart) && $id_cart && $cur_cart->id != $id_cart)) {
|
||||
/*
|
||||
* When a user (e.g., guest, customer, Google...) is on PrestaShop, he has already its cart as the global (see /init.php)
|
||||
* When a non-user calls directly this method (e.g., payment module...) is on PrestaShop, he does not have already it BUT knows the cart ID
|
||||
* When called from the back office, cart ID can be inexistant
|
||||
*/
|
||||
if (!$id_cart && !isset($context->employee)) {
|
||||
die(Tools::displayError());
|
||||
}
|
||||
$cur_cart = new Cart($id_cart);
|
||||
// Store cart in context to avoid multiple instantiations in BO
|
||||
if (!Validate::isLoadedObject($context->cart)) {
|
||||
$context->cart = $cur_cart;
|
||||
}
|
||||
}
|
||||
|
||||
$cart_quantity = 0;
|
||||
if ((int)$id_cart) {
|
||||
$cache_id = 'Product::getPriceStatic_'.(int)$id_product.'-'.(int)$id_cart;
|
||||
if (!Cache::isStored($cache_id) || ($cart_quantity = Cache::retrieve($cache_id) != (int)$quantity)) {
|
||||
$sql = 'SELECT SUM(`quantity`)
|
||||
FROM `'._DB_PREFIX_.'cart_product`
|
||||
WHERE `id_product` = '.(int)$id_product.'
|
||||
AND `id_cart` = '.(int)$id_cart;
|
||||
$cart_quantity = (int)Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue($sql);
|
||||
Cache::store($cache_id, $cart_quantity);
|
||||
} else {
|
||||
$cart_quantity = Cache::retrieve($cache_id);
|
||||
}
|
||||
}
|
||||
|
||||
$id_currency = Validate::isLoadedObject($context->currency) ? (int)$context->currency->id : (int)Configuration::get('PS_CURRENCY_DEFAULT');
|
||||
|
||||
// retrieve address informations
|
||||
$id_country = (int)$context->country->id;
|
||||
$id_state = 0;
|
||||
$zipcode = 0;
|
||||
|
||||
if (!$id_address && Validate::isLoadedObject($cur_cart)) {
|
||||
$id_address = $cur_cart->{Configuration::get('PS_TAX_ADDRESS_TYPE')};
|
||||
}
|
||||
|
||||
if ($id_address) {
|
||||
$address_infos = Address::getCountryAndState($id_address);
|
||||
if ($address_infos['id_country']) {
|
||||
$id_country = (int)$address_infos['id_country'];
|
||||
$id_state = (int)$address_infos['id_state'];
|
||||
$zipcode = $address_infos['postcode'];
|
||||
}
|
||||
} elseif (isset($context->customer->geoloc_id_country)) {
|
||||
$id_country = (int)$context->customer->geoloc_id_country;
|
||||
$id_state = (int)$context->customer->id_state;
|
||||
$zipcode = $context->customer->postcode;
|
||||
}
|
||||
|
||||
if (Tax::excludeTaxeOption()) {
|
||||
$usetax = false;
|
||||
}
|
||||
|
||||
if ($usetax != false
|
||||
&& !empty($address_infos['vat_number'])
|
||||
&& $address_infos['id_country'] != Configuration::get('VATNUMBER_COUNTRY')
|
||||
&& Configuration::get('VATNUMBER_MANAGEMENT')) {
|
||||
$usetax = false;
|
||||
}
|
||||
|
||||
if (is_null($id_customer) && Validate::isLoadedObject($context->customer)) {
|
||||
$id_customer = $context->customer->id;
|
||||
}
|
||||
|
||||
$return = Product::priceCalculation(
|
||||
$context->shop->id,
|
||||
$id_product,
|
||||
$id_product_attribute,
|
||||
$id_country,
|
||||
$id_state,
|
||||
$zipcode,
|
||||
$id_currency,
|
||||
$id_group,
|
||||
$quantity,
|
||||
$usetax,
|
||||
$decimals,
|
||||
$only_reduc,
|
||||
$usereduc,
|
||||
$with_ecotax,
|
||||
$specific_price_output,
|
||||
$use_group_reduction,
|
||||
$id_customer,
|
||||
$use_customer_price,
|
||||
$id_cart,
|
||||
$cart_quantity,
|
||||
$id_configurator
|
||||
);
|
||||
|
||||
return $return ;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<?php
|
||||
class AdminOrdersController extends AdminController
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,248 @@
|
||||
<?php
|
||||
class CartController extends CartControllerCore
|
||||
{
|
||||
protected $id_configurator;
|
||||
|
||||
protected function parseConfigurator()
|
||||
{
|
||||
// @todo : in real time is it a good solution to get id before write items OR get from ps_cart_product and update it quickly
|
||||
$this->id_configurator = Db::getInstance()->getValue('SELECT (MAX(`id_configurator`)+1) FROM `'._DB_PREFIX_.'configurator_storage`');
|
||||
if ($this->id_configurator === null) {
|
||||
$this->id_configurator = 1;
|
||||
}
|
||||
|
||||
// Create array of option to retrieve price impact
|
||||
$detectOptGroup = 'optgroup-';
|
||||
$postValues = Tools::getAllValues();
|
||||
if (count($postValues) > 0) {
|
||||
$sqlValues = array();
|
||||
foreach($postValues as $p => $v) {
|
||||
if (!empty($v)) {
|
||||
if (substr($p, 0, strlen($detectOptGroup)) === $detectOptGroup) {
|
||||
if (is_array($v) && count($v) > 0) {
|
||||
foreach ($v as $vArray) {
|
||||
$price = Db::getInstance()->getValue('SELECT price FROM ps_product_configurator_opt_impact WHERE id_product_configurator_opt_impact = '.(int)$vArray);
|
||||
$sqlValues[] = '('.$this->id_configurator.', '.$this->id_product.', '.substr($p, strlen($detectOptGroup)).', '.pSQL($vArray).', '.$price.')';
|
||||
}
|
||||
} else {
|
||||
$price = Db::getInstance()->getValue('SELECT price FROM ps_product_configurator_opt_impact WHERE id_product_configurator_opt_impact = '.(int)$v);
|
||||
$sqlValues[] = '('.$this->id_configurator.', '.$this->id_product.', '.substr($p, strlen($detectOptGroup)).', '.pSQL($v).', '.$price.')';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($sqlValues) > 0) {
|
||||
$result = Db::getInstance()->execute('
|
||||
INSERT INTO `'._DB_PREFIX_.'configurator_storage` (`id_configurator`, `id_product`, `id_product_configurator_opt_group`, `id_product_configurator_opt_impact`, `price`)
|
||||
VALUES '.implode(',', $sqlValues)
|
||||
);
|
||||
// update cart_product
|
||||
if ($result) {
|
||||
Db::getInstance()->update('cart_product', array(
|
||||
'id_configurator' => (int)$this->id_configurator),
|
||||
'id_cart='.(int)$this->context->cart->id.
|
||||
' AND id_product='.(int)$this->id_product.
|
||||
' AND id_address_delivery='.(int)$this->id_address_delivery.
|
||||
' AND id_shop='.(int)$this->context->cart->id_shop.
|
||||
' AND id_product_attribute='.(int)$this->id_product_attribute.
|
||||
' AND quantity='.(int)$this->qty
|
||||
.' AND id_configurator = 0');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected function processDeleteProductInCart()
|
||||
{
|
||||
$customization_product = Db::getInstance()->executeS('SELECT * FROM `'._DB_PREFIX_.'customization`
|
||||
WHERE `id_cart` = '.(int)$this->context->cart->id.' AND `id_product` = '.(int)$this->id_product.' AND `id_customization` != '.(int)$this->customization_id);
|
||||
|
||||
if (count($customization_product)) {
|
||||
$product = new Product((int)$this->id_product);
|
||||
if ($this->id_product_attribute > 0) {
|
||||
$minimal_quantity = (int)Attribute::getAttributeMinimalQty($this->id_product_attribute);
|
||||
} else {
|
||||
$minimal_quantity = (int)$product->minimal_quantity;
|
||||
}
|
||||
|
||||
$total_quantity = 0;
|
||||
foreach ($customization_product as $custom) {
|
||||
$total_quantity += $custom['quantity'];
|
||||
}
|
||||
|
||||
if ($total_quantity < $minimal_quantity) {
|
||||
$this->ajaxDie(Tools::jsonEncode(array(
|
||||
'hasError' => true,
|
||||
'errors' => array(sprintf(Tools::displayError('You must add %d minimum quantity', !Tools::getValue('ajax')), $minimal_quantity)),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->context->cart->deleteProduct($this->id_product, $this->id_product_attribute, $this->customization_id, $this->id_address_delivery)) {
|
||||
Hook::exec('actionAfterDeleteProductInCart', array(
|
||||
'id_cart' => (int)$this->context->cart->id,
|
||||
'id_product' => (int)$this->id_product,
|
||||
'id_product_attribute' => (int)$this->id_product_attribute,
|
||||
'customization_id' => (int)$this->customization_id,
|
||||
'id_address_delivery' => (int)$this->id_address_delivery
|
||||
));
|
||||
|
||||
if (!Cart::getNbProducts((int)$this->context->cart->id)) {
|
||||
$this->context->cart->setDeliveryOption(null);
|
||||
$this->context->cart->gift = 0;
|
||||
$this->context->cart->gift_message = '';
|
||||
$this->context->cart->update();
|
||||
}
|
||||
}
|
||||
$removed = CartRule::autoRemoveFromCart();
|
||||
CartRule::autoAddToCart();
|
||||
if (count($removed) && (int)Tools::getValue('allow_refresh')) {
|
||||
$this->ajax_refresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function processChangeProductInCart()
|
||||
{
|
||||
$mode = (Tools::getIsset('update') && $this->id_product) ? 'update' : 'add';
|
||||
|
||||
if ($this->qty == 0) {
|
||||
$this->errors[] = Tools::displayError('Null quantity.', !Tools::getValue('ajax'));
|
||||
} elseif (!$this->id_product) {
|
||||
$this->errors[] = Tools::displayError('Product not found', !Tools::getValue('ajax'));
|
||||
}
|
||||
|
||||
$product = new Product($this->id_product, true, $this->context->language->id);
|
||||
if (!$product->id || !$product->active || !$product->checkAccess($this->context->cart->id_customer)) {
|
||||
$this->errors[] = Tools::displayError('This product is no longer available.', !Tools::getValue('ajax'));
|
||||
return;
|
||||
}
|
||||
|
||||
$qty_to_check = $this->qty;
|
||||
$cart_products = $this->context->cart->getProducts();
|
||||
|
||||
if (is_array($cart_products)) {
|
||||
foreach ($cart_products as $cart_product) {
|
||||
if ((!isset($this->id_product_attribute) || $cart_product['id_product_attribute'] == $this->id_product_attribute) &&
|
||||
(isset($this->id_product) && $cart_product['id_product'] == $this->id_product)) {
|
||||
$qty_to_check = $cart_product['cart_quantity'];
|
||||
|
||||
if (Tools::getValue('op', 'up') == 'down') {
|
||||
$qty_to_check -= $this->qty;
|
||||
} else {
|
||||
$qty_to_check += $this->qty;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check product quantity availability
|
||||
if ($this->id_product_attribute) {
|
||||
if (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $qty_to_check)) {
|
||||
$this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax'));
|
||||
}
|
||||
} elseif ($product->hasAttributes()) {
|
||||
$minimumQuantity = ($product->out_of_stock == 2) ? !Configuration::get('PS_ORDER_OUT_OF_STOCK') : !$product->out_of_stock;
|
||||
$this->id_product_attribute = Product::getDefaultAttribute($product->id, $minimumQuantity);
|
||||
// @todo do something better than a redirect admin !!
|
||||
if (!$this->id_product_attribute) {
|
||||
Tools::redirectAdmin($this->context->link->getProductLink($product));
|
||||
} elseif (!Product::isAvailableWhenOutOfStock($product->out_of_stock) && !Attribute::checkAttributeQty($this->id_product_attribute, $qty_to_check)) {
|
||||
$this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax'));
|
||||
}
|
||||
} elseif (!$product->checkQty($qty_to_check)) {
|
||||
$this->errors[] = Tools::displayError('There isn\'t enough product in stock.', !Tools::getValue('ajax'));
|
||||
}
|
||||
|
||||
// If no errors, process product addition
|
||||
if (!$this->errors && $mode == 'add') {
|
||||
// Add cart if no cart found
|
||||
if (!$this->context->cart->id) {
|
||||
if (Context::getContext()->cookie->id_guest) {
|
||||
$guest = new Guest(Context::getContext()->cookie->id_guest);
|
||||
$this->context->cart->mobile_theme = $guest->mobile_theme;
|
||||
}
|
||||
$this->context->cart->add();
|
||||
if ($this->context->cart->id) {
|
||||
$this->context->cookie->id_cart = (int)$this->context->cart->id;
|
||||
}
|
||||
}
|
||||
|
||||
// Check customizable fields
|
||||
if (!$product->hasAllRequiredCustomizableFields() && !$this->customization_id) {
|
||||
$this->errors[] = Tools::displayError('Please fill in all of the required fields, and then save your customizations.', !Tools::getValue('ajax'));
|
||||
}
|
||||
|
||||
if (!$this->errors) {
|
||||
$cart_rules = $this->context->cart->getCartRules();
|
||||
$available_cart_rules = CartRule::getCustomerCartRules($this->context->language->id, (isset($this->context->customer->id) ? $this->context->customer->id : 0), true, true, true, $this->context->cart, false, true);
|
||||
|
||||
// Configurator options
|
||||
$this->parseConfigurator();
|
||||
|
||||
// Send configurator id
|
||||
$update_quantity = $this->context->cart->updateQty(
|
||||
$this->qty,
|
||||
$this->id_product,
|
||||
$this->id_product_attribute,
|
||||
$this->customization_id,
|
||||
Tools::getValue('op', 'up'),
|
||||
$this->id_address_delivery,
|
||||
null,
|
||||
true,
|
||||
$this->id_configurator
|
||||
);
|
||||
|
||||
if ($update_quantity < 0) {
|
||||
// If product has attribute, minimal quantity is set with minimal quantity of attribute
|
||||
$minimal_quantity = ($this->id_product_attribute) ? Attribute::getAttributeMinimalQty($this->id_product_attribute) : $product->minimal_quantity;
|
||||
$this->errors[] = sprintf(Tools::displayError('You must add %d minimum quantity', !Tools::getValue('ajax')), $minimal_quantity);
|
||||
} elseif (!$update_quantity) {
|
||||
$this->errors[] = Tools::displayError('You already have the maximum quantity available for this product.', !Tools::getValue('ajax'));
|
||||
} elseif ((int)Tools::getValue('allow_refresh')) {
|
||||
// If the cart rules has changed, we need to refresh the whole cart
|
||||
$cart_rules2 = $this->context->cart->getCartRules();
|
||||
if (count($cart_rules2) != count($cart_rules)) {
|
||||
$this->ajax_refresh = true;
|
||||
} elseif (count($cart_rules2)) {
|
||||
$rule_list = array();
|
||||
foreach ($cart_rules2 as $rule) {
|
||||
$rule_list[] = $rule['id_cart_rule'];
|
||||
}
|
||||
foreach ($cart_rules as $rule) {
|
||||
if (!in_array($rule['id_cart_rule'], $rule_list)) {
|
||||
$this->ajax_refresh = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$available_cart_rules2 = CartRule::getCustomerCartRules($this->context->language->id, (isset($this->context->customer->id) ? $this->context->customer->id : 0), true, true, true, $this->context->cart, false, true);
|
||||
if (count($available_cart_rules2) != count($available_cart_rules)) {
|
||||
$this->ajax_refresh = true;
|
||||
} elseif (count($available_cart_rules2)) {
|
||||
$rule_list = array();
|
||||
foreach ($available_cart_rules2 as $rule) {
|
||||
$rule_list[] = $rule['id_cart_rule'];
|
||||
}
|
||||
foreach ($cart_rules2 as $rule) {
|
||||
if (!in_array($rule['id_cart_rule'], $rule_list)) {
|
||||
$this->ajax_refresh = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$removed = CartRule::autoRemoveFromCart();
|
||||
CartRule::autoAddToCart();
|
||||
if (count($removed) && (int)Tools::getValue('allow_refresh')) {
|
||||
$this->ajax_refresh = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
class ProductController extends ProductControllerCore
|
||||
{
|
||||
protected $optValues = array();
|
||||
|
||||
protected $impactPrice;
|
||||
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
|
||||
if ($this->ajax && Tools::getValue('impactprice', 0)) {
|
||||
if (Validate::isLoadedObject($this->product)) {
|
||||
$qty = Tools::getValue('qty', 1);
|
||||
// @todo : Attributes & Quantity
|
||||
$productPrice = $this->product->getPrice(true, null, 6 , null, false, true, $qty);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create array of option to retrieve price impact
|
||||
$detectOptGroup = 'optgroup-';
|
||||
$postValues = Tools::getAllValues();
|
||||
$this->optValues = array();
|
||||
$impact = 0;
|
||||
if (count($postValues) > 0) {
|
||||
foreach($postValues as $p => $v) {
|
||||
if (!empty($v)) {
|
||||
if (substr($p, 0, strlen($detectOptGroup)) === $detectOptGroup) {
|
||||
$this->optValues[] = array(
|
||||
'id_product_configurator_opt_group' => substr($p, strlen($detectOptGroup)),
|
||||
'id_product_configurator_opt_impact' => $v
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$impact = $this->product->getConfiguratorImpactPrice($this->optValues);
|
||||
}
|
||||
|
||||
$this->impactPrice = $productPrice + $impact;
|
||||
}
|
||||
}
|
||||
|
||||
public function postProcess()
|
||||
{
|
||||
if ($this->ajax && Tools::getValue('impactprice', 0)) {
|
||||
$return = array(
|
||||
'priceDisplay' => Tools::displayPrice($this->impactPrice),
|
||||
'price' => $this->impactPrice,
|
||||
);
|
||||
die(Tools::jsonEncode($return));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{$message}
|
@ -0,0 +1,47 @@
|
||||
{*Ajouter une OptGroup*}
|
||||
<div id="product-configurator-opt" class="panel product-tab">
|
||||
<div class="panel-heading">{l s='Add options for this product'}</div>
|
||||
<div class="panel-body">
|
||||
<form id="product-configurator-opt-add" name="product-configurator-opt-add" class="form-inline" method="post" data-token="{$token}" action="{$OptGroupListFormLink}">
|
||||
<input type="hidden" name="id_product" value="{$id_product}"/>
|
||||
<div class="form-group">
|
||||
<select name="id_configurator_opt_group" class="form-control">
|
||||
<option value="">-</option>
|
||||
{foreach $OptGroupList as $l}
|
||||
<option value="{$l.id_configurator_opt_group}">{$l.name}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-default pull-right">{l s="Add New option"}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$('form#product-configurator-opt-add').submit(function(){
|
||||
|
||||
var postData = {
|
||||
//required parameters
|
||||
ajax : true,
|
||||
controller : 'AdminAntadisConfiguratorProduct',
|
||||
action : 'Add',
|
||||
token : $(this).attr('data-token'),
|
||||
//additional parameters to your controller
|
||||
id_configurator_opt_group : $('select[name=id_configurator_opt_group]').val(),
|
||||
id_product: $('input[name=id_product]').val(),
|
||||
};
|
||||
|
||||
$.post('ajax-tab.php', postData, function (data) {}, 'json')
|
||||
.done(function(){
|
||||
window.location.href = window.location.href;
|
||||
})
|
||||
.fail(function(){
|
||||
// Display error message
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
|
||||
{*Gestion des OptGroup*}
|
||||
{$ProductOptGroupList}
|
||||
|
@ -0,0 +1,53 @@
|
||||
{if $optGroupList|@count > 0}
|
||||
<h3 class="page-product-heading" id="antadisconfigurator-content-tab">{l s='Options' mod='antadisconfigurator'}</h3>
|
||||
<input type="hidden" name="id_product" value="{$product->id}" />
|
||||
{foreach item=optGroup from=$optGroupList}
|
||||
<h4>{$optGroup['name']}</h4> {*visible*}
|
||||
{if $optGroup['type'] == 'text'}
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<input type="text" class="configurator-opt" name="optgroup-{$optGroup['id_product_configurator_opt_group']}" value="" placeholder="{$optImpact['name']}" />
|
||||
{/foreach}
|
||||
{elseif $optGroup['type'] == 'date'}
|
||||
<label>{$optGroup['value']}</label>
|
||||
<input type="date" class="configurator-opt" name="optgroup-{$optGroup['id_product_configurator_opt_group']}" value="" />
|
||||
{elseif $optGroup['type'] == 'radio'}
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<label>
|
||||
<input type="radio" data-url="./?controller=product&impactprice=1&ajax=1" class="configurator-opt-click" name="optgroup-{$optGroup['id_product_configurator_opt_group']}" value="{$optImpact['id_product_configurator_opt_impact']}" />
|
||||
{$optImpact['name']}
|
||||
</label>
|
||||
{/foreach}
|
||||
{elseif $optGroup['type'] == 'checkbox'}
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<label>
|
||||
<input type="checkbox" data-url="./?controller=product&impactprice=1&ajax=1" class="configurator-opt-click" name="optgroup-{$optGroup['id_product_configurator_opt_group']}[]" value="{$optImpact['id_product_configurator_opt_impact']}" />
|
||||
{$optImpact['name']}
|
||||
</label>
|
||||
{/foreach}
|
||||
{elseif $optGroup['type'] == 'select'}
|
||||
<select class="configurator-opt-change" data-url="./?controller=product&impactprice=1&ajax=1" name="optgroup-{$optGroup['id_product_configurator_opt_group']}">
|
||||
<option value="">-</option>
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<option value="{$optImpact['id_product_configurator_opt_impact']}">{$optImpact['name']}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
{/if}
|
||||
{/foreach}
|
||||
|
||||
<script>
|
||||
$('.configurator-opt-change').on('change', function(e) {
|
||||
console.log($('form#buy_block').serialize());
|
||||
$.post($(this).data('url'), $('form#buy_block').serialize(), function (data) {
|
||||
console.log(data);
|
||||
$('span#our_price_display').replaceWith('<span id="our_price_display" class="price" itemprop="price" content="'+data.price+'">'+data.priceDisplay+'</span>');
|
||||
}, 'json').fail(function(){});
|
||||
});
|
||||
$('.configurator-opt-click').on('click', function(e){
|
||||
console.log($('form#buy_block').serialize());
|
||||
$.post($(this).data('url'), $('form#buy_block').serialize(), function (data) {
|
||||
console.log(data);
|
||||
$('span#our_price_display').replaceWith('<span id="our_price_display" class="price" itemprop="price" content="'+data.price+'">'+data.priceDisplay+'</span>');
|
||||
}, 'json').fail(function(){});
|
||||
})
|
||||
</script>
|
||||
{/if}
|
@ -0,0 +1,76 @@
|
||||
{if $optGroupList|@count > 0}
|
||||
<h3 class="page-product-heading" id="antadisconfigurator-content-tab">{l s='Options' mod='antadisconfigurator'}</h3>
|
||||
<form name="configurator-opt" method="post" action="./">
|
||||
<input type="hidden" name="controller" value="product"/>
|
||||
<input type="hidden" name="token" value="{$token}" />
|
||||
<input type="hidden" name="ajax" value="1" />
|
||||
<input type="hidden" name="impactprice" value="1" />
|
||||
<input type="hidden" name="id_product" value="{$product->id}" />
|
||||
{foreach item=optGroup from=$optGroupList}
|
||||
<h4>{$optGroup['name']}</h4> {*visible*}
|
||||
{if $optGroup['type'] == 'text'}
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<input type="text" class="configurator-opt" name="optgroup-{$optGroup['id_product_configurator_opt_group']}" value="" placeholder="{$optImpact['name']}" />
|
||||
{/foreach}
|
||||
{elseif $optGroup['type'] == 'date'}
|
||||
<label>{$optGroup['value']}</label>
|
||||
<input type="date" class="configurator-opt" name="optgroup-{$optGroup['id_product_configurator_opt_group']}" value="" />
|
||||
{elseif $optGroup['type'] == 'radio'}
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<label>
|
||||
<input type="radio" class="configurator-opt" name="optgroup-{$optGroup['id_product_configurator_opt_group']}" value="{$optImpact['id_product_configurator_opt_impact']}" />
|
||||
{$optImpact['name']}
|
||||
</label>
|
||||
{/foreach}
|
||||
{elseif $optGroup['type'] == 'checkbox'}
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<label>
|
||||
<input type="checkbox" class="configurator-opt" name="optgroup-{$optGroup['id_product_configurator_opt_group']}[]" value="{$optImpact['id_product_configurator_opt_impact']}" />
|
||||
{$optImpact['name']}
|
||||
</label>
|
||||
{/foreach}
|
||||
{elseif $optGroup['type'] == 'select'}
|
||||
<select class="configurator-opt" name="optgroup-{$optGroup['id_product_configurator_opt_group']}">
|
||||
<option value="">-</option>
|
||||
{foreach item=optImpact from=$optImpactList[$optGroup['id_product_configurator_opt_group']]}
|
||||
<option value="{$optImpact['id_product_configurator_opt_impact']}">{$optImpact['name']}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</form>
|
||||
|
||||
<script>
|
||||
$('.configurator-opt').on('change', function(e) {
|
||||
if ($(this).attr('type') == 'radio' ||
|
||||
$(this).attr('type') == 'checkbox' ||
|
||||
$(this).attr('type') == 'input') {
|
||||
return;
|
||||
}
|
||||
if ($(this).val() == "") {
|
||||
return;
|
||||
}
|
||||
$('form[name=configurator-opt]').submit();
|
||||
});
|
||||
$('.configurator-opt').on('click', function(e){
|
||||
if ($(this).attr('type') == 'text' ||
|
||||
$(this).attr('type') == 'select') {
|
||||
return;
|
||||
}
|
||||
if ($(this).val() == "") {
|
||||
return;
|
||||
}
|
||||
$('form[name=configurator-opt]').submit();
|
||||
})
|
||||
|
||||
$('form[name=configurator-opt]').on('submit', function(e) {
|
||||
console.log($(this).serialize());
|
||||
$.post($(this).attr('action'), $(this).serialize(), function (data) {
|
||||
console.log(data);
|
||||
$('span#our_price_display').replaceWith('<span id="our_price_display" class="price" itemprop="price" content="'+data.price+'">'+data.priceDisplay+'</span>');
|
||||
}, 'json').fail(function(){ /* Display error message */ });
|
||||
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
{/if}
|
@ -0,0 +1 @@
|
||||
No Config
|
@ -384,6 +384,9 @@
|
||||
</div> <!-- end attributes -->
|
||||
{/if}
|
||||
</div> <!-- end product_attributes -->
|
||||
|
||||
{hook h='displayProductForm' mod='antadisconfigurator'}
|
||||
|
||||
<div class="box-cart-bottom">
|
||||
<div{if (!$allow_oosp && $product->quantity <= 0) || !$product->available_for_order || (isset($restricted_country_mode) && $restricted_country_mode) || $PS_CATALOG_MODE} class="unvisible"{/if}>
|
||||
<p id="add_to_cart" class="buttons_bottom_block no-print">
|
||||
|
@ -32,6 +32,18 @@
|
||||
<p class="product-name"><a href="{$link->getProductLink($product.id_product, $product.link_rewrite, $product.category, null, null, $product.id_shop, $product.id_product_attribute, false, false, true)|escape:'html':'UTF-8'}">{$product.name|escape:'html':'UTF-8'}</a></p>
|
||||
{if $product.reference}<small class="cart_ref">{l s='SKU'}{$smarty.capture.default}{$product.reference|escape:'html':'UTF-8'}</small>{/if}
|
||||
{if isset($product.attributes) && $product.attributes}<small><a href="{$link->getProductLink($product.id_product, $product.link_rewrite, $product.category, null, null, $product.id_shop, $product.id_product_attribute, false, false, true)|escape:'html':'UTF-8'}">{$product.attributes|@replace: $smarty.capture.sep:$smarty.capture.default|escape:'html':'UTF-8'}</a></small>{/if}
|
||||
|
||||
{if isset($product.configurator_opt)}
|
||||
{foreach item=group from=$product.configurator_opt}
|
||||
<small>
|
||||
{$group['name']} :
|
||||
{foreach item=i from=$group['value'] name=opt}
|
||||
{$i} {if !$smarty.foreach.opt.last},{/if}
|
||||
{/foreach}
|
||||
</small>
|
||||
{/foreach}
|
||||
{/if}
|
||||
|
||||
</td>
|
||||
{if $PS_STOCK_MANAGEMENT}
|
||||
<td class="cart_avail"><span class="label{if $product.quantity_available <= 0 && isset($product.allow_oosp) && !$product.allow_oosp} label-danger{elseif $product.quantity_available <= 0} label-warning{else} label-success{/if}">{if $product.quantity_available <= 0}{if isset($product.allow_oosp) && $product.allow_oosp}{if isset($product.available_later) && $product.available_later}{$product.available_later}{else}{l s='In Stock'}{/if}{else}{l s='Out of stock'}{/if}{else}{if isset($product.available_now) && $product.available_now}{$product.available_now}{else}{l s='In Stock'}{/if}{/if}</span>{if !$product.is_virtual}{hook h="displayProductDeliveryTime" product=$product}{/if}</td>
|
||||
|
Loading…
Reference in New Issue
Block a user