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;
}
Related
I have a Sample model that has a status (string) and a current task (foreign key to the Task model).
field type
---------------------------
id int
status string -> I use an Enum to store possible values
current_task_id int -> foreign key to the Task model
On my model, I define the relationship as follows:
public function currentTask()
{
return $this->belongsTo(Task::class, 'current_task_id', 'id');
}
Now, I've created an Observer with the following function:
public function updated(Sample $sample)
{
// check if the current task is null and if not change the status to in progress
Log::info('Sample status changed to in progress', ['sample' => $sample->toArray()]);
if ($sample->currentTask()->exists()) {
$sample->status = 'in progress';
$sample->save();
}
}
I want this to trigger when a sample is updated, check if there is an associated Task, and change the status to in progress if so.
I've encountered two issues:
When updating the current_task_id field manually and running save(), I get a memory leak caused somehow by the observer code.
When running the "associate" method to assign the currentTask, the observer does not trigger.
See the code below that I run in Tinkerwell
$sample = Sample::factory()->create();
echo $sample->currentTask(); // null
echo $sample->status; // not started
$sample->current_task_id = 2;
$sample->save(); // memory leak, additionally, if I check $sample->currentTask it gives me null...
Or with associate:
$sample = Sample::factory()->create();
echo $sample->currentTask(); // null
echo $sample->status; // not started
$sample->currentTask()->associate(2); // does not trigger observer
echo $sample->currentTask(); // Task object
echo $sample->status; // not started
How can I trigger the observer on associate? Or alternatively, why would the save() cause a memory leak?
Here's my recommendation:
Keep using an observer but use the saving (or updating) method:
public function saving(Sample $sample)
{
// check if the current task changed
Log::info('Sample status changed to in progress', ['sample' => $sample->toArray()]);
if ($sample->isDirty('current_task_id') && CurentTask::where('id', $sample->current_task_id)->exists()) {
$sample->status = 'in progress';
}
}
If you don't use the isDirty check in a saving or updating event you will end up with an infinite loop of saving, triggering updated and saving again
I'm using sales_order_shipment_save_after observer to collect tracking numbers. I have tried $event->getOrder but it will not load any order object. I suppose it's the shipment observer I use as opposed to order observer. Usually, getId or getIncrementId on Order would ok. Right now I was able to get tracking number and shipment ID just fine. Is there a way to get order ID from shipment ID in Magento?
Here is what I got
$shipment = $event->getShipment();
$tracks = $shipment->getAllTracks();
foreach ($tracks as $track) {
$orderTracking = $track->getTrackNumber();
}
need to try below code
$shipment = $observer->getEvent()->getShipment();
$order = $shipment->getOrder();
$shippingMethod = $order->getShippingMethod();
I am try to get order details form shipment object
Your function , should like this
public function you_function_name(Varien_Event_Observer $observer)
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 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.
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/