How do order statuses/states work in Magento 1.4.x - magento

As far as I understand Magento have various order statuses under global/sales/order/statuses which can be altered by either copying app/code/core/Mage/Sales/etc/config.xml to local scope or overriding it with your custom module.
There are also global/sales/order/states defined in the same file and as far as I understand states are something like statuses groups. Only states (not statuses) can be set at the order status in magento and statuses are something like states subdivisions. So in administrator interface you can change statuses of a placed order but you can't change state from the order status drop-down (you can change it by either invoicing the client or canceling the order).
As far as I understand you can easily add a new status to your Magento but can't add new state as states are somehow hardcoded with the rest or Magento order processing logic. I really hope that I'm wrong.
Please correct me if I'm wrong in any point as these are just my thoughts and it might be quite far from real Magento 1.4.x flow.

I'm quite sure that 'state' is free data, it can be set to ANY value using the setData option on an order instance. So if you write a custom module that can load an order, set data to one of your new 'states' and test with what ever custom logic you require.
$order = Mage::getModel('sales/order')->load(1);
$order->setData('state','myCustomState');
$order->setData('status','onCustomState');
echo $order->getState()
// Returns myCustomState
its worth bearing in mine that CLOSED/CANCELLED are protected states, so trying to use $order->setState('my_state') will fail on those order, but shouldn't fail on setData so you can overwrite a closed or cancelled order with this method.
if you were to overwrite the order model with a custom one you could add your own logic such as isOnCustomState() and allow the order to be handled in any way just by loading by id.
To add 'custom logic' to your order you could do something copy app\code\core\Mage\Sales\Model\Order.php into your local folder, then you can add functions into that model,
public function isActive(){ if($this->getState() == 'active'){ return true; } else { return false; }
public function isInActive(){ if($this->getState() == 'deactivated'){ return true; } else { return false; }
public function activate(){
if(!$this->isActive()){
$this->setData('state','active');
$this->setData('status','Active Subscription');
// some custom code to start a recuring payment
return $this;
}
}
public function deactiveate(){
if(!$this->isInActive()){
$this->setData('state','deactivated');
$this->sendOrderUpdateEmail(true,'Your subscription has been deactivated.');
// some custom code to stop a recuring payment
return $this;
}
}
now you can load an order and set activate or deactivate on that order to fire your custom code,
$order = Mage::getModel('sales/order')->load(1)->activate();
this code is all untested and just an example of somethings you could try, please don't just dump this code in your model and expect it to work perfectly. in code\core\Mage\Sales\etc\config.xml in the nodes sales/order/states add
<activated translate="label">
<label>Active Subscription</label>
<statuses>
<pending default="1"/>
</statuses>
<visible_on_front/>
</activated>

Magento Order is a finite state machine.
Therefore when you define status it would automatically try to define its state. Altering state directly is not recommended.
When you define status it checks various flags for shipment and invoices and depending in all those it would get the right state. Once order is in approved state however you can easily change status regardless of if there is invoice or any flag etc.

Related

Laravel Observer Updating/Updated

I am not sure how best to do this. I need access to is_dirty() to check if specific fields were changed which needs to be done in the 'Updating' method in the observer. But I only want to act on it if the update is successful.
If there a way within the 'Updating' method to tell it to try to save the changes and then see if it was successful?
If not, what would be the best way to pair Updating and Updated? Would I just save a cache value in Updating specifying if the relevant fields were modified, then pull that cache value in Updated? Or would there be a better way?
You could try something along these lines:
class ModelObserver
{
public function updated(Model $model)
{
/**
* Listening inside 'updated' since we only care about model
* updated which have already happened
*/
if ($model->wasChanged('my-special-field')) {
// Do something...
}
}
}
You can read more about the wasChanged method here.

Magento - catalog_product_save_after: Check if product has been saved

I am currently trying to save a product with attributes that I have built, and it's working fine. I have also set up my code to call the catalog_product_save_after function on my observer, as shown below:
class Package_MyModule_Model_Observer
{
public function catalog_product_save_after($observer)
{
$product = $observer->getProduct();
//Do stuff here
}
}
In this line of code here, is there a way to detect whether the product has already been saved (i.e. no error messages were shown)? Because I need to update some values in the database when the product is saved successfully.
Mostly this gets called after product is saved successfully, but to be sure you can hook into
catalog_product_save_commit_after

magento target rule not applying to a specific product

A simple product is in specific category other products have that rule applied.This is happening on magento enterprise 1.13.0.1 version.
A rule is applicable to that category but when I look in catalogrule_product table then there is no entry for that product. This means no rule applies to that product.
http://www.solvingmagento.com/quick-tip-magento-catalog-price-rules-dont-work/ is the link I refered.
I want to know if for some reason a product has no target rules applied then:
1. Is there no cron job that will handle this and populate catalogrule_product table.
If yes then which cron job does this.
Also when we saved product its expected that catalog_product_save_after event should get fired resulting in Mage_CatalogRule module’s observer method applyAllRulesOnProduct getting executed but still no luck.
When I click via admin apply rule then it works.
I want to know is has magento not provided any cron job/indexer to handle this.
Thanks in Advance.
If you are creating products outside of the magento backend (using php, or soap) you may have to use the following code after you have called the $product->save() method...
public function applyActiveRulesToProduct($productId)
{
try {
$product = Mage::getModel('catalog/product') -> load($productId);
$rules = Mage::getModel('catalogrule/rule')->getCollection()->addFieldToFilter('is_active', 1);
foreach ($rules as $rule) {
$rule->applyAllRulesToProduct($product);
}
return "Applied rules to " . $productId;
} catch (Exception $e) {
return $e->getMessage();
}
}
It is code that i wrote for my own soap api extension. I could not get the rules to apply using applyToProduct(product, websiteIds) but using applyAllRulesToProduct with filters on the rules array seems to do the trick.
FYI, this code is buried inside of the CatalogRule.Rule.php core code as well, but it cannot be called directly using the rule model or product model. Who knows why they did that.

Magento automatic order status - getting list of order_status / state

I am trying to build a Magento module that observes certain events and tries to proceed automatically to a new automatic status/state, based on payment method.
In order to do that, I organized some status on the backoffice based on payment method. For example:
event: sales_order_place_after
Automatic status: pp_1_pending - First status/state where a new placed order will automatically have this status if the payment method is paypal.
event: sales_order_payment_pay
Automatic status: pp_2_payment - Second status/state after an order is payed when the payment method is paypal
event: sales_order_invoice_save_after
Automatic status: pp_3_complete- Third and final status/state after an order is invoiced, ending the transaction.
For this to work I would need to collect all status with the prefix pp_ and after checking which was set on the order, proceed to the next status in order. This way this module would be scalable.
However I can't seem to get the status collection. I am trying:
$statuses = Mage::getModel('sales/order_status')
->getCollection()
->addAttributeToSelect('status')
->addAttributeToSelect('label')
->addFieldToFilter('status',array('like','pp_'));
Hope anyone can help me. Thanks all!
The addAttributeToSelect() function is used for EAV based models.For flat models use addFieildToSelect()
The code should be
$statuses = Mage::getModel('sales/order_status')
->getCollection()
->addFieldToSelect('status')
->addFieldToSelect('label')
->addFieldToFilter('status',array('like'=>'pp_%'));
Have a look at the generated SELECT query if it looks ok.
$collection->getSelect()->__toString();
you have to use the wildcard (%) in your query, because you want the statuses that begin with pp_:
$statuses = Mage::getModel('sales/order_status')
->getCollection()
->addAttributeToSelect('status')
->addAttributeToSelect('label')
->addFieldToFilter('status',array('like','pp_%'));
in case someone is wondering, to get both states and status together, here's a function for you:
private function _allStatusStateCollection($filter) {
$collection = Mage::getModel( 'sales/order_status' )
->getCollection()->joinStates();
if ($filter != '') { return $collection->addFieldToFilter('main_table.status',array('like'=>$filter.'%')); }
return $collection;
}

Add checkbox to Magento checkout?

I've been searching, trying, and failing alot here. What I want is to add a checkbox, on the Shipping page of Onepage checkout, the standard magento checkout.
I want to create a checkbox so that customers can check it if they want their products to be placed on their address without a signature.
I've been messing around with some old "Accept Terms" checkboxes, but with no luck.
I'm hoping that somebody might have had to make the same kind of customization.
What you can do is save the preference in the checkout/session via an observer. First, add the checkbox to the shipping section and give it the property of name=shipping[no_signature]. Then, create a new module and hook into the event controller_action_postdispatch_checkout_onepage_saveShipping and then use this code:
public function controller_action_postdispatch_checkout_onepage_saveShipping($observer)
{
$params = (Mage::app()->getRequest()->getParams()) ? Mage::app()->getRequest()->getParams() : array();
if (isset($params['shipping']['no_signature']) && $params['shipping']['no_signature']) {
Mage::getSingleton('checkout/session')->setNoSignature(true);
} else {
Mage::getSingleton('checkout/session')->setNoSignature(false);
}
return $this;
}
Then, when the order is about to be placed, hook into the event sales_order_place_before you can add a comment to the order like this:
public function sales_order_place_before($observer)
{
$order = $observer->getOrder();
if (Mage::getSingleton('checkout/session')->getNoSignature()) {
$order->setCustomerNote('No signature required.');
} else {
$order->setCustomerNote(null);
}
return $this;
}
When you go to Sales > Orders, you should see a comment on the order regarding if the customer requires a signature or not. This is under the assumption that no other module or custom code is injecting anything into the customer_note field on the order object.

Resources