Prestashop - calculated field in backoffice table form - module

I would like to add a "virtual" field to a Prestashop 1.6 custom table in the back office. The field indice_calculo_pvp2 should not be saved into the database, as it is a calculated from the values of indice_calculo_pvp and precio_venta_recomendado. What would be the correct way to implement this?
My code is as follows :
public function renderList() {
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->fields_list = array(
'id_product_price' => array(
'search' => false,
'title' => 'ID'
),
'precio_coste' => array(
'title' => 'Precio coste',
'search' => false,
'callback' => 'callback_format_price',
'suffix' => '€'
),
'indice_calculo_pvp' => array(
'title' => 'Indice de cálculo PVP',
'search' => false,
'callback' => 'callback_format_price',
'suffix' => '%'
),
'indice_calculo_pvp2' => array(
'title' => 'Indice de cálculo PVP2',
'search' => false,
'callback' => 'callback_calculate_pvp',
'suffix' => '%'
),
'precio_venta_recomendado' => array(
'title' => 'Precio de venta recomendado con IVA',
'search' => false,
'callback' => 'callback_format_price',
'suffix' => '€'
)
);
return parent::renderList();
}

Use calculation in your SQL SELECT query for the list. I don't know what your calculation formula and your SELECT query is but example of this:
$this->_select = 'a.indice_calculo_pvp / a.precio_venta_recomendado AS indice_calculo_pvp2';

You have 2 options:
You can use a callback function as in your code:
public function callback_calculate_pvp($id, $tr)
{
return $tr['indice_calculo_pvp'] * $tr['precio_venta_recomendado'];
}
You can use a virtual column in your field list indice_calculo_pvp2 and set the value in your SQL query or in getList override function (as ProductController do with price).
Good luck.

Related

remove button from CGridView with condition

Hi I have CRUD generated CGridView in yii. I need to add a new button to CGridView rows and hide it if appointment_status(one of CGridView column) value equals 0
This is my code of CGridView,
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'bookings-grid',
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
'id',
'name',
'email',
'telephone',
'time',
'employee',
'appointment_status',
'client_ip',
'link' => array(
'header' => 'Confirmation',
'type' => 'raw',
'value' => 'CHtml::button("$data->appointment_status",array("onclick"=>"document.location.href=\'".Yii::app()->controller->createUrl("controller/action",array("id"=>$data->id))."\'"))',
'visible'=>$data->appointment_status==1,
),
array(
'class' => 'CButtonColumn',
),
),
));
But all I'm getting is error stating,
Undefined variable: data
It would be great help if someone can look into it.
you can use like this:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'bookings-grid',
'dataProvider' => $model->search(),
'filter' => $model,
'columns' => array(
'id',
'name',
'email',
'telephone',
'time',
'employee',
'appointment_status',
'client_ip',
'link' => array(
'header' => 'Confirmation',
'type' => 'raw',
'value' => function ($data) {
if ($data->appointment_status == 1) {
return CHtml::button("$data->appointment_status", array("onclick" => "document.location.href=\'" . Yii::app()->controller->createUrl("controller/action", array("id" => $data->id)) . "\'"));
} else {
return;
}
}
),
array(
'class' => 'CButtonColumn',
),
),
));
Your 'visible' handling the column visibility and not the button, you can use custom attribute on model to create and handle the button visibility.
add to your model:
public function getConfirmationButton()
{
if ($data->appointment_status == 1) {
return CHtml::button($this->appointment_status,array("onclick"=>"document.location.href=\'".Yii::app()->controller->createUrl("controller/action",array("id"=>$this->id))."\'"));
} else {
return '';
}
}
and call it in your view:
..........
'link' => array(
'header' => 'Confirmation',
'type' => 'raw',
'value' => '$data->confirmationButton',
),
...........
visible is a boolean or a PHP expression that will be evaluated to give a boolean. During the evaluation $data is assigned to the current item from the dataProvider used. $data doesn't exist outside of the evaluation function evaluateExpression(). As such the implementation should be:
`visible` => '$data->appointment_status == 1',
You need to quote value of visible key in link array. So instead of this:
'visible'=>$data->appointment_status==1
It should be:
'visible'=>'$data->appointment_status==1'
it should work now.
You will get undefined variable because visible not allow any callback.
Try this solution, it's yii2 code and i don't know much of Yii.
'delete' => function ($url, $model) {
return ($model->isVisible($model)) ?
Html::a('<span class="glyphicon glyphicon-trash"></span>',
$url,
['title' => Yii::t('app', 'Delete')]) : '';
public static function isVisible($data)
{
return ($data->appointment_status == 1) ? true : false;
}

Yii - Sort Error while using Join query in CDbCriteria with CActiveDataProvider

Model Search Method
$criteria->alias = 'c';
$criteria->select = 'c.*,max(ca.date) AS lastactivity';
$criteria->join = 'LEFT JOIN tbl_contact_action AS ca ON (ca.contact_id=c.contact_id)';
$criteria->condition = 'c.status<>"Deleted"';
$criteria->group = 'c.contact_id';
$criteria->order = 'lastactivity DESC';
$sort = new CSort;
$sort->defaultOrder = array('lastactivity' => CSort::SORT_DESC); //'name ASC';
$sort->attributes = array(
'name' => 'name',
'email' => 'email',
'status' => 'status',
'createdon' => 'createdon',
'lastactivity' => 'lastactivity',
);
$sort->applyOrder($criteria);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
'sort' => $sort,
));
Basically, I have a 1:n relationship where in I need only latest record from child table. The parent table data will be displayed based on the comment that is done latest in child table. How to make this field sortable ?
Error
CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'c.lastactivity' in 'order clause'.
Just a theory:
because you have a join with together sql, all the data will be together in 1 result. I am not sure if you can still use $data->ca->date because your data is not a known active record type.
Try putting
$criteria->select = 'maintable.*,ca.date as ca_date';
then you should be able to use
array(
'header' => 'Last Activity',
'class' => 'gridDataColumn',
'value' => '$data->ca_date',
),
Below is the Model which will allow to have a custom/computational field that will be SORTABLE. Instead of simply writing 'lastactivity'=>'lastactivity' in sort array, passing whole array did the trick for me. Hope it helps someone :)
class Contact extends CActiveRecord {
public $verifyCode;
public $lastactivity;
public static function model($className = __CLASS__) {
return parent::model($className);
}
public function tableName() {
return '{{contact}}';
}
public function rules() {
return array(
array('name, email, subject, message', 'required', 'message' => Yii::t('app', 'MSG_ATTRIBUTE_BLANK')),
array('email', 'email'),
array('verifyCode', 'CaptchaExtendedValidator', 'allowEmpty' => !CCaptcha::checkRequirements(), 'on' => 'fContact'),
array('name, email,subject,message,lastactivity', 'safe', 'on' => 'search'),
array('name, subject, email, message, status,createdon,updatedon,verifyCode,lastactivity', 'safe'),
);
}
public function relations() {
return array(
'ca' => array(self::HAS_MANY, 'ContactAction', 'contact_id'),
);
}
public function search() {
$criteria = new CDbCriteria;
$criteria->compare('name', CommonFunctions::escapeOperator($this->name), true, 'OR');
$criteria->compare('subject', CommonFunctions::escapeOperator($this->subject), true, 'OR');
$criteria->compare('email', CommonFunctions::escapeOperator($this->email), true, 'OR');
$criteria->compare('status', CommonFunctions::escapeOperator($this->status), true,'OR');
$lastactivity_sql = '(select max(date) from tbl_contact_action ca where ca.contact_id=t.contact_id)';
$criteria->select = array('*', $lastactivity_sql . ' as lastactivity');
$criteria->addCondition('status<>"Deleted"');
$criteria->compare($lastactivity_sql, $this->lastactivity);
$sort = new CSort;
$sort->defaultOrder = array('lastactivity' => CSort::SORT_DESC); //'title ASC';
$sort->attributes = array(
'name' => 'name',
'email' => 'email',
'status' => 'status',
'createdon' => 'createdon',
'lastactivity' => array(
'asc' => 'lastactivity ASC',
'desc' => 'lastactivity DESC',
),
);
$sort->applyOrder($criteria);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
'sort' => $sort,
'pagination' => array(
'pageSize' => Yii::app()->user->getState('contactPageSize', Yii::app()->params['RECORDPERPAGE_ADMIN']),
'currentPage' => Yii::app()->user->getState('Contact_page', 0),
),
));
}
}

Invalid type given. String expected - Zend Framework 2

Im working on Zend Framework 2 especially with Zend Forms. I have declared a Select dropdown box in
Form:
$selectElement = new Element\Select('selectElement');
$selectElement->setAttribute('title', 'Select a Value')
->setAttribute('id', 'id');
$data = array(
array(
//Fetching the values from database
),
);
$selectElement->setAttribute('multiple', 'multiple')
->setValueOptions($data);
$this->add($selectElement);
InputFilter:
$inputFilter->add($factory->createInput(array(
'name' => 'selectElement',
'required' => false,
'filters' => array(
array(
'name' => 'Int'
),
),
)));
I have used Zend Debug to get the values which are in the selectElement dropbox in this fashion:
$dataSelectElements = $this->getRequest()->getPost('selectElement');
\Zend\Debug\Debug::dump($dataSelectElements);
Debug Result:
array(4) {
[0] => string(2) "20"
[1] => string(2) "22"
[2] => string(2) "23"
[3] => string(2) "75"
}
Basically Im getting the id's from the selectElement form to store it in the database. Right now Im getting a notice and zend form error:
Notice Error:
Notice: Array to string conversion in ..\zendframework\zendframework\library\Zend\Filter\Int.php on line 29
And a form invalid error:
array(1) {
[0] => array(1) {
["selectElement "] => array(1) {
["explodeInvalid"] => string(35) "Invalid type given. String expected"
}
}
}
Is there a solution to over come this problem. Any help would be appreciated.
The Int filter will attempt to make an Integer out of your array of data, which is not going to work.
Previously I've used the Callback filter, which can be used to loop through the data and check if each value is an Int.
For example:
'filters' => array(
array(
'name' => 'Callback',
'options' => array(
'callback' => function($values) {
return array_filter($values, function($value) {
return ((int)$value == $value);
});
}
)
),
),
I did bit differently, something like this
form
class Companyform extends Form
{
public function __construct()
{
// we want to ignore the name passed
parent::__construct('company');
$this->setAttribute ('method', 'post');
$this->setAttribute ('class', 'form-horizontal');
$this->add ( array (
'name' => 'parentID',
'type' => 'Zend\Form\Element\Select',
'attributes' => array(
'id' => 'parentID',
'type' => 'select',
'placeholder' => "Parent Company",
),
'options' => array(
'label' => 'Parent Company'
)
));
$this->add(array(
'name' => 'btnsubmit',
'attributes' => array(
'id' => 'btnsubmit',
'type' => 'submit',
'value' => 'Add',
'class' => 'btn btn-primary'
),
));
}
}
controller
public function addAction()
{
$request = $this->getRequest();
$companyList = $this->_getCompanyList();
$form = new Companyform();
$form->get('parentID')->setAttribute('options',$companyList);
if ($request->isPost())
{
$company = new Company();
$form->setInputFilter($company->getInputFilter());
$form->setData($request->getPost());
if ($form->isvalid())
{
}
}
}
public function _getCompanyList()
{
$companies = $this->Em()->getEntityManager()->getRepository('XXXX\Entity\Company')->findBy(array('isDeleted'=>'0'));
$companyIDList = array();
$companyIDList[0] = "No Parent";
foreach ($companies as $company)
{
$companyIDList[$company->id] = $company->companyName;
}
return $companyIDList;
}
Entity class
protected $inputFilter;
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add($factory->createInput(array(
'name' => 'companyName',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 2,
'max' => 255,
),
),
),
)));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
You may need to add following library in entity
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
In ZendFramework 2, when you creating a (add) element from your Form file, Check the attribute: inarrayvalidator is true.
$this->add(array(
'name' => 'select_name',
'type' => 'select',
'id' => 'select_name',
'options' => array(
'label' => 'Select Name',
),
'attributes' => array(
'id' => 'select_id',
'inarrayvalidator' => true,
),
));
I hope, this works...

How do I set order by field when using fuelphp orm's has many?

I'm using fuelphp's orm to model my data. How can I control which order my child elements are returned when doing a cascaded find.
For example, here's the example config to attach comments to a post:
protected static $_has_many = array(
'comments' => array(
'key_from' => 'id',
'model_to' => 'Model_Comment',
'key_to' => 'post_id',
'cascade_save' => true,
'cascade_delete' => false,
)
);
How can I say, for example, order the comments by the 'date_entered' field?
Thanks in advance,
David
You can add the order_by clause to the conditions.
protected static $_has_many = array(
'comments' => array(
'key_from' => 'id',
'model_to' => 'Model_Comment',
'key_to' => 'post_id',
'cascade_save' => true,
'cascade_delete' => false,
'conditions' => array(
'order_by' => array(
'field1' => 'DESC',
'field2' => 'ASC',
)
),
),
);
Note that as they are defined in the relation, they are always active and can not be turned off!

Populating CGridView one to many relation

In my project one of the model named types having multiple relation to other models the criteria with part is giving below its like
$criteria->with = array(
'category',
'subCategory',
'accountsSupplierPriceDetails' => array(
'with' => 'serviceLevel'
)
);
the relationship goes like
types - category - relation(1-1)
types - subcategory - relation(1-1)
types - accountsSupplierPriceDetails - relation(1-1)
accountsSupplierPriceDetails - serviceLevel - relation(1-n)
my problem is how to display the names from each table in a grid. the result of (1-n) should be displayed in a dropdownbox. when i try to access the data from column it shows the error Trying to get property of non-object ($data->accountsSupplierPriceDetails->serviceLevel ->name). can anyone please help me.
Thanks in advance.
in my view i create a cgridview with 5 rows in which one row data is populated using dropdownlist.
<div style="width:700px; height:auto;">
<?php
$widget = $this->widget('zii.widgets.grid.CGridView', array(
'id' => 'response-grid',
'dataProvider' => $pickdataset->pickCategorylistingForMain(),
'cssFile' => Yii::app()->baseUrl . '/media/css/gridview.css',
'summaryText' => '',
'ajaxUpdate' => 'response-grid',
'enablePagination' => true,
'pager' => array(
'class' => 'LinkPager',
'cssFile' => false,
'header' => false,
'firstPageLabel' => 'First',
'prevPageLabel' => 'Previous',
'nextPageLabel' => 'Next',
'lastPageLabel' => 'Last',
),
'columns' => array(
array(
'name' => 'id',
'header' => '#',
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'type' => 'raw',
'name' => 'categoryExt',
'header' => 'Category',
),
array(
'type' => 'raw',
'header' => 'Sub Category',
'value' => '$data->subCategory->name',
),
array(
'type' => 'raw',
'name' => 'locationExt',
'header' => 'Location',
),
array(
'type' => 'raw',
'header' => 'Name',
'value' => 'CHtml::dropDownList($data->corporate_id."-".$data->category_id."-".$data->sub_category_id."-".$data->location_id,"",popDropBox($data->masterCategoryServiceLevels), array("class" => "listbox"), array("empty" => "Select a Location"))',
),
array(
'type' => 'raw',
'header' => 'Pick',
'value' => 'CHtml::image(Yii::app()->baseUrl . "/media/images/edit_icon.png",$data->corporate_id."-".$data->category_id."-".$data->sub_category_id."-".$data->location_id,array("title" => "Select this Combination"))',
),
),));
function popDropBox($data)
{
$list = array();
foreach ($data as $row)
{
$list[$row->serviceLevel->id] = $row->serviceLevel->name;
}
return $list;
}
?>
</div>
the relation in model is:
'masterCategoryServiceLevels' => array(self::HAS_MANY, 'MasterCategoryServiceLevel', 'category_template_id'),
'corporate' => array(self::BELONGS_TO, 'AccountsCorporate', 'corporate_id'),
'category' => array(self::BELONGS_TO, 'MasterCategory', 'category_id'),
'subCategory' => array(self::BELONGS_TO, 'MasterCategory', 'sub_category_id'),
'location' => array(self::BELONGS_TO, 'MasterLocation', 'location_id'),
the row is
array(
'type' => 'raw',
'header' => 'Name',
'value' => 'CHtml::dropDownList($data->corporate_id."-".$data->category_id."-".$data->sub_category_id."-".$data->location_id,"",popDropBox($data->masterCategoryServiceLevels), array("class" => "listbox"), array("empty" => "Select a Location"))',
),
and i use a function to create dropdown data is
function popDropBox($data)
{
$list = array();
foreach ($data as $row)
{
$list[$row->serviceLevel->id] = $row->serviceLevel->name;
}
return $list;
}
please comment if you have any doubt. i am free to share... have a nice day SO friends... wishes and prayers.