prestashop - Display status of order in AdminStats - prestashop

I want the status order to display at AdminStats. I created the file override/controllers/admin/AdminStatsController.php:
<?php // Check order status in Stats Dashboard BO class AdminStatsController extends AdminStatsControllerCore {
public function __construct() {
parent::__construct();
$this->fields_list['order_statuses'] = array('title' => $this->l('Order Status');
}
}
But when I go to AdminStats, a blank page shows up (see image below).
Any suggestions?

EDIT: this is not the solution in respect to the question asked.
I'd to do the exact same thing. I did it something like this, but it was AdminOrdersController but it's pretty much the same. Here it is,
// override/controllers/admin/AdminStatsController.php
<?php
public function __construct() {
parent::__construct();
$this->fields_list = array_merge($this->fields_list, [
'order_statuses' => [
'title' => $this->l('Order Status'),
'align' => 'text-center',
'callback' => 'orderStatusFunction', // yes, a callback to get a piece of UI back, a button maybe
'orderby' => false, // or true, anything you'd like
'search' => false,
'remove_onclick' => true,
]
]);
}
}
Now the callback
<?php
public function orderStatusFunction($row_number, $row_data) // row_data like date, order, customer, etc
{
/* do stuff with data and assign to your template */
$view = _PS_MODULE_DIR_ . 'path/to/view/file/view.tpl';
$html = $this->context->smarty->createTemplate($view, $this->context->smarty)->fetch();
return $html;
}
Let me know if you've any confusion, or if it didn't work out.

Related

Prestashop 1.7.7 - HelperForm in a Multistore Context

I'm testing a first simple version for a Multistore-compatible module. It has just two settings, which have to be saved differently depending on the current shop Context (a single shop mainly).
Now, I know that from 1.7.8 there are additional checkbox for each setting in the BO Form, but I have to manage to get it work also for 1.7.7.
Now, both Configuration::updateValue() and Configuration::get() should be multistore-ready, meaning that they update or retrieve the value only for the current context, so it should be fine.
The weird thing is that, after installing the test module, if I go to the configuration page, it automatically redirects to an All-Shop context and, if I try to manually switch (from the dropdown in the top right), it shows a blank page. Same thing happens if I try to deactivate the bottom checkbox "Activate this module in the context of: all shops".
Here is my code:
class TestModule extends Module
{
public function __construct()
{
$this->name = 'testmodule';
$this->tab = 'front_office_features';
$this->version = '1.0.0';
$this->author = 'Test';
$this->need_instance = 1;
$this->ps_versions_compliancy = [
'min' => '1.7.0.0',
'max' => '1.7.8.0',
];
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l("Test Module");
$this->description = $this->l('Collection of custom test extensions');
$this->confirmUninstall = $this->l('Are you sure you want to uninstall?');
if (!Configuration::get('TESTM_v')) {
$this->warning = $this->l('No version provided');
}
}
public function install()
{
if (Shop::isFeatureActive()) {
Shop::setContext(Shop::CONTEXT_ALL);
}
return (
parent::install()
&& $this->registerHook('header')
&& $this->registerHook('backOfficeHeader')
&& Configuration::updateValue('TESTM_v', $this->version)
);
}
public function uninstall()
{
if (Shop::isFeatureActive()) {
Shop::setContext(Shop::CONTEXT_ALL);
}
return (
parent::uninstall()
&& $this->unregisterHook('header')
&& $this->unregisterHook('backOfficeHeader')
&& Configuration::deleteByName('TESTM_v')
);
}
public function getContent()
{
// this part is executed only when the form is submitted
if (Tools::isSubmit('submit' . $this->name)) {
// retrieve the value set by the user
$configValue1 = (string) Tools::getValue('TESTM_CONFIG_1');
$configValue2 = (string) Tools::getValue('TESTM_CONFIG_2');
// check that the value 1 is valid
if (empty($configValue1)) {
// invalid value, show an error
$output = $this->displayError($this->l('Invalid Configuration value'));
} else {
// value is ok, update it and display a confirmation message
Configuration::updateValue('TESTM_CONFIG_1', $configValue1);
$output = $this->displayConfirmation($this->l('Settings updated'));
}
// check that the value 2 is valid
Configuration::updateValue('TESTM_CONFIG_2', $configValue2);
$output = $this->displayConfirmation($this->l('Settings updated'));
}
// display any message, then the form
return $output . $this->displayForm();
}
public function displayForm()
{
// Init Fields form array
$form = [
'form' => [
'legend' => [
'title' => $this->l('Settings'),
],
'input' => [
[
'type' => 'text',
'label' => $this->l('Custom CSS file-name.'),
'name' => 'TESTM_CONFIG_1',
'size' => 20,
'required' => true,
],
[
'type' => 'switch',
'label' => $this->l('Enable custom CSS loading.'),
'name' => 'TESTM_CONFIG_2',
'is_bool' => true,
'desc' => $this->l('required'),
'values' => array(
array(
'id' => 'sw1_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'sw1_off',
'value' => 0,
'label' => $this->l('Disabled')
)
)
],
],
'submit' => [
'title' => $this->l('Save'),
'class' => 'btn btn-default pull-right',
],
],
];
$helper = new HelperForm();
// Module, token and currentIndex
$helper->table = $this->table;
$helper->name_controller = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex . '&' . http_build_query(['configure' => $this->name]);
$helper->submit_action = 'submit' . $this->name;
// Default language
$helper->default_form_language = (int) Configuration::get('PS_LANG_DEFAULT');
// Load current value into the form or take default
$helper->fields_value['TESTM_CONFIG_1'] = Tools::getValue('TESTM_CONFIG_1', Configuration::get('TESTM_CONFIG_1'));
$helper->fields_value['TESTM_CONFIG_2'] = Tools::getValue('TESTM_CONFIG_2', Configuration::get('TESTM_CONFIG_2'));
return $helper->generateForm([$form]);
}
/**
* Custom CSS & JavaScript Hook for FO
*/
public function hookHeader()
{
//$this->context->controller->addJS($this->_path.'/views/js/front.js');
if (Configuration::get('TESTM_CONFIG_2') == 1) {
$this->context->controller->addCSS($this->_path.'/views/css/'.((string)Configuration::get('TESTM_CONFIG_1')));
} else {
$this->context->controller->removeCSS($this->_path.'/views/css/'.((string)Configuration::get('TESTM_CONFIG_1')));
}
}
}
As you can see it's a pretty simple setting: just load a custom CSS file and choose if loading it or not. I've red official PS Docs per Multistore handling and searched online, but cannot find an answer to this specific problem.
I've also tried to add:
if (Shop::isFeatureActive()) {
$currentIdShop = Shop::getContextShopID();
Shop::setContext(Shop::CONTEXT_SHOP, $currentIdShop);
}
To the 'displayForm()' function, but without results.
Thank you in advance.
It seemsit was a caching error.
After trying many variations, I can confirm that the first solution I've tried was the correct one, meaning that:
if (Shop::isFeatureActive()) {
$currentIdShop = Shop::getContextShopID();
Shop::setContext(Shop::CONTEXT_SHOP, $currentIdShop);
}
needs to be added ad the beginning of the "displayForm()" function for it to work when selecting a single shop. Values are now correctly saved in the database. With a little bit extra logic it can be arranged to behave differently (if needed) when saving for "All shops" context.

Yii2 - Bad Request (#400) Missing required parameters in index.php

I have problem for action view, update, and delete in index.php page, it always show bad request (#400) Missing required parameters: id_kategori and the address always go to localhost/training/frontend/web/index.php?r=kategori%2F(view/update/delete)&id=1, but when i change the address manually to localhost/training/frontend/web/index.php?r=kategori%2Fview&id_kategori=1 it's no problem, also i can create action but then it will redirect page to localhost/training/frontend/web/index.php?r=kategori%2Fview&id=1. Here's the code, its generate from Gii CRUD:
public function actionView($id_kategori)
{
return $this->render('view', [
'model' => $this->findModel($id_kategori),
]);
}
public function actionUpdate($id_kategori)
{
$model = $this->findModel($id_kategori);
if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) {
return $this->redirect(['view', 'id_kategori' => $model->id_kategori]);
}
return $this->render('update', [
'model' => $model,
]);
}
public function actionDelete($id_kategori)
{
$this->findModel($id_kategori)->delete();
return $this->redirect(['index']);
}
Should i rename id_kategori column to id and other id_column just to id?
Version: Yii 2 (2.0.43)
Template: Advanced Template
define $id_kategori=null in function
public function actionView($id_kategori=null)
{
return $this->render('view', [
'model' => $id_kategori ? $this->findModel($id_kategori) : null,
]);
}
You need to do like this
public function actionView($id) {
return $this->render('view', [
'model' => $this->findModel($id),
]);
}

How to get values from my object model and display my banner on header in Prestashop

I developed a custom multi-banner module to display on the header of my prestashop page. When i save my changes on form i would like to display it on header.
My module form:
My table to see all banner inserted:
I tried to use smarty and orm to retrieve all information but i don't know how to display on my header.
Any issues? I hope i can understand my trobles :)
Thanks
Here's the code of some of my files:
//in main file:
public function hookDisplayHeaderBanner($params) {
$banner = Banner::getBannerToDisplay();
// If there is a banner to display
if ($banner) {
$this->context->smarty->assign([
'banner' => $banner
]);
return $this->display(__FILE__, 'views/templates/hook/display-custom-banner.tpl');
}
// Nothing to display
return false;
}
//In classes/Banner.php
class Banner extends ObjectModel
{
public $id;
public $color;
public $background_color;
public $content;
public static $definition = [
'table' => 'custom_banner',
'primary' => 'id_custom_banner',
'multilang' => false,
'fields' => [
'color' => [
'type' => self::TYPE_STRING,
],
'background_color' => [
'type' => self::TYPE_STRING,
],
'content' => [
'type' => self::TYPE_STRING
]
]
];
/*
*
* Return the banner to display
*
* Here we put the logic to select the right banner
*/
public static function getBannerToDisplay()
{
$sql = 'SELECT *
FROM `' . _DB_PREFIX_ . self::$definition['table'] . '`
WHERE active = 1';
return Db::getInstance()->getRow($sql);
}
}
//In display-custom-banner.tpl
<div id="banner" style="background-color:{$banner.background_color}!important;">
<p style="color:{$banner.color}!important;">
{$banner.content}
</p>
</div>
Using:
return Db::getInstance()->getRow($sql);
only retrieve the first row of the result, if you would like to return more than one banner you would like to use Db::getInstance()->executeS($sql); to get all results.
Also check your DB table structure and a var_dump() of the involved variables, this would help understanding if there are more issues.

Cakephp 3: How to ignore beforefind for specific queries?

I am working on multilingual posts. I have added beforefind() in the PostsTable so I can list posts for current language
public function beforeFind(Event $event, Query $query) {
$query->where(['Posts.locale' => I18n::locale()]);
}
In order to allow users duplicate posts in different languages i wrote following function:
public function duplicate(){
$this->autoRender = false;
$post_id= $this->request->data['post_id'];
$post = $this->Posts
->findById($post_id)
->select(['website_id', 'category_id', 'locale', 'title', 'slug', 'body', 'image', 'thumb', 'meta_title', 'meta_description', 'other_meta_tags', 'status'])
->first()
->toArray();
foreach($this->request->data['site'] as $site) {
if($site['name'] == false) {
continue;
}
$data = array_merge($post, [
'website_id' => $site['website_id'],
'locale' => $site['locale'],
'status' => 'Draft',
'duplicate' => true
]);
$pageData = $this->Posts->newEntity($data);
if($this->Posts->save($pageData)) {
$this->Flash->success(__('Post have been created.'));;
} else{
$this->Flash->error(__('Post is not created.'));
}
}
return $this->redirect(['action' => 'edit', $post_id]);
}
In order to check if the posts are already duplicated. I am doing a check in 'edit' functino:
$languages = TableRegistry::get('Websites')->find('languages');
foreach($languages as $language)
{
$exists[] = $this->Posts
->findByTitleAndWebsiteId($post['title'], $language['website_id'])
->select(['locale', 'title', 'website_id'])
->first();
}
$this->set('exists',$exists);
but as the beforefind() is appending query to above query. I am not getting any results. Is there any way I can ignore beforefind() for only cerrtain queries. I tried using entity as below:
public function beforeFind(Event $event, Query $query) {
if(isset($entity->duplicate)) {
return true;
}
$query->where(['Posts.locale' => I18n::locale()]);
}
but no luck. Could anyone guide me? Thanks for reading.
There are various possible ways to handle this, one would be to make use of Query::applyOptions() to set an option that you can check in your callback
$query->applyOptions(['injectLocale' => false])
public function beforeFind(Event $event, Query $query, ArrayObject $options)
{
if(!isset($options['injectLocale']) || $options['injectLocale'] !== false) {
$query->where(['Posts.locale' => I18n::locale()]);
}
}
Warning: The $options argument is currently passed as an array, while it should be an instance of ArrayObject (#5621)
Callback methods can be ignored using this:
$this->Model->find('all', array(
'conditions' => array(...),
'order' => array(...),
'callbacks' => false
));

passing value from Yii CController class to CForm (Form Builder) config array

I'm new to Yii, and I'm trying to do my initial project the "right" way. I've created a CFormModel class that needs three fields to query for some data, a CForm config to construct the form, and a CController to tie it together (all given below).
The data request needs an account, and this can come from a couple of different places. I think retrieving it should be in the controller. However, I don't know how to get it into the form's hidden "account" field from the controller, so that it makes it to the arguments assigned to the CFormModel after submission. More generally, I know how to pass from CController to view script, but not to CForm. Is the registry (Yii::app()->params[]) my best bet?
I suppose I can just leave it out of the form (and required fields) and wait to populate it in the submit action (actionSummaries). Does that break the intention of CForm? Is there a best practice? Even taking this solution, can someone address the first issue, in case it comes up again?
Any other, gentle critique is welcome.
models/SummariesForm.php
class SummariesForm extends CFormModel
{
public $account;
public $userToken;
public $year;
public function rules () {...}
public function fetchSummary () {...}
static public function getYearOptions () {...}
}
views/account/select.php
<?php
$this->pageTitle=Yii::app()->name;
?>
<div class="form">
<?php echo $form->render(); ?>
</div>
controllers/AccountController.php
class AccountController extends CController
{
public $layout = 'extranet';
public function actionSelect ()
{
$model = new SummariesForm();
// retrieve account
require_once 'AccountCookie.php';
/*
*
* Here, I insert the account directly into the
* model used to build the form, but $model isn't
* available to selectForm.php. So, it doesn't
* become part of the form, and this $model doesn't
* persist to actionSummaries().
*
*/
$model->account = AccountCookie::decrypt();
if ($model->account === false) {
throw new Exception('Unable to retrieve account.');
}
$form = new CForm('application.views.account.selectForm', $model);
$this->render('select', array(
'form' => $form,
'account' => $model->account,
));
}
public function actionSummaries ()
{
$model = new SummariesForm();
if (isset($_POST['SummariesForm'])) {
$model->attributes = $_POST['SummariesForm'];
/*
*
* Should I just omit "account" from the form altogether
* and fetch it here? Does that break the "model"?
*
*/
if ($model->validate() === true) {
try {
$summaries = $model->fetchSummary();
} catch (Exception $e) {
...
CApplication::end();
}
if (count($summaries) === 0) {
$this->render('nodata');
CApplication::end();
}
$this->render('summaries', array('model' => $model, 'summaries' => $summaries));
} else {
throw new Exception('Invalid year.');
}
}
}
}
views/account/selectForm.php
<?php
return array(
'title' => 'Select year',
'action' => Yii::app()->createUrl('Account/Summaries'),
'method' => 'post',
'elements' => array(
'account' => array(
'type' => 'hidden',
'value' => $account,
),
'userToken' => array(
'type' => 'hidden',
'value' => /* get token */,
),
'year' => array(
'type' => 'dropdownlist',
'items' => SummariesForm::getYearOptions(),
),
),
'buttons' => array(
'view' => array(
'type' => 'submit',
'label' => 'View summaries',
),
),
);
The answer is NO to do what you asked. You can see $form variable which acted almost like array when it was passed from controller to view. The solution is you add more property $account into selectForm model and treat it like other elements. I don't think leaving the new field outside the form will be properly way if you want to submit its value also.
Edited: