Magento Event Check Order State When Changed - php

Hope all is fine for you :)
Today, I'm programming on Magento. As you can see in the title, I would like to catch an event when the state of an order has changed (Pending payment, processing, Complete).
And, do something if order is in state "Processing" or "Pending payment" or "Complete".
I used "sales_order_save_after" in my config.xml for my event, and in my class, I done this:
<?php
class Test_Model_Observer extends Mage_Core_Model_Abstract
{
/**
* Magento passes a Varien_Event_Observer object as
* the first parameter of dispatched events.
*/
public function logOrderUpdated(Varien_Event_Observer $observer)
{
// if state = pending payment, do:
// if state = processing, do:
// if state = complete, do:
Mage::log(
"State:",
null,
'order-state.log');
}
}
The event works, but I don't know how to know the state of the order...
Can you help me please ?
Thank you so much!

public function getStatus(Varien_Event_Observer $observer)
{
$status = $observer->getEvent()->getOrder()->getStatus();
$state = $observer->getEvent()->getOrder()->getState();
}

Related

Observer Cancel order Magento

Hi I'm trying to add functionality when I'm canceling a order in Magento.
my config is working and when I'm cancelling a order my function gets triggered but i don't get the order dispatched to the observer.
Here are the initial code of my class.
class Imo_Model_Observer {
static function exportOrder($observer)
{
$order= $observer->getData('entity_id');
self::createFile($order, 'completed');
//echo "export started";
}
In this case i have tryed to get entity_id from the order I'm canceling but with no luck.
i would like to get the whole order.
Cancelling a order means actually that order state is set to "cancelled" so you need to observe the event sales_order_save_after and get the order object from event, check which was the previous state and set your own state
Here is what i ended up with
public function exportOrder(Varien_Event_Observer $observer)
{
$track = $observer->getEvent()->getPayment();
$increment_id = $track->getOrder();
In Magento 2.3 there is the event order_cancel_after, which is dispatched after the cancellation took place.
The cancel method in Magento\Sales\Model\Order looks like this:
public function cancel()
{
if ($this->canCancel()) {
$this->getPayment()->cancel();
$this->registerCancellation();
$this->_eventManager->dispatch('order_cancel_after', ['order' => $this]);
}
return $this;
}

Magento Event Not Found

I have working on magento 1.6.1.0 version. I have not found any event to call after shipping generate or after order status completed.
Then i call our module observer when order status is completed.
After order status complete, i want to update a customer attribute value.
please give me answer of this problem.
I have search and do various things but they are not useful.
The first place to start would be the sales_order_save_after event. This certainly will work, but will be called any time the order is updated and saved. Therefore the logic must consider when the order is newly created & complete straightaway, or when the order is marked as complete later on (the latter being the most common). You may need to adjust logic and acceptable end-state values for orders based on cancellations, multiple orders, etc.
/**
* Update customer attribute when order is completed.
*
* Need to catch two conditions:
* 1) Order is new AND `status` = complete
* 2) Order exists but `status` is changed to complete
*
* #param $obs Varien_Event_Observer
*/
public function adjustCustomerAfterComplete($obs)
{
/* #var $order Mage_Sales_Model_Order */
$order = $obs->getOrder();
if ($order->getStatus() === $order::STATE_COMPLETE
&& $order->getOrigData('status' !== $order::STATE_COMPLETE))
{
Mage::getModel('customer/customer')
->load($order->getCustomerId())
->setCustomAttr('new val') //custom attr code
->save();
//Another approach if you don't need events, etc.:
/*
$obj = new Varien_Object(
array(
'entity_id'=>$order->getCustomerId(),
'custom_attr'=>'new val'
)
);
Mage::getResourceModel('customer/customer')
->saveAttribute($obj,'custom_attr');
*/
}
}

Can Observer break the Event in Magento?

I am new to Magento. I want to build an observer which on cancellation of an order will perform a query to my database and will decide whether the order is cancellable or not (This is decided on the basis of a certain state.). If it can't be cancelled, then it should break the cancel event and display a message that the order cannot be cancelled.
Which event I should choose, order_cancel_after or sales_order_item_cancel, and how can I break out of this event in between?
Thanks in advance. :)
There is no general answer to this, it depends on the context where the event is triggered and what happens there afterwards.
The events don't have an interface to "stop" them and they are not tied to the actual "event" (i.e. order cancellation) other than by name.
So you will have to look at the code of Mage_Sales_Model_Order_Item where sales_order_item_cancel gets triggered (order_cancel_after is obviously the wrong place to look because at that point the order is already cancelled):
/**
* Cancel order item
*
* #return Mage_Sales_Model_Order_Item
*/
public function cancel()
{
if ($this->getStatusId() !== self::STATUS_CANCELED) {
Mage::dispatchEvent('sales_order_item_cancel', array('item'=>$this));
$this->setQtyCanceled($this->getQtyToCancel());
$this->setTaxCanceled($this->getTaxCanceled() + $this->getBaseTaxAmount() * $this->getQtyCanceled() / $this->getQtyOrdered());
$this->setHiddenTaxCanceled($this->getHiddenTaxCanceled() + $this->getHiddenTaxAmount() * $this->getQtyCanceled() / $this->getQtyOrdered());
}
return $this;
}
You see that there is no additional check after the event was dispatched, but it would be possible to set the qty_to_cancel attributes to 0 to uneffect the cancelling.
Your observer method:
public function salesOrderItemCancel(Varien_Event_Observer $observer)
{
$item = $observer->getEvent()->getItem();
if (!$this->_isCancellable($item->getOrder())) {
$item->setQtyToCancel(0);
$this->_showErrorMessage();
}
}
Note that you don't have to set tax_canceled or hidden_tax_canceled because they depend on qty_canceled and thus will stay 0.

How to create shipping automatically in Magento

I need to change Magento default workflow. So, I should automatically create shipping as soon as customers buy something.(when customers see Receipt page). I am not sure where should I start. I started googling for some extension, but no luck for now. That's why I came here. Does anyone have an idea where can I start resolving this problem? Thanks!
You should never put this kind of code in view files. Besides it being bad practice in general, as #user2729065 mentioned: if the customer does not return to the thank you page after the payment, the code will not be run.
Better is to create a custom module with an observer. To do this, add the following code to your module etc/config.xml file:
<global>
<events>
<sales_order_invoice_pay>
<observers>
<[my]_[module]_automatically_complete_order>
<class>[module]/observer</class>
<method>automaticallyShipCompleteOrder</method>
</[my]_[module]_automatically_complete_order>
</observers>
</sales_order_invoice_pay>
</events>
</global>
Change my_module to your module name. This will triger when an invoice is paid.
Then create the Observer in My/Module/Model/Observer.php
<?php
class My_Module_Model_Observer
{
/**
* Mage::dispatchEvent($this->_eventPrefix.'_save_after', $this->_getEventData());
* protected $_eventPrefix = 'sales_order';
* protected $_eventObject = 'order';
* event: sales_order_invoice_pay
*/
public function automaticallyShipCompleteOrder($observer)
{
$order = $observer->getEvent()->getInvoice()->getOrder();
if ($order->getState() == Mage_Sales_Model_Order::STATE_PROCESSING) {
try {
$shipment = $order->prepareShipment();
$shipment->register();
$order->setIsInProcess(true);
$order->addStatusHistoryComment('Shippment automatically created.', false);
Mage::getModel('core/resource_transaction')
->addObject($shipment)
->addObject($shipment->getOrder())
->save();
} catch (Exception $e) {
$order->addStatusHistoryComment('Could not automaticly create shipment. Exception message: '.$e->getMessage(), false);
$order->save();
}
}
return $this;
}
}
This will check if the order is still in Processing ( the state it gets after it is paid for.). And if so, try to create the shipment. After the shipment is created, the order will automatically change its state to completed.
If you want the shipment to get created directly after the order is placed (before the invoice is created and paid for.), change
<sales_order_invoice_pay>
in
<sales_order_place_after>
in config.xml. And because this observer returns an order and not an invoice, also change:
$order = $observer->getEvent()->getInvoice()->getOrder();
to
$order = $observer->getEvent()->getOrder();
Code is based on an example from Inchoo so most credits go to them.
I found a solution. I guess this is not the best way to do it, but it works.
In file your_theme_name/template/checkout/success.phtml
add this code
<?php
$orderId = Mage::getSingleton('checkout/session')->getLastRealOrderId();
$order = Mage::getModel('sales/order') -> loadByIncrementId($orderId);
if ($order -> canShip()) {
$itemQty = $order -> getItemsCollection() -> count();
$shipment = Mage::getModel('sales/service_order', $order) -> prepareShipment($itemQty);
$shipment = new Mage_Sales_Model_Order_Shipment_Api();
$shipmentId = $shipment -> create($orderId);
}
?>
That will add shipping for the order on receipt page.
To put code in a template is a really bad idea: it adds the Shipping code to your Template / View. This functionality doesn't belong there. (For instance: if the payment is confirmed after 5 minutes it doesn't work).
Solution is to write an Observer to the Payment-Success event:
http://inchoo.net/ecommerce/magento/magento-orders/automatically-invoice-ship-complete-order-in-magento/

Magento - Reassign catalog rules after modifying product attributes

I'm in the process of developing an extension for Magento 1.5.1.0, which allows me to add catalog price rules to products which quantity in stock is reduced to zero. I have added an attribute to my attribute-set called auto_discount_active. This attribute is my on/off switch which works as condition for my price rule.
I wrote an Observer that reacts on the events sales_order_place_after and catalog_product_save_before. It's task is to check wether to stock quantity of the current product has been changed and set my custom attribute to on or off.
The method which handles the catalog_product_save_before event works fine. After saving an article in the backend, the price rule becomes (in)active like it should. The code looks like following:
class Company_AutoDiscount_Model_Observer
{
public function updateAutoDiscount($observer)
{
/**
* #var Varien_Event
*/
$event = $observer->getEvent();
$product = $event->getProduct();
$data = $product->getStockData();
$discount = $data['qty'] < 1 ? true : false;
$attributes = $product->getAttributes();
$attribute = $attributes["auto_discount_active"];
if ($product->getAutoDiscountAllowed())
{
$product->setAutoDiscountActive($discount);
}
return $this;
}
}
Now I want to do the same thing, if someone places an order in my shop. That for I use the event sales_order_place_after which works so far. But after changing the custom attributes value, the price rules are not updated. My observer method looks like this:
public function updateAutoDiscountAfterOrder($observer)
{
/**
* #var Varien_Event
*/
$event = $observer->getEvent();
$order = $event->getOrder();
foreach ($order->getItemsCollection() as $item)
{
$productId = $item->getProductId();
$productIds[] = $productId;
$product = Mage::getModel('catalog/product')->setStoreId($order->getStoreId())->load($productId);
$data = $product->getStockData();
$discount = $data['qty'] < 1 ? true : false;
if ($product->getAutoDiscountAllowed())
{
$product->setAutoDiscountActive($discount);
$product->save();
}
Mage::getModel('catalogrule/rule')->applyAllRulesToProduct($productId);
}
return $this;
}
After placing an order and saving the bought article manually in the backend without changes, the price rule gets updated. But I have get the update working in my observer method.
What do I have to do to get the catalog price rule being assigned, after changing the custom attribute?
Thx in advance!
Okay, I want to advise you on some fairly major code optimisations.
You can reduce your collection size and remove the conditional logic inside your loop by using:
$order->getItemsCollection()->addFieldToFilter('is_in_stock', 0);
You could also update all the attributes with a much faster method than save(), by using:
Mage::getSingleton('catalog/product_action')
->updateAttributes($order->getItemsCollection()->addFieldToFilter('is_in_stock', 0)->getAllIds(), array('auto_discount_active' => 1), 0);
Also, bear in mind, you'll also need to apply your observer to any product stock level modification, ie. product save, import, credit memo (refund) - so its a fairly expansive area. You would probably be better served rewriting the stock class, as there isn't too many events dispatched that will give you enough scope to cover this.
Finally, to perform the assignation of rules, I would suggest extending the resource model for the rule (Mage/CatalogRule/Model/Mysql4/Rule.php) so that you can pass in your array of product ids (to save it iterating through the entire catalogue).
You could simply extend getRuleProductIds() to take a Mage::registry variable (if set) with your product ids from the collection above. Then after running the code above, you could just execute
Mage::getModel('catalogrule/rule')->load(myruleid)->save();
Which will re-index and apply rules to new products as necessary - for only the products that have changed.
I would imagine this method cutting overheads by an extremely significant amount.

Categories