sales_order_place_after not working magento 2 - events

I am trying to listen to this event sales_order_place_after in magento 2 , but after place order click nothings happen, (the same observer work when listning to another event like login).
Any idea for what's going on ?
Thanxs.

You can do this by using the Observer in your module app\code\Vendorname\modulename\etc\frontend\events.xml -
<event name="checkout_onepage_controller_success_action">
<observer name="mymodule_controller_success_action" instance="Vendorname\modulename\Observer\MyObserver" />
</event>
and in app\code\Vendorname\modulename\MyObserver.php file add code -
<?php
namespace Vendorname\mudulename\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\Request\DataPersistorInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Captcha\Observer\CaptchaStringResolver;
class MyObserver implements ObserverInterface
{
public function execute(\Magento\Framework\Event\Observer $observer)
{
$order = $observer->getEvent()->getOrder();
echo $orderId = $order->getId();
$comment = $this->getRequest()->getParam('comment');
print_r("Catched event succssfully !"); exit;
echo "Do your Work Here";
}
}

Related

Accessing product attributes from within a class definition inside view.phtml

I'm adding a small function to the code for our view.phtml to check if the product in question has certain atributes and then build a list from them.
At the top of my file I have
<?php $_helper = $this->helper('catalog/output');?>
<?php $_product = $this->getProduct(); ?>
and elsewhere in my code I quite happily and without issue make use of such calls as:
<?php $_product->getColor();?>
All fine and dandy so far.
Later I declare a class AttributeList and within it's constructor I try to access values of $_product
class AttributeList{ // AttributeList CLASS DEFINITION
public $attributes = array();
public $count;
function __construct(){ //CONSTRUCTOR FOR AttributeList CLASS
$this->itemCount = 0;
if($_product->getColor()){
//DO SOME THINGS
}
}//CONSTRUCTOR ENDS
}// AttributeList CLASS ENDS
This causes my page not to load. If i change the conditions of the if statement to something arbitraraly true like "0 < 1" the code executes perfectly, so I presume the issue is that $_product is not visible from within my class definition.
Can someone explain why this is the case, and how i'm supposed to access the properties of my product from within my class definition?
Which stupidly obvious facet of magento or php am I overlooking here?
It's a very bad practice to put a class inside a view but to answer your question, use Mage::registry('current_product') inside your class:
<?php
class AttributeList {
public $attributes = array();
public $count;
public $product;
function __construct()
{
$this->itemCount = 0;
$this->product = Mage::registry('current_product');
if($this->_product->getColor()){
}
}
}

Disable full page caching for specific block

I'm working with magento EE that has full page caching feature. There is a block that is updated dynamically, but I can't seem to disable its caching.
What I want to achieve ideally: disable caching only for particular block so it would be rendered again each time the page loads.
Things I tried:
Include unsetData to layout file
<action method="unsetData"><key>cache_lifetime</key></action>
<action method="unsetData"><key>cache_tags</key></action>
Set function _saveCache to return false
protected function _saveCache($data, $id, $tags = array(), $lifetime = null) {
return false;
}
Set different values for cache_lifetime
public function __construct()
{
$this->addData(array(
‘cache_lifetime’ => 0,
‘cache_tags’ => array(Mage_Catalog_Model_Product::CACHE_TAG),
));
}
Perhaps I'm missing something in full page caching mechanics?
Well, I found a couple of good posts and implement my caching with etc/cache.xml, that wraps my block with container object.
My cache.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<placeholders>
<namespace_block_unique_node>
<block>module/block_class</block>
<name>name_of_block_in_my_layout</name>
<template>path/to/my/template</template>
<placeholder>UNIQUE_PLACEHOLDER_HERE</placeholder>
<container>Namespace_Module_Model_Caching_Container_BlockName</container>
<cache_lifetime>86400</cache_lifetime>
</namespace_block_unique_node>
</placeholders>
</config>
I used here as block the block that should not be cached, as name name of block in my layout, and as container I've choose my container.
Code for container:
<?php
class Namespace_Module_Model_Caching_Container_BlockName extends Enterprise_PageCache_Model_Container_Abstract
{
protected function _getCacheId()
{
return 'NAMESPACE_MODULE_BLOCKNAME' . $this->_getIdentifier();
}
protected function _getIdentifier()
{
return microtime();
}
protected function _renderBlock()
{
$blockClass = $this->_placeholder->getAttribute('block');
$template = $this->_placeholder->getAttribute('template');
$block = new $blockClass;
$block->setTemplate($template);
$layout = Mage::app()->getLayout();
$block->setLayout($layout);
return $block->toHtml();
}
protected function _saveCache($data, $id, $tags = array(), $lifetime = null) { return false;}
}
Here I putmicrotime() function to identify block, but inside my module I used cookie variables related to my module. I believe that saves redundant reloading of a block when nothing was really changed.
The thing that I didn't found in other tutorials is that I had to create layout variable and assign it to my block, otherwise I was getting only my block instead of whole page.
Here is the solution for disabling FPC for a specific controller (could be extended to specific action as well).
First create an Observer to listen on the controller_action_predispatch event:
public function processPreDispatch(Varien_Event_Observer $observer)
{
$action = $observer->getEvent()->getControllerAction();
// Check to see if $action is a Product controller
if ($action instanceof Mage_Catalog_ProductController)
{
$request = $action->getRequest();
$cache = Mage::app()->getCacheInstance();
// Tell Magento to 'ban' the use of FPC for this request
$cache->banUse('full_page');
}
}
Then add the following to your config.xml file for the module. This goes in the section:
<events>
<controller_action_predispatch>
<observers>
<YOUR_UNIQUE_IDENTIFIER>
<class>YOURMODULE/observer</class>
<method>processPreDispatch</method>
</YOUR_UNIQUE_IDENTIFIER>
</observers>
</controller_action_predispatch>
</events>
Now Magento will serve up your page every time and bypass FPC for the request.
And You can also refer: http://mikebywaters.wordpress.com/2011/12/14/disable-magento-full-page-cache-on-a-per-controller-basis/
cache_lifetime must be set to null to disable cache for this block
public function __construct()
{
$this->addData(array(
‘cache_lifetime’ => null,
));
}

capture Order completion status in observer in magento

Hi I want to catpture the order information when the oder is completed or close.I try different events like (sales_order_place_after) but didn't complete my requirements.I am completing orders form admin side and i create observer for capturing the information like
Xml :
<events>
<sales_order_place_after>
<observers>
<extra_options>
<class>My_Module_Model_Observer</class>
<method>salesConvertQuoteItemToOrderItem</method>
</extra_options>
</observers>
</sales_order_place_after>
</events>
Observer :
public function salesConvertQuoteItemToOrderItem($observer)
{
$order = $observer->getOrder();
$orders = $observer->getEvent()->getOrder();
if($order->getState() == Mage_Sales_Model_Order::STATE_COMPLETE){
echo "<pre>";
print_r($orders);exit;
}
}
Can anyone help ? Thanks in advance
You are doing everything right except you are listening to wrong event. You have to use sales_order_save_after instead.
Using sales_order_save_after is still good, but it just requires you also to check for the state (as Mischa suggests):
public function salesOrderSaveAfter($observer)
{
$order = $observer->getEvent()->getOrder();
if($order->getState() != Mage_Sales_Model_Order::STATE_COMPLETE) {
return $this;
}
if($order->getData('state') == $order->getOrigData('state')) {
return $this;
}
// do your stuff
return $this;
}
This works fine for me.

How to create a child block programmatically?

I have a page that has some template block included programmatically as follows:
public function indexAction() {
$this->loadLayout();
$block = $this->getLayout()
->createBlock('core/template')
->setTemplate('somefolder/sometemplate.phtml');
$this->getLayout()->getBlock('content')->append($block);
$this->renderLayout();
}
I would like to put inside the sometemplate.phtml, $this->getChildHtml('somechild') to insert another block.
I tried
$box = $this->getLayout()
->createBlock('page/html')
->setTemplate('somefolder/somechild.phtml');
$block->append($box);
But it didn't work. How can I do it?
I solved the problem by using setChild method as follows:
$block->setChild('somealias',$childBlock);
And so I can use
<?php echo $this->getChildHtml('somealias'); ?>
To add up to Ricardo Martins's answer
If you need it in a block directly you can do what product price does
Mage_Catalog_Block_Product:
public function getPriceHtml($product)
{
$this->setTemplate('catalog/product/price.phtml');
$this->setProduct($product);
return $this->toHtml();
}

Magento Payment Redirect Order

Is there any functionality in magento payment extention to stop the creation of an order before the success status from payment gateway is returned?
The Extension is designed as a payment redirect (with getOrderPlaceRedirectUrl) but really in the correct controller action, I do post from the action with params, to the gateway and return success if all OK, and return failure if not.
But the order is already created so I must cancel this order, but it should not create this order in the first place.
Maybe if I can design it as a gateway, I can use some payment method to do this?
I thought about the validate or prepareSave methods, but both of them are called twice - on accept payment method and on place order.
Also I thought about events - maybe I can use some event to do this post action and on failture just throw exception?
But I really think that in the payment methods, there has to be some standard functionality that I can use.
This is quite a common issue during Payment Module development.
Magento offers two hooks for payment method classes to provide redirect URL's, one before the order is created, one after.
If a payment method model implements getOrderPlaceRedirectUrl() the customer will be redirected after the confirmation step of the one page checkout, the order entity will be created.
If a payment method model implements the getCheckoutRedirectUrl() method, the customer will be redirected after the payment step of the one page checkout, and no order entity is created.
This is not ideal, but thats what Magento offers out of the box.
How about extending the _validate() method on Mage_Sales_Model_Service_Quote, and throw an error there so that it never gets to the "$transaction->save();" bit.
public function submitOrder()
{
$this->_deleteNominalItems();
// do some check here
$this->_validate();
// End checks
$quote = $this->_quote;
$isVirtual = $quote->isVirtual();
........
try {
$transaction->save();
$this->_inactivateQuote();
Mage::dispatchEvent('sales_model_service_quote_submit_success', array('order'=>$order, 'quote'=>$quote));
} catch (Exception $e) {
...........
}
...........
return $order;
}
Validate function looks like this:
protected function _validate()
{
$helper = Mage::helper('sales');
if (!$this->getQuote()->isVirtual()) {
$address = $this->getQuote()->getShippingAddress();
$addressValidation = $address->validate();
if ($addressValidation !== true) {
Mage::throwException(
$helper->__('Please check shipping address information. %s', implode(' ', $addressValidation))
);
}
$method= $address->getShippingMethod();
$rate = $address->getShippingRateByCode($method);
if (!$this->getQuote()->isVirtual() && (!$method || !$rate)) {
Mage::throwException($helper->__('Please specify a shipping method.'));
}
}
$addressValidation = $this->getQuote()->getBillingAddress()->validate();
if ($addressValidation !== true) {
Mage::throwException(
$helper->__('Please check billing address information. %s', implode(' ', $addressValidation))
);
}
if (!($this->getQuote()->getPayment()->getMethod())) {
Mage::throwException($helper->__('Please select a valid payment method.'));
}
return $this;
}
The extended function can look like this:
public function __construct(Mage_Sales_Model_Quote $quote)
{
$this->_quote = $quote;
parent::__construct($quote);
}
protected function _validate()
{
// Code to test comes here
Mage::throwException(Mage::helper('payment')->__('unsuccessfull.....'));
// Code ends, now call parent
return parent::_validate();
}
As I said - giving sample that I used for this solution at final.
I prefered to observe event to do post request. Really if you'll use method presented here
you will take the same effect, but I prefer to use event observer. So:
First add some data to config.xml to create event observer in frontend section
<events>
<sales_model_service_quote_submit_before>
<observers>
<lacpaycs>
<type>singleton</type>
<class>OS_LacPayCS_Model_Observer</class>
<method>lacpaycs_payment_send</method>
</lacpaycs>
</observers>
</sales_model_service_quote_submit_before>
</events>
then we must create Observer class in OS/LacPayCS/Mode/Observer.php:
class OS_LacPayCS_Model_Observer {
protected $_code = 'lacpaycs';
// Here some our additional functions
/**
* #param Varien_Object $observer
*/
public function lacpaycs_payment_send(Varien_Object $observer)
{
/**
* #var Mage_Sales_Model_Order $order
* #var Mage_Sales_Model_Quote $quote
*/
$order = $observer->getOrder();
$quote = $observer->getQuote();
$payment = $order->getPayment();
if ($payment->getMethodInstance()->getCode() != $this->_code) {
return;
}
$helper = Mage::helper('lacpaycs');
try {
// Here we prepare data and sending request to gateway, and getting response
if (!$this->_validateResponse($response)) {
Mage::throwException('Error '.$this->errorMsg);
}
} catch (Exception $e) {
Mage::throwException($e->getMessage());
}
}
}
So in two words what we doing here $_code is the same that in our payment model and with it we checking in observer if we catched event when customer using our payment method
All another code is simple, so I think it's no need to comment it

Resources