I'm using prestashop v 1.6.1.1
What I'm trying to get
I'm trying to add a column called dni to my customer section in backoffice.
What I tried
I know the file to do this is called AdminCustomersController.php and it is located in controllers/admin/AdminCustomersController.php
Also I know that with this query i can get the data in the database:
SELECT ps_address.dni, ps_customer. *
FROM ps_customer
INNER JOIN ps_address ON ps_customer.id_customer = ps_address.id_customer
LIMIT 0 , 30
The current query in the customer section is:
SELECT a.`id_customer`, `firstname`, `lastname`, `email`, a.`active` AS `active`, `newsletter`, `optin` , a.date_add, gl.name as title, ( SELECT SUM(total_paid_real / conversion_rate) FROM ps_orders o WHERE o.id_customer = a.id_customer AND o.id_shop IN (2, 1) AND o.valid = 1 ) as total_spent, ( SELECT c.date_add FROM ps_guest g LEFT JOIN ps_connections c ON c.id_guest = g.id_guest WHERE g.id_customer = a.id_customer ORDER BY c.date_add DESC LIMIT 1 ) as connect, shop.name as shop_name FROM `ps_customer` a LEFT JOIN ps_gender_lang gl ON (a.id_gender = gl.id_gender AND gl.id_lang = 1) LEFT JOIN ps_shop shop ON a.id_shop = shop.id_shop WHERE 1 AND a.`deleted` = 0 AND a.id_shop IN (2, 1) ORDER BY `date_add` DESC LIMIT 0, 50
I dont know
I dont know how to change that query to add just ps_address.dni and also get the other columns.
Thanks
EDITED Partially Solved
Well, At the end I didn't change AdminCustomersController.php I have changed AdminAddressesController.php that means change Customer/Directions backoffice.
I have just added this lines and it worked like charm:
$this->fields_list = array(
'id_address' => array('title' => $this->l('ID'), 'align' => 'center', 'class' => 'fixed-width-xs'),
'firstname' => array('title' => $this->l('First Name'), 'filter_key' => 'a!firstname'),
'lastname' => array('title' => $this->l('Last Name'), 'filter_key' => 'a!lastname'),
'address1' => array('title' => $this->l('Address')),
'postcode' => array('title' => $this->l('Zip/Postal Code'), 'align' => 'right'),
'dni' => array('title' => $this->l('DNI'), 'align' => 'right'),
'city' => array('title' => $this->l('City')),
'country' => array('title' => $this->l('Country'), 'type' => 'select', 'list' => $this->countries_array, 'filter_key' => 'cl!id_country'));
Now I have a place to search DNI-customer
Try this, override the AdminCustomersController, new file in prestashop/override/controllers/admin/ named AdminCustomersController.php
class AdminCustomersController extends AdminCustomersControllerCore {
public function __construct(){
$this->bootstrap = true;
$this->required_database = true;
$this->required_fields = array('newsletter','optin');
$this->table = 'customer';
$this->className = 'Customer';
$this->lang = false;
$this->deleted = true;
$this->explicitSelect = true;
$this->allow_export = true;
$this->addRowAction('edit');
$this->addRowAction('view');
$this->addRowAction('delete');
$this->bulk_actions = array(
'delete' => array(
'text' => $this->l('Delete selected'),
'confirm' => $this->l('Delete selected items?'),
'icon' => 'icon-trash'
)
);
$this->context = Context::getContext();
$this->default_form_language = $this->context->language->id;
$titles_array = array();
$genders = Gender::getGenders($this->context->language->id);
foreach ($genders as $gender) {
/** #var Gender $gender */
$titles_array[$gender->id_gender] = $gender->name;
}
$this->_join = 'LEFT JOIN '._DB_PREFIX_.'gender_lang gl ON (a.id_gender = gl.id_gender AND gl.id_lang = '.(int)$this->context->language->id.')
LEFT JOIN '._DB_PREFIX_.'address addr ON (a.id_customer = addr.id_customer)';
$this->_use_found_rows = false;
$this->fields_list = array(
'id_customer' => array(
'title' => $this->l('ID'),
'align' => 'text-center',
'class' => 'fixed-width-xs'
),
'title' => array(
'title' => $this->l('Social title'),
'filter_key' => 'a!id_gender',
'type' => 'select',
'list' => $titles_array,
'filter_type' => 'int',
'order_key' => 'gl!name'
),
'firstname' => array(
'title' => $this->l('First name'),
'filter_key' => 'a!firstname'
),
'lastname' => array(
'title' => $this->l('Last name'),
'filter_key' => 'a!lastname'
),
'email' => array(
'title' => $this->l('Email address')
),
'dni' => array( // Your new field
'title' => $this->l('DNI'),
'filter_key' => 'addr!dni'
)
);
if (Configuration::get('PS_B2B_ENABLE')) {
$this->fields_list = array_merge($this->fields_list, array(
'company' => array(
'title' => $this->l('Company')
),
));
}
$this->fields_list = array_merge($this->fields_list, array(
'total_spent' => array(
'title' => $this->l('Sales'),
'type' => 'price',
'search' => false,
'havingFilter' => true,
'align' => 'text-right',
'badge_success' => true
),
'active' => array(
'title' => $this->l('Enabled'),
'align' => 'text-center',
'active' => 'status',
'type' => 'bool',
'orderby' => false,
'filter_key' => 'a!active'
),
'newsletter' => array(
'title' => $this->l('Newsletter'),
'align' => 'text-center',
'type' => 'bool',
'callback' => 'printNewsIcon',
'orderby' => false
),
'optin' => array(
'title' => $this->l('Opt-in'),
'align' => 'text-center',
'type' => 'bool',
'callback' => 'printOptinIcon',
'orderby' => false
),
'date_add' => array(
'title' => $this->l('Registration'),
'type' => 'date',
'align' => 'text-right'
),
'connect' => array(
'title' => $this->l('Last visit'),
'type' => 'datetime',
'search' => false,
'havingFilter' => true
)
));
$this->shopLinkType = 'shop';
$this->shopShareDatas = Shop::SHARE_CUSTOMER;
AdminController::__construct(); // Important
$this->_select = '
addr.dni,
a.date_add, gl.name as title, (
SELECT SUM(total_paid_real / conversion_rate)
FROM '._DB_PREFIX_.'orders o
WHERE o.id_customer = a.id_customer
'.Shop::addSqlRestriction(Shop::SHARE_ORDER, 'o').'
AND o.valid = 1
) as total_spent, (
SELECT c.date_add FROM '._DB_PREFIX_.'guest g
LEFT JOIN '._DB_PREFIX_.'connections c ON c.id_guest = g.id_guest
WHERE g.id_customer = a.id_customer
ORDER BY c.date_add DESC
LIMIT 1
) as connect';
$this->_group = 'GROUP BY a.id_customer'; // Don't forget this
// Check if we can add a customer
if (Shop::isFeatureActive() && (Shop::getContext() == Shop::CONTEXT_ALL || Shop::getContext() == Shop::CONTEXT_GROUP)) {
$this->can_add_customer = false;
}
self::$meaning_status = array(
'open' => $this->l('Open'),
'closed' => $this->l('Closed'),
'pending1' => $this->l('Pending 1'),
'pending2' => $this->l('Pending 2')
);
}
}
You don't have to do anything else. However, if the customer have more of one address you could have unexpected results.
You're gonna have to create a new file named AdminCustomersController.php in your override/controllers/admin folder. Read this for more information.
Then, in your __construct() function, you'll have to append a sub query to $this->select and add the corresponding field to $this->fields_list.
Hereafter is an example I made to add the invoice id on the BO orders page, the process should be quite similar for what you're trying to achieve :
<?php
class AdminOrdersController extends AdminOrdersControllerCore
{
public function __construct()
{
parent::__construct();
$this->_select .= '
, (SELECT MAX(oi.id_order_invoice) FROM '._DB_PREFIX_.'order_invoice oi WHERE oi.id_order = a.id_order) as id_inv
';
$this->fields_list = array_merge($this->fields_list, array(
'id_inv' => array(
'title' => $this->l('Invoice'),
'align' => 'text-center',
'class' => 'fixed-width-xs',
'orderby' => false,
'search' => false
)
));
}
[...]
}
Related
I am using prestashop 1.7.3 and I have added Tracking number filter on orders list page BUT it is just after the filtter for Refference number. How can I move filtter tracking number after the filtter for order status (Please, check the screenshot attached)
My code is located in: /override/controllers/admin/AdminOrdersController.php
Screenshot
<?php
class AdminOrdersController extends AdminOrdersControllerCore
{
public function __construct()
{
$this->bootstrap = true;
$this->table = 'order';
$this->className = 'Order';
$this->lang = false;
$this->addRowAction('view');
$this->explicitSelect = true;
$this->allow_export = true;
$this->deleted = false;
parent::__construct();
$this->_select = '
a.id_currency,
a.id_order AS id_pdf,
CONCAT(c.`firstname`, \' \', c.`lastname`) AS `customer`,
c.email AS `email`,
address.phone `phone`,
osl.`name` AS `osname`,
os.`color`,
IF((SELECT so.id_order FROM `'._DB_PREFIX_.'orders` so WHERE so.id_customer = a.id_customer AND so.id_order < a.id_order LIMIT 1) > 0, 0, 1) as new,
country_lang.name as cname,
IF(a.valid, 1, 0) badge_success';
$this->_join = '
INNER JOIN `'._DB_PREFIX_.'order_carrier` oc ON a.`id_order` = oc.`id_order`
LEFT JOIN `'._DB_PREFIX_.'customer` c ON (c.`id_customer` = a.`id_customer`)
INNER JOIN `'._DB_PREFIX_.'address` address ON address.id_address = a.id_address_delivery
INNER JOIN `'._DB_PREFIX_.'country` country ON address.id_country = country.id_country
INNER JOIN `'._DB_PREFIX_.'country_lang` country_lang ON (country.`id_country` = country_lang.`id_country` AND country_lang.`id_lang` = '.(int)$this->context->language->id.')
LEFT JOIN `'._DB_PREFIX_.'order_state` os ON (os.`id_order_state` = a.`current_state`)
LEFT JOIN `'._DB_PREFIX_.'order_state_lang` osl ON (os.`id_order_state` = osl.`id_order_state` AND osl.`id_lang` = '.(int)$this->context->language->id.')';
$this->_orderBy = 'id_order';
$this->_orderWay = 'DESC';
$this->_use_found_rows = true;
$statuses = OrderState::getOrderStates((int)$this->context->language->id);
foreach ($statuses as $status) {
$this->statuses_array[$status['id_order_state']] = $status['name'];
}
$this->fields_list = array(
'id_order' => array(
'title' => $this->trans('ID', array(), 'Admin.Global'),
'align' => 'text-center',
'class' => 'fixed-width-xs'
),
'reference' => array(
'title' => $this->trans('Reference', array(), 'Admin.Global')
),
'tracking_number' => array(
'title' => $this->l('tracking number'),
'havingFilter' => true,
),
/*
'new' => array(
'title' => $this->trans('New client', array(), 'Admin.Orderscustomers.Feature'),
'align' => 'text-center',
'type' => 'bool',
'tmpTableFilter' => true,
'orderby' => false,
),
*/
'customer' => array(
'title' => $this->trans('Customer', array(), 'Admin.Global'),
'havingFilter' => true,
),
'phone' => array(
'title' => $this->trans('Phone', array(), 'Admin.Global')
),
'email' => array(
'title' => $this->trans('Email', array(), 'Admin.Global')
),
);
if (Configuration::get('PS_B2B_ENABLE')) {
$this->fields_list = array_merge($this->fields_list, array(
'company' => array(
'title' => $this->trans('Company', array(), 'Admin.Global'),
'filter_key' => 'c!company'
),
));
}
$this->fields_list = array_merge($this->fields_list, array(
'total_paid_tax_incl' => array(
'title' => $this->trans('Total', array(), 'Admin.Global'),
'align' => 'text-right',
'type' => 'price',
'currency' => true,
'callback' => 'setOrderCurrency',
'badge_success' => true
),
'payment' => array(
'title' => $this->trans('Payment', array(), 'Admin.Global')
),
'osname' => array(
'title' => $this->trans('Status', array(), 'Admin.Global'),
'type' => 'select',
'color' => 'color',
'list' => $this->statuses_array,
'filter_key' => 'os!id_order_state',
'filter_type' => 'int',
'order_key' => 'osname'
),
'date_add' => array(
'title' => $this->trans('Date', array(), 'Admin.Global'),
'align' => 'text-right',
'type' => 'datetime',
'filter_key' => 'a!date_add'
)
));
/*
if (Country::isCurrentlyUsed('country', true)) {
$result = Db::getInstance(_PS_USE_SQL_SLAVE_)->ExecuteS('
SELECT DISTINCT c.id_country, cl.`name`
FROM `'._DB_PREFIX_.'orders` o
'.Shop::addSqlAssociation('orders', 'o').'
INNER JOIN `'._DB_PREFIX_.'address` a ON a.id_address = o.id_address_delivery
INNER JOIN `'._DB_PREFIX_.'country` c ON a.id_country = c.id_country
INNER JOIN `'._DB_PREFIX_.'country_lang` cl ON (c.`id_country` = cl.`id_country` AND cl.`id_lang` = '.(int)$this->context->language->id.')
ORDER BY cl.name ASC');
$country_array = array();
foreach ($result as $row) {
$country_array[$row['id_country']] = $row['name'];
}
$part1 = array_slice($this->fields_list, 0, 3);
$part2 = array_slice($this->fields_list, 3);
$part1['cname'] = array(
'title' => $this->trans('Delivery', array(), 'Admin.Global'),
'type' => 'select',
'list' => $country_array,
'filter_key' => 'country!id_country',
'filter_type' => 'int',
'order_key' => 'cname'
);
$this->fields_list = array_merge($part1, $part2);
}
*/
$this->shopLinkType = 'shop';
$this->shopShareDatas = Shop::SHARE_ORDER;
if (Tools::isSubmit('id_order')) {
// Save context (in order to apply cart rule)
$order = new Order((int)Tools::getValue('id_order'));
$this->context->cart = new Cart($order->id_cart);
$this->context->customer = new Customer($order->id_customer);
}
$this->bulk_actions = array(
'updateOrderStatus' => array('text' => $this->trans('Change Order Status', array(), 'Admin.Orderscustomers.Feature'), 'icon' => 'icon-refresh')
);
}
}
i solved it cycling the field_list array and rebuilding it into different array, so in my override i put this code just before closing the constructor function in this way
class AdminOrdersController extends AdminOrdersControllerCore
{
public function __construct()
{
public function __construct()
{
/* Your code */
$fileds = array();
foreach ($this->fields_list as $key => $value) {
$fileds[$key] = $value;
if ($key == 'current_state') {
$fileds['tracking_number'] = array(
'title' => $this->l('tracking number'),
'havingFilter' => true,
);
}
$this->fields_list = $fileds;
}
}
}
this works in my case
I need a specific list of recipients to receive stocks alerts only and another list of recipients to receive only the new order alert.
What is the best way to do it?
Thank you
Here is how I would deal with this question:
Create the override file /override/modules/mailalerts/mailalerts.php with this code:
<?php
class MailAlertsOverride extends MailAlerts
{
protected $merchant_mails_stock;
protected function init()
{
parent::init();
$this->merchant_mails_stock = str_replace(',', self::__MA_MAIL_DELIMITOR__, (string)Configuration::get('MA_MERCHANT_MAILS_STOCK'));
}
public function install($delete_params = true)
{
if (! parent::install($delete_params))
return false;
if ($delete_params)
{
Configuration::updateValue('MA_MERCHANT_MAILS_STOCK', Configuration::get('PS_SHOP_EMAIL'));
}
return true;
}
public function uninstall($delete_params = true)
{
if ($delete_params)
{
Configuration::deleteByName('MA_MERCHANT_MAILS_STOCK');
}
return parent::uninstall();
}
protected function postProcess()
{
$errors = array();
if (Tools::isSubmit('submitMAMerchant'))
{
$emails = (string)Tools::getValue('MA_MERCHANT_MAILS_STOCK');
if (!$emails || empty($emails))
$errors[] = $this->l('Please type one (or more) e-mail address');
else
{
$emails = str_replace(',', self::__MA_MAIL_DELIMITOR__, $emails);
$emails = explode(self::__MA_MAIL_DELIMITOR__, $emails);
foreach ($emails as $k => $email)
{
$email = trim($email);
if (!empty($email) && !Validate::isEmail($email))
{
$errors[] = $this->l('Invalid e-mail:').' '.Tools::safeOutput($email);
break;
}
elseif (!empty($email) && count($email) > 0)
$emails[$k] = $email;
else
unset($emails[$k]);
}
$emails = implode(self::__MA_MAIL_DELIMITOR__, $emails);
if (!Configuration::updateValue('MA_MERCHANT_MAILS_STOCK', (string)$emails))
$errors[] = $this->l('Cannot update settings');
}
}
if (count($errors) > 0)
{
$this->html .= $this->displayError(implode('<br />', $errors));
return $this->init();
}
parent::postProcess();
}
public function hookActionUpdateQuantity($params)
{
$this->merchant_mails = $this->merchant_mails_stock;
parent::hookActionUpdateQuantity($params);
}
public function renderForm()
{
$fields_form_1 = array(
'form' => array(
'legend' => array(
'title' => $this->l('Customer notifications'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'switch',
'is_bool' => true, //retro compat 1.5
'label' => $this->l('Product availability'),
'name' => 'MA_CUSTOMER_QTY',
'desc' => $this->l('Gives the customer the option of receiving a notification when an out-of-stock product is available again.'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'switch',
'is_bool' => true, //retro compat 1.5
'label' => $this->l('Order edit'),
'name' => 'MA_ORDER_EDIT',
'desc' => $this->l('Send a notification to the customer when an order is edited.'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
),
),
'submit' => array(
'title' => $this->l('Save'),
'class' => 'btn btn-default pull-right',
'name' => 'submitMailAlert',
)
),
);
$fields_form_2 = array(
'form' => array(
'legend' => array(
'title' => $this->l('Merchant notifications'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'switch',
'is_bool' => true, //retro compat 1.5
'label' => $this->l('New order'),
'name' => 'MA_MERCHANT_ORDER',
'desc' => $this->l('Receive a notification when an order is placed.'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'switch',
'is_bool' => true, //retro compat 1.5
'label' => $this->l('Out of stock'),
'name' => 'MA_MERCHANT_OOS',
'desc' => $this->l('Receive a notification if the available quantity of a product is below the following threshold.'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'text',
'label' => $this->l('Threshold'),
'name' => 'MA_LAST_QTIES',
'class' => 'fixed-width-xs',
'desc' => $this->l('Quantity for which a product is considered out of stock.'),
),
array(
'type' => 'switch',
'is_bool' => true, //retro compat 1.5
'label' => $this->l('Coverage warning'),
'name' => 'MA_MERCHANT_COVERAGE',
'desc' => $this->l('Receive a notification when a product has insufficient coverage.'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'text',
'label' => $this->l('Coverage'),
'name' => 'MA_PRODUCT_COVERAGE',
'class' => 'fixed-width-xs',
'desc' => $this->l('Stock coverage, in days. Also, the stock coverage of a given product will be calculated based on this number.'),
),
array(
'type' => 'switch',
'is_bool' => true, //retro compat 1.5
'label' => $this->l('Returns'),
'name' => 'MA_RETURN_SLIP',
'desc' => $this->l('Receive a notification when a customer requests a merchandise return.'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
),
array(
'type' => 'textarea',
'cols' => 36,
'rows' => 4,
'label' => $this->l('E-mail addresses'),
'name' => 'MA_MERCHANT_MAILS',
'desc' => $this->l('One e-mail address per line (e.g. bob#example.com).'),
),
array(
'type' => 'textarea',
'cols' => 36,
'rows' => 4,
'label' => $this->l('E-mail stock addresses'),
'name' => 'MA_MERCHANT_MAILS_STOCK',
'desc' => $this->l('One e-mail address per line (e.g. bob#example.com).'),
),
),
'submit' => array(
'title' => $this->l('Save'),
'class' => 'btn btn-default pull-right',
'name' => 'submitMAMerchant',
)
),
);
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
$helper->default_form_language = $lang->id;
$helper->module = $this;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitMailAlertConfiguration';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false)
.'&configure='.$this->name
.'&tab_module='.$this->tab
.'&module_name='.$this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFieldsValues(),
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id
);
return $helper->generateForm(array($fields_form_1, $fields_form_2));
}
public function getConfigFieldsValues()
{
$config = parent::getConfigFieldsValues();
$config['MA_MERCHANT_MAILS_STOCK'] = Tools::getValue('MA_MERCHANT_MAILS_STOCK', Configuration::get('MA_MERCHANT_MAILS_STOCK'));
return $config;
}
}
I want create a input type switch in my backend module in prestashop 1.6.
I write this and work
array(
'type' => 'switch',
'label' => $this->l('Label'),
'name' => 'PRESTASHOP_INPUT_SWITCH',
'is_bool' => true,
'desc' => $this->l('Description'),
'values' => array(
array(
'id' => 'active_on',
'value' => true,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => false,
'label' => $this->l('Disabled')
)
),
)
But if i try with custom value e not boolean it not work
array(
'type' => 'switch',
'label' => $this->l('Label'),
'name' => 'PRESTASHOP_INPUT_SWITCH',
'is_bool' => false,
'desc' => $this->l('Description'),
'values' => array(
array(
'id' => 'value1',
'value' => 'value1',
'label' => $this->l('value1')
),
array(
'id' => 'value2',
'value' => 'value2',
'label' => $this->l('value2')
)
),
)
In backend appear two boxes with labels value 'no'.
In HelperForm classes of prestashop there is no trace of input type switch.
The same code with type radio work, but i want a switch type.
Unfortunately, as you can see here:
PrestaShop doesn't have possibility to use custom value in "switch" field.
You don't need to change default switch values.
This is how you handle submit form:
public function getContent()
{
if (Tools::isSubmit('submitForm'))
{
$my_value = ( (int)Tools::getValue('PRESTASHOP_INPUT_SWITCH') == 1 ) ? 'value1' : 'value2';
if (Configuration::updateValue('PRESTASHOP_INPUT_SWITCH', $my_value))
$echo .= $this->displayConfirmation($this->l('Value updated.'));
}
$echo .= $this->renderForm();
return $echo;
}
You probably already have something like this:
public function renderForm()
{
$fields_form = array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'switch',
'label' => $this->l('Label'),
'name' => 'PRESTASHOP_INPUT_SWITCH',
'is_bool' => true,
'desc' => $this->l('Description'),
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Value1')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Value2')
)
),
)
),
'submit' => array(
'title' => $this->l('Save'),
)
),
);
$helper = new HelperForm();
$helper->module = $this;
$helper->show_toolbar = false;
$helper->table = $this->table;
$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
$helper->default_form_language = $lang->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
$this->fields_form = array();
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitForm';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='.$this->tab.'&module_name='.$this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->tpl_vars = array(
'fields_value' => $this->getConfigFieldsValues(),
'languages' => $this->context->controller->getLanguages(),
'id_language' => $this->context->language->id
);
return $helper->generateForm(array($fields_form));
}
and loading the values:
public function getConfigFieldsValues()
{
return array(
'PRESTASHOP_INPUT_SWITCH' => Tools::getValue('PRESTASHOP_INPUT_SWITCH', Configuration::get('PRESTASHOP_INPUT_SWITCH') == 'value1' : 1 : 0),
);
}
Unfortunately prestashop doesn't support the custom value of switch but you can handle this like:
$config = Configuration::get('oneclickcheckout');
$this->settings = Tools::unSerialize($config);
$settings = $this->settings;
if (isset($settings['Description']) && $settings['Description'] == 1) {
}
I'm developing a module and extended AdminFeaturesController.php to display my custom field Add/Edit Feature Value, but it is showing following error in popup:
Notice on line 719 in file
D:\xampp\htdocs\prestashop16\tools\smarty\sysplugins\smarty_internal_templatebase.php(157)
: eval()'d code [8] Undefined index: value
I think it is due to I override the function initFormFeatureValue() in my AdminFeaturesController.php file and added a new field. Here is the code for that:
public function initFormFeatureValue()
{
$this->setTypeValue();
$this->fields_form[0]['form'] = array(
'legend' => array(
'title' => $this->l('Feature value'),
'icon' => 'icon-info-sign'
),
'input' => array(
array(
'type' => 'select',
'label' => $this->l('Feature'),
'name' => 'id_feature',
'options' => array(
'query' => Feature::getFeatures($this->context->language->id),
'id' => 'id_feature',
'name' => 'name'
),
'required' => true
),
array(
'type' => 'text',
'label' => $this->l('Value'),
'name' => 'value',
'lang' => true,
'size' => 33,
'hint' => $this->l('Invalid characters:').' <>;=#{}',
'required' => true
),
array(
'type' => 'select',
'label' => $this->l('Parent Feature Value'),
'name' => 'parent_id_feature_value',
'options' => array(
'query' => FeatureValue::getFeatureValues((int)Tools::getValue('id_feature')),
'id' => 'id_feature_value',
'name' => 'value'
),
'required' => true
),
),
'submit' => array(
'title' => $this->l('Save'),
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save then add another value mamu'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save'
)
)
);
$this->fields_value['id_feature'] = (int)Tools::getValue('id_feature');
// Create Object FeatureValue
$feature_value = new FeatureValue(Tools::getValue('id_feature_value'));
$this->tpl_vars = array(
'feature_value' => $feature_value,
);
$this->getlanguages();
$helper = new HelperForm();
$helper->show_cancel_button = true;
$back = Tools::safeOutput(Tools::getValue('back', ''));
if (empty($back))
$back = self::$currentIndex.'&token='.$this->token;
if (!Validate::isCleanHtml($back))
die(Tools::displayError());
$helper->back_url = $back;
$helper->currentIndex = self::$currentIndex;
$helper->token = $this->token;
$helper->table = $this->table;
$helper->identifier = $this->identifier;
$helper->override_folder = 'feature_value/';
$helper->id = $feature_value->id;
$helper->toolbar_scroll = false;
$helper->tpl_vars = $this->tpl_vars;
$helper->languages = $this->_languages;
$helper->default_form_language = $this->default_form_language;
$helper->allow_employee_form_lang = $this->allow_employee_form_lang;
$helper->fields_value = $this->getFieldsValue($feature_value);
$helper->toolbar_btn = $this->toolbar_btn;
$helper->title = $this->l('Add a new feature value');
$this->content .= $helper->generateForm($this->fields_form);
}
Any idea why it is showing this error? Also, it is not populating my custom field.
OK, I fixed it. The problem was with options array in my new field array. Following is the correct one.
array(
'type' => 'select',
'label' => $this->l('Parent Feature Value'),
'name' => 'parent_id_feature_value',
'options' => array(
'query' => FeatureValue::getFeatureValuesWithLang($this->context->language->id, $parent_id),
'id' => 'id_feature_value',
'name' => 'value'
),
'required' => true
),
Here I had to override the FeatureValue class and add the getFeatureValuesWithLang() function.
public static function getFeatureValuesWithLang($id_lang, $id_feature, $custom = false)
{
return Db::getInstance()->executeS('
SELECT *
FROM `'._DB_PREFIX_.'feature_value` v
LEFT JOIN `'._DB_PREFIX_.'feature_value_lang` vl
ON (v.`id_feature_value` = vl.`id_feature_value` AND vl.`id_lang` = '.(int)$id_lang.')
WHERE v.`id_feature` = '.(int)$id_feature.'
'.(!$custom ? 'AND (v.`custom` IS NULL OR v.`custom` = 0)' : '').'
ORDER BY v.`position` ASC
', true, false);
}
What is actually does is that it was finding the 'value' field which was not present in the query result. So, I override FeatureValue class and add the above method and called that one. It solved the problem.
I have created a custom field for Product Feature in my module override. Custom field for Feature is not saving in the database on edit. But on Add new feature it works fine. Here is the code for my AdminFeaturesController.php file:
<?php
class AdminFeaturesController extends AdminFeaturesControllerCore
{
public function __construct()
{
$this->table = 'feature';
$this->className = 'Feature';
$this->list_id = 'feature';
$this->identifier = 'id_feature';
$this->lang = true;
$this->fields_list = array(
'id_feature' => array(
'title' => $this->l('ID'),
'align' => 'center',
'class' => 'fixed-width-xs'
),
'name' => array(
'title' => $this->l('Name'),
'width' => 'auto',
'filter_key' => 'b!name'
),
'value' => array(
'title' => $this->l('Values'),
'orderby' => false,
'search' => false,
'align' => 'center',
'class' => 'fixed-width-xs'
),
'parent_id_feature' => array(
'title' => $this->l('ParentID'),
'align' => 'center',
'class' => 'fixed-width-xs'
),
'position' => array(
'title' => $this->l('Position'),
'filter_key' => 'a!position',
'align' => 'center',
'class' => 'fixed-width-xs',
'position' => 'position'
)
);
$this->bulk_actions = array(
'delete' => array(
'text' => $this->l('Delete selected'),
'icon' => 'icon-trash',
'confirm' => $this->l('Delete selected items?')
)
);
AdminController::__construct();
}
/**
* AdminController::renderForm() override
* #see AdminController::renderForm()
*/
public function renderForm()
{
$this->toolbar_title = $this->l('Add a new feature');
$this->fields_form = array(
'legend' => array(
'title' => $this->l('Feature with Parent'),
'icon' => 'icon-info-sign'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Name'),
'name' => 'name',
'lang' => true,
'size' => 33,
'hint' => $this->l('Invalid characters:').' <>;=#{}',
'required' => true
),
array(
'type' => 'select',
'label' => $this->l('Parent Feature'),
'name' => 'parent_id_feature',
'options' => array(
'query' => Feature::getFeaturesExcept($this->context->language->id, Tools::getValue('id_feature')),
'id' => 'id_feature',
'name' => 'name'
),
'required' => true
)
)
);
if (Shop::isFeatureActive())
{
$this->fields_form['input'][] = array(
'type' => 'shop',
'label' => $this->l('Shop association'),
'name' => 'checkBoxShopAsso',
);
}
$this->fields_form['submit'] = array(
'title' => $this->l('Save'),
);
return AdminController::renderForm();
}
public function renderView()
{
if (($id = Tools::getValue('id_feature')))
{
$this->setTypeValue();
$this->list_id = 'feature_value';
$this->position_identifier = 'id_feature_value';
$this->position_group_identifier = 'id_feature';
$this->lang = true;
// Action for list
$this->addRowAction('edit');
$this->addRowAction('delete');
if (!Validate::isLoadedObject($obj = new Feature((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;
}
$this->feature_name = $obj->name;
$this->toolbar_title = $this->feature_name[$this->context->employee->id_lang];
$this->fields_list = array(
'id_feature_value' => array(
'title' => $this->l('ID'),
'align' => 'center',
'class' => 'fixed-width-xs'
),
'value' => array(
'title' => $this->l('Value')
),
'parent_id_feature_value' => array(
'title' => $this->l('ParentID'),
'align' => 'center',
'class' => 'fixed-width-xs'
),
'position' => array(
'title' => $this->l('Position'),
'filter_key' => 'a!position',
'align' => 'center',
'class' => 'fixed-width-xs',
'position' => 'position'
)
);
$this->_where = sprintf('AND `id_feature` = %d', (int)$id);
$this->_orderBy = 'position';
self::$currentIndex = self::$currentIndex.'&id_feature='.(int)$id.'&viewfeature';
$this->processFilter();
return AdminController::renderList();
}
}
/**
* AdminController::renderForm() override
* #see AdminController::renderForm()
*/
public function initFormFeatureValue()
{
$this->setTypeValue();
$parent_id = Feature::getParentFeatureID((int)Tools::getValue('id_feature'));
$this->fields_form[0]['form'] = array(
'legend' => array(
'title' => $this->l('Feature value'),
'icon' => 'icon-info-sign'
),
'input' => array(
array(
'type' => 'select',
'label' => $this->l('Feature'),
'name' => 'id_feature',
'options' => array(
'query' => Feature::getFeatures($this->context->language->id),
'id' => 'id_feature',
'name' => 'name'
),
'required' => true
),
array(
'type' => 'text',
'label' => $this->l('Value'),
'name' => 'value',
'lang' => true,
'size' => 33,
'hint' => $this->l('Invalid characters:').' <>;=#{}',
'required' => true
),
array(
'type' => 'select',
'label' => $this->l('Parent Feature Value'),
'name' => 'parent_id_feature_value',
'options' => array(
'query' => FeatureValue::getFeatureValuesWithLang($this->context->language->id, $parent_id),
'id' => 'id_feature_value',
'name' => 'value'
),
'required' => true
),
),
'submit' => array(
'title' => $this->l('Save'),
),
'buttons' => array(
'save-and-stay' => array(
'title' => $this->l('Save then add another value'),
'name' => 'submitAdd'.$this->table.'AndStay',
'type' => 'submit',
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-save'
)
)
);
$this->fields_value['id_feature'] = (int)Tools::getValue('id_feature');
// Create Object FeatureValue
$feature_value = new FeatureValue(Tools::getValue('id_feature_value'));
$this->tpl_vars = array(
'feature_value' => $feature_value,
);
$this->getlanguages();
$helper = new HelperForm();
$helper->show_cancel_button = true;
$back = Tools::safeOutput(Tools::getValue('back', ''));
if (empty($back))
$back = self::$currentIndex.'&token='.$this->token;
if (!Validate::isCleanHtml($back))
die(Tools::displayError());
$helper->back_url = $back;
$helper->currentIndex = self::$currentIndex;
$helper->token = $this->token;
$helper->table = $this->table;
$helper->identifier = $this->identifier;
$helper->override_folder = 'feature_value/';
$helper->id = $feature_value->id;
$helper->toolbar_scroll = false;
$helper->tpl_vars = $this->tpl_vars;
$helper->languages = $this->_languages;
$helper->default_form_language = $this->default_form_language;
$helper->allow_employee_form_lang = $this->allow_employee_form_lang;
$helper->fields_value = $this->getFieldsValue($feature_value);
$helper->toolbar_btn = $this->toolbar_btn;
$helper->title = $this->l('Add a new feature value');
$this->content .= $helper->generateForm($this->fields_form);
}
public function ajaxProcessUpdatePositions()
{
if ($this->tabAccess['edit'] === '1')
{
$way = (int)Tools::getValue('way');
$id = (int)Tools::getValue('id');
$table = 'feature';
$positions = Tools::getValue($table);
if (empty($positions))
{
$table = 'feature_value';
$positions = Tools::getValue($table);
}
$new_positions = array();
foreach ($positions as $v)
if (!empty($v))
$new_positions[] = $v;
foreach ($new_positions as $position => $value)
{
$pos = explode('_', $value);
if (isset($pos[2]) && (int)$pos[2] === $id)
{
if ($table == 'feature')
{
if ($feature = new Feature((int)$pos[2]))
if (isset($position) && $feature->updatePosition($way, $position, $id))
echo 'ok position '.(int)$position.' for feature '.(int)$pos[1].'\r\n';
else
echo '{"hasError" : true, "errors" : "Can not update feature '.(int)$id.' to position '.(int)$position.' "}';
else
echo '{"hasError" : true, "errors" : "This feature ('.(int)$id.') can t be loaded"}';
break;
}
elseif ($table == 'feature_value')
{
if ($feature_value = new FeatureValue((int)$pos[2]))
if (isset($position) && $feature_value->updatePosition($way, $position, $id))
echo 'ok position '.(int)$position.' for feature value '.(int)$pos[2].'\r\n';
else
echo '{"hasError" : true, "errors" : "Can not update feature value '.(int)$id.' to position '.(int)$position.' "}';
else
echo '{"hasError" : true, "errors" : "This feature value ('.(int)$id.') can t be loaded"}';
break;
}
}
}
}
}
}
And my Feature.php is:
<?php
class Feature extends FeatureCore
{
/** #var string Name */
public $parent_id_feature;
/**
* #see ObjectModel::$definition
*/
public static $definition = array(
'table' => 'feature',
'primary' => 'id_feature',
'multilang' => true,
'fields' => array(
'position' => array('type' => self::TYPE_INT, 'validate' => 'isInt'),
// Parent Feature ID
'parent_id_feature' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => false),
// Lang fields
'name' => array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 128),
)
);
/**
* Get a parent feature id for a given id_feature
*
* #param integer $id_feature Feature id
* #return integer ID of parent feature
* #static
*/
public static function getParentFeatureID($id_feature)
{
return Db::getInstance()->getValue('
SELECT parent_id_feature
FROM `'._DB_PREFIX_.'feature` f
WHERE f.`id_feature` = '.(int)$id_feature
);
}
/**
* Get all features for a given language except for given id
*
* #param integer $id_lang Language id
* #param integer $id_feature Feature id to exclude
* #return array Multiple arrays with feature's data
* #static
*/
public static function getFeaturesExcept($id_lang, $id_feature, $with_shop = true)
{
return Db::getInstance()->executeS('
SELECT DISTINCT f.id_feature, f.*, fl.*
FROM `'._DB_PREFIX_.'feature` f
'.($with_shop ? Shop::addSqlAssociation('feature', 'f') : '').'
LEFT JOIN `'._DB_PREFIX_.'feature_lang` fl ON (f.`id_feature` = fl.`id_feature` AND fl.`id_lang` = '.(int)$id_lang.')
WHERE f.id_feature != '.(int)$id_feature.'
ORDER BY f.`position` ASC');
}
}