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.
Related
I have two models, Show and Episode, with a one to many relationship. I have an Observer for each model to watch when they are deleted and do some tasks. If my ShowObserver looks like this everything works properly and cascades down, the EpisodeObserver fires its deleting() method for each Episode that is deleted along with the show:
<?php
/**
* Listen to the Show deleting event.
*
* #param Show $show
* #return void
*/
public function deleting(Show $show)
{
if ($show->isForceDeleting()) {
foreach ($show->episodes()->onlyTrashed()->get() as $episode) {
$episode->forceDelete();
}
} else {
$show->episodes()->delete();
}
}
However, if I change it to looks like this the EpisodeObserver#deleting() methods never fire even though the Episodes do get forceDeleted:
<?php
/**
* Listen to the Show deleting event.
*
* #param Show $show
* #return void
*/
public function deleting(Show $show)
{
if ($show->isForceDeleting()) {
$show->episodes()->onlyTrashed()->forceDelete();
} else {
$show->episodes()->delete();
}
}
Is there something about $show->episodes()->onlyTrashed()->forceDelete(); that is incorrect, or is this potentially a bug?
Check out the documentation (on the red warning block): https://laravel.com/docs/5.3/eloquent#deleting-models
When executing a mass delete statement via Eloquent, the deleting and deleted model events will not be fired for the deleted models. This is because the models are never actually retrieved when executing the delete statement.
This is also same to update call.
So if you need to fire the events, you have no choice but to delete it one by one, or fire your own custom event if performance is critical.
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;
}
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();
}
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');
*/
}
}
I need to save some cms pages and delete others in a single transaction.
So, how to I make this:
$page1->save();
$page2->delete();
A single transaction? For reference, both $page1 and $page2 come from Mage::getModel('cms/page'). Also, I found an excellent answer here that tells me how to do two saves in a transaction, but not how to do both a save and delete. How can it be done?
If you must do this in a single transaction, just call isDeleted(true) on those items which you wish to be deleted:
//Build out previous items, then for each which should be deleted...
$page2->isDeleted(true);
$transaction = Mage::getModel('core/resource_transaction');
$transaction->addObject($page1)
$transaction->addObject($page2)
//$transaction->addObject(...) etc...
$transaction->save();
Thought I should add an explanation (from Mage_Core_Model_Abstract::save() [link]):
/**
* Save object data
*
* #return Mage_Core_Model_Abstract
*/
public function save()
{
/**
* Direct deleted items to delete method
*/
if ($this->isDeleted()) {
return $this->delete();
}
// ...
}