Reopen a complete/closed order in Magento? - magento

Is there a way to programmatically reopen an order in Magento that has already reached complete or closed status? I have the following code which works for changing the status of an order, but I can't get it to work for complete or closed orders.
// connect to magento
require_once('app/Mage.php');
umask(022);
Mage::app();
// check admin credentials
Mage::getSingleton('core/session', array('name' => 'adminhtml'));
$admin = Mage::getSingleton('admin/session');
if ( $admin->isLoggedIn() ) {
// update order status
$orderIncrementId = "100000001";
$order = Mage::getModel('sales/order')->loadByIncrementId($orderIncrementId);
$order->setState(Mage_Sales_Model_Order::STATE_PROCESSING, true)->save();
}
I got the current code here. On that page it says that it was tested with Magento 1.3.2.4, but I'm using Magento 1.6.x. Maybe that's the issue?
Let me know if I need to provide more detail, and thanks for any help you can offer.

I don't think that you're having a Magento version issue here.
Under specific circumstances Magento simply just does not allow to switch the state of an order back to Mage_Sales_Model_Order::STATE_PROCESSING.
For example, usually you cannot save a Mage_Sales_Model_Order::STATE_PROCESSING state to any order, which already has had refunds (creditmemos). Neither in 1.3.2.4, nor in 1.6.x.
This is by-design.
Look at Mage_Sales_Model_Order::_checkState() to see under which circumstances Magento forces resetting the order state to STATE_COMPLETE or STATE_CLOSED, respectively.
protected function _checkState()
{
if (!$this->getId()) {
return $this;
}
$userNotification = $this->hasCustomerNoteNotify() ? $this->getCustomerNoteNotify() : null;
if (!$this->isCanceled()
&& !$this->canUnhold()
&& !$this->canInvoice()
&& !$this->canShip()) {
if (0 == $this->getBaseGrandTotal() || $this->canCreditmemo()) {
if ($this->getState() !== self::STATE_COMPLETE) {
$this->_setState(self::STATE_COMPLETE, true, '', $userNotification);
}
}
/**
* Order can be closed just in case when we have refunded amount.
* In case of "0" grand total order checking ForcedCanCreditmemo flag
*/
elseif (floatval($this->getTotalRefunded()) || (!$this->getTotalRefunded()
&& $this->hasForcedCanCreditmemo())
) {
if ($this->getState() !== self::STATE_CLOSED) {
$this->_setState(self::STATE_CLOSED, true, '', $userNotification);
}
}
}
if ($this->getState() == self::STATE_NEW && $this->getIsInProcess()) {
$this->setState(self::STATE_PROCESSING, true, '', $userNotification);
}
return $this;
}
To answer your question: you could achieve what you're trying to do by overriding the _checkState() method with your own method, which allows to set STATE_PROCESSING.
Be aware though, that this most probably will cause the creation of new state contexts which Magento neither knows nor expects or can handle.
If your changes wreak havoc, don't blame me. You've been warned^^

Related

joomla plugin works correctly without caching and does not work with caching

if caching is turned off then everything works correctly. if you enable caching, the plugin at the beginning works correctly, but after 5 minutes it stops processing the line. normal or progressive caching — it doesn’t matter. when you delete the cache — processing is turned on again, and again after 5 minutes it disappears.
here is the complete plugin code. what could be the reason?
code inserted into the material for example such {robokassa 5}
class plgContentRobokassa extends JPlugin
{
public $cont='';
public function onContentPrepare($context, &$row, &$params, $page = 0)
{
$doc = JFactory::getDocument();
$doc->addStyleSheet(JURI::root(true).'/plugins/content/robokassa/css/robokassa.css');
$this->cont=$context;
}
public function onAfterRender()
{
$is_test='0';
$mrh_pass1='*****';
$mrh_login='******';
$app = JFactory::getApplication();
if ($app->getName() != 'site') {
return true;
}
// Получаем кодовое слово из параметров
$varname = 'robokassa';
//Получаем тело сайта
$html = $app->getBody();
// Если тегов нет
if (strpos($html, $varname) === false)
{
return true;
}
$bodyPos = stripos($html, '<body');
$preContent = '';
if ($bodyPos > -1)
{
$preContent = substr($html, 0, $bodyPos);
$html = substr($html, $bodyPos);
}
//Задаем шаблон поиска
$pattern = '#\{' . $varname . ' ([0-9]+)\}#i';
//Закидываем все найденные шаблоны в массив
if (preg_match_all($pattern, $html, $matches))
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
foreach ($matches[0] as $i => $match)
{
*replace code here*
}
$html=$preContent.$html.$script_alert;
//Запихиваем всё обратно в тело
$app->setBody($html);
}
}
}
The plugin events are invoked in the order they have in the Plugin administration.
Cache is part of the System plugins so when their cache is valid the response is retrieved from Cache, and the plugins which come before it are not executed.
You could be able to solve this by moving your plugin after Cache (or last)
If the plugin is of a different kind, i.e. Content, there is no way to achieve this.
You can change it into a System plugin (all events from any plugin category is available also in the System plugins).
Another alternative, you could put your code in a module, prevent caching in the module; but this will not work with page cache.
Finally, and I don't know why I didn't write it first, make an Ajax call to a page which you will NOT cache (by excluding it in the page cache plugin configuration: that way the page will be cached and each time it will retrieve the current data.

How to prevent additional page requests after response sent

I have configured a listener on kernel.request which sets a new response with redirect when the session time has reached a certain value. The listener works fine and redirects to a certain page, on the next request, after the session has ended. But my problem is on the page I have many links and if I press multiple times the same link, the initial request with the redirect is cancelled/stopped and a new request is made with the last link pressed and so it passes my redirect even though the session has ended and is destroyed. So, my question is how to prevent additional requests/link presses after the firs request is made?
Here is my code:
public function onKernelRequestSession(GetResponseEvent $event)
{
$request = $event->getRequest();
$route = $request->get('_route');
$session = $request->getSession();
if ((false === strpos($route, '_wdt')) && ($route != null)) {
$session->start();
$time = time() - $session->getMetadataBag()->getCreated();
if ($route != 'main_route_for_idle_page') {
if (!$session->get("active") && $route == 'main_route_for_site_pages') {
$session->invalidate();
$session->set("active", "1");
} else {
if ($time >= $this->sessionTime) {
$session->clear();
$session->invalidate();
$event->setResponse(new RedirectResponse($this->router->generate('main_route_for_idle_page')));
}
}
} else {
if ($session->get("activ")) {
$session->clear();
$session->invalidate();
}
}
}
}
Thak you.
Idea #1: Simple incremental counter
Each request sends sequence number as param which is being verified as expected at the server.
Server increments the number and sends it back via response
the new number is used in future requests
Basically, if server expects the SEQUENCE number to be 2 and client sends 1 the request is to be rejected.
Idea #2: Unique hash each time
Similar to the idea above, but uses unique hashes to eliminate predictive nature of incremental sequence.
I resolved the issue using JQuery: when a link was pressed I disabled the other ones and so only one request is made from the page:
var isClicked = false;
$(".menu-link").click(function(e) {
if(!isClicked) {
isClicked = true;
} else {
e.preventDefault();
}
});
Thanks.

Writing Logs from Console Shell

I have been using CakePHP 2.4.4 to build the interactive web part of my app and that is going very well. CakePHP is awesome.
I am now doing some supporting background processes. The Console and Shell seems to be the way to do it as it has access to the Models.
I have written the code and have it working but I am trying to write to the same log that I use for the Models. In the models I have an afterSave function to log all the database changes and I just used the $this->log("$model $logEntry", 'info'); to write to the log.
That doesn't work in the Shell but I thought the CakeLog::write('info', "$model $logEntry"); might work but it doesn't either.
Do I need to initialise the CakeLog to point to the correct log files?
<?php
App::uses('CakeTime', 'Utility');
App::uses('CakeLog', 'Utility');
class ProcessRequestShell extends AppShell {
//Need to access the request and monitor tables
public $uses = array('Request');
private function updateRequest($data){
$model = 'Request';
$result = $this->Request->save($data);
$logEntry = "UPDATE ProcessRequestShell ";
foreach ($data[$model] AS $k => $v){$logEntry .= "$k='$v' ";}
if ($result){
//$this->log("$model $logEntry", 'info');
CakeLog::write('info', "$model $logEntry");
} else {
//$this->log("$model FAILED $logEntry", 'error');
CakeLog::write('error', "$model FAILED $logEntry");
}
return($result);
}
public function main() {
$options = array('conditions' => array('state' => 0, 'next_state' => 1));
$this->Request->recursive = 0;
$requests = $this->Request->find('all', $options);
//See if the apply_changes_on date/time is past
foreach ($requests AS $request){
$this->out("Updating request ".$request['Request']['id'], 1, Shell::NORMAL);
//Update the next_state to "ready"
$request['Request']['state'] = 1;
$request['Request']['next_state'] = 2;
$this->updateRequest($request);
}
}
}
?>
Did you set up a default listener/scope for those log types?
If not, they will not get logged.
// Setup a 'default' cache configuration for use in the application.
Cache::config('default', array('engine' => 'File'));
In your bootstrap.php for example
See http://book.cakephp.org/2.0/en/appendices/2-2-migration-guide.html#log
You need to setup default log stream writing to file, eventually, in app/Config/bootstrap.php.
CakeLog does not auto-configure itself anymore. As a result log files
will not be auto-created anymore if no stream is listening. Make sure
you got at least one default stream set up, if you want to listen to
all types and levels. Usually, you can just set the core FileLog class
to output into app/tmp/logs/:
CakeLog::config('default', array(
'engine' => 'File'
));
See Logging → Writing to logs section of the CookBook 2.x

CI Route Issue Not Getting Variable

I'm having an issue with this route and not sure what my problem is exactly.
My page is located at http://www.kansasoutlawwrestling.com/kowmanager/pmsystem/viewmessage/1 where 1 is the message id.
I set up a route to look like
$route['pmsystem/viewmessage/(:num)'] = 'pmsystem/viewmessage/$1';
and I'm still getting a error message like this
A PHP Error was encountered
Severity: Warning
Message: Missing argument 1 for Pmsystem::viewmessage()
Filename: controllers/pmsystem.php
Line Number: 76
// View A Message
function viewmessage($message_id)
{
//Config Defaults Start
$msgBoxMsgs = array();//msgType = dl, info, warn, note, msg
$cssPageAddons = '';//If you have extra CSS for this view append it here
$jsPageAddons = '<script src='.base_url().'../assets/js/cpanel/personalmessages.js></script><script src='.base_url().'assets/js/mylibs/jwysiwyg/jquery.wysiwyg.js></script>';//If you have extra JS for this view append it here
$metaAddons = '';//Sometimes there is a need for additional Meta Data such in the case of Facebook addon's
$siteTitle = '';//alter only if you need something other than the default for this view.
//Config Defaults Start
//examples of how to use the message box system (css not included).
//$msgBoxMsgs[] = array('msgType' => 'dl', 'theMsg' => 'This is a Blank Message Box...');
/**********************************************************Your Coding Logic Here, Start*/
// Checks to see if a session is active for user and shows corresponding view page
if (!$this->loggedin->chkLoginStatus() === FALSE)
{
if( ! $this->uri->segment(3))
{
redirect('error', 'refresh');
}
}
else
{
redirect('login', 'refresh');
}
$bodyContent = 'viewpm';//which view file
$bodyType = "full";//type of template
/***********************************************************Your Coding Logic Here, End*/
//Double checks if any default variables have been changed, Start.
//If msgBoxMsgs array has anything in it, if so displays it in view, else does nothing.
if(count($msgBoxMsgs) !== 0)
{
$msgBoxes = $this->msgboxes->buildMsgBoxesOutput(array('display' => 'show', 'msgs' =>$msgBoxMsgs));
}
else
{
$msgBoxes = array('display' => 'none');
}
if($siteTitle == '')
{
$siteTitle = $this->metatags->SiteTitle(); //reads
}
//Double checks if any default variables have been changed, End.
$this->data['msgBoxes'] = $msgBoxes;
$this->data['cssPageAddons'] = $cssPageAddons;//if there is any additional CSS to add from above Variable this will send it to the view.
$this->data['jsPageAddons'] = $jsPageAddons;//if there is any addictional JS to add from the above variable this will send it to the view.
$this->data['metaAddons'] = $metaAddons;//if there is any addictional meta data to add from the above variable this will send it to the view.
$this->data['pageMetaTags'] = $this->metatags->MetaTags();//defaults can be changed via models/metatags.php
$this->data['siteTitle'] = $siteTitle;//defaults can be changed via models/metatags.php
$this->data['bodyType'] = $bodyType;
$this->data['bodyContent'] = $bodyContent;
$this->data['user_data'] = $this->users->getUserByUserId($this->session->userdata('user_id'));
$this->data['users'] = $this->loggedin->getUserList();
$this->data['personal_messages'] = array($this->pmmodel->getTotalMessages($this->session->userdata('user_id')), $this->pmmodel->getTotalUnreadMessages($this->session->userdata('user_id')), $this->pmmodel->getLast5Messages($this->session->userdata('user_id')));
$this->data['messages'] = array($this->pmmodel->getInboxMessages($this->session->userdata('user_id')), $this->pmmodel->getSentMessages($this->session->userdata('user_id')));
//$this->data['message_data'] = $this->pmmodel->getPmMessage($this->uri->segment(3));
$this->load->view('cpanel/index', $this->data);
}
UPDATE
// Checks to see if a session is active for user and shows corresponding view page
if (!$this->loggedin->chkLoginStatus() === FALSE)
{
if (!is_numeric($this->uri->segment(3)))
{
$this->data['message_data'] = 'Invalid message id!';
}
else
{
$this->data['message_data'] = $this->pmmodel->getPmMessage($this->uri->segment(3));
}
$bodyContent = 'viewpm';//which view file
}
else
{
redirect('login', 'refresh');
}
$bodyType = "full";//type of template
This route is unnecessary - it doesn't change anything.
$route['pmsystem/viewmessage/(:num)'] = 'pmsystem/viewmessage/$1';
You can remove that route. The problem is here:
function viewmessage($message_id) // no default value means it's required
{
// your code
}
Your controller methods literally accept user input as arguments (whatever's in the address bar). You always have to account for those required arguments not being present in CI controller methods.
function viewmessage($message_id = NULL)
{
if ( ! $message_id) show_404();
// your code
}
This will silence the errors and show a 404 if the required $message_id is not there. Additionally, $this->uri->segment(3) is unnecessary because it should have the same value as $message_id.
I highly discourage redirecting to an error page when you really want a 404, but that's up to you. It sure doesn't help the user realize their mistake when the address is lost after the redirect, and you're sending the wrong HTTP headers by doing so.

Pagination in CodeIgniter, need to disable query strings so we can cache

We have a CI installation that has the following setting in our config...
$config['enable_query_strings'] = TRUE;
We need this in order for another area of our application to run correctly with a third party API. What's happening, however, is that pagination is defaulting to a query string method of doing pagination, which doesn't play well with caching.
Right now, they look like this...
http://localhost/something/?&page=6
It's not playing well with caching, mainly because every page URL is the same page to CI. My goal is to get switched over to the below example without messing with global settings for the rest of my application.
I've been trying for hours to find a way to disable the above setting only within this single part of the application, so that we can properly have separate URLs for the pagination, like this...
http://localhost/something/1
http://localhost/something/2
http://localhost/something/3
So far, I have been unable to overide that setting for this controller, and honestly, I'm not sure there's even a way to actually do it. Any help is appreciated. There's got to be some method of disabling a feature for a single controller somehow.
Could you use routing?
$route['something/page/(:num)'] = "something?&page=$1";
edit: to turn off pagination query strings with $config['enable_query_strings'] = TRUE;
system/libraries/Pagination.php
~line 134
change
if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
{
if ($CI->input->get($this->query_string_segment) != 0)
{
$this->cur_page = $CI->input->get($this->query_string_segment);
// Prep the current page - no funny business!
$this->cur_page = (int) $this->cur_page;
}
}
else
{
if ($CI->uri->segment($this->uri_segment) != 0)
{
$this->cur_page = $CI->uri->segment($this->uri_segment);
// Prep the current page - no funny business!
$this->cur_page = (int) $this->cur_page;
}
}
to
if ($CI->uri->segment($this->uri_segment) != 0)
{
$this->cur_page = $CI->uri->segment($this->uri_segment);
// Prep the current page - no funny business!
$this->cur_page = (int) $this->cur_page;
}
~line 196
if ($CI->config->item('enable_query_strings') === TRUE OR $this->page_query_string === TRUE)
{
$this->base_url = rtrim($this->base_url).'&'.$this->query_string_segment.'=';
}
else
{
$this->base_url = rtrim($this->base_url, '/') .'/';
}
to
$this->base_url = rtrim($this->base_url, '/') .'/';
that might do it. Or maybe better form would be to hook into the page...
Simple solution...
$this->config->set_item('enable_query_strings',FALSE);
Just put this before you call your pagination logic in the controller. Thanks go to Taftse in the #codeigniter IRC channel for this simple override.

Resources