Error 500 upon adding shipping_save_after observer on Magento 2 - magento

upon adding my observer, I got error 500 when I'm trying to complete shipping process. What I want to achieve is, I want to send a review request after the shipment is done.I've started using Magento for about a month ago, that's why I don't know if I made an error on Observer, events.xml or it just doesn't work. I've been doing this for about three days, please help.
Vendor name: Lns
Module Name: ReviewRequest
Review.php
<?php
namespace Lns\ReviewRequest\Observer;
use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
class Review implements ObserverInterface
{
protected $transportBuilder;
protected $storeManager;
protected $logger;
public function __construct(
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
TransportBuilder $transportBuilder,
StoreManagerInterface $storeManager,
LoggerInterface $logger
) {
$this->transportBuilder = $transportBuilder;
$this->storeManager = $storeManager;
$this->logger = $logger;
}
/**
* Below is the method that will fire whenever the event runs!
*
* #param Observer $observer
*/
public function execute(Observer $observer)
{
$store = $this->storeManager->getStore();
$templateParams = ['store' => $store, 'customer' => $customer, 'administrator_name' => $receiverInfo['name']];
$transport = $this->transportBuilder
->setTemplateIdentifier('Entrelabel Add Review')
->setTemplateOptions(['area' => 'frontend', 'store' => $store->getId()])
->addTo($receiverInfo['email'], $receiverInfo['name'])
->setTemplateVars($templateParams)
->setFrom('general')
->getTransport();
try {
// Send an email
$transport->sendMessage();
} catch (\Exception $e) {
// Write a log message whenever get errors
$this->logger->critical($e->getMessage());
}
return var_dump($e);
}
}
Events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_order_shipment_save_after">
<observer name="reviewRequest" instance="Lns\ReviewRequest\Observer\Review" />
</event>
</config>

add before class start
use Magento\Framework\Mail\Template\TransportBuilder
use Magento\Store\Model\StoreManagerInterface
and check log files in var folder

Related

how to send notification from admin to user by id with Laravel Pusher

I have successfully implemented pusher on my laravel app but I want to make, when the user succeeds in making an order the default status_message for the order is pending, the case is when the admin changes the status_message to processed, the user who has ordered gets a notification that the order he has made is processed.
this is my code but this code sends notifications to all users.
Controller
if ($data->status_message == 'processed') {
event(new OrderEvent('Hi, Your order is processed!'));
//...
}
My Event OrderEvent.php
public function broadcastOn()
{
return new Channel('notif-channel');
}
/**
* Broadcast order event.
*
* #return void
*/
public function broadcastAs()
{
return 'order-event';
}
in App blade
var channel = pusher.subscribe('notif-channel');
channel.bind('order-event', function(data) {
const obj = JSON.parse(JSON.stringify(data));
const message = obj.message;
blah blah blah
}
Both user and admin should be on the same channel. For example if user is subscribed for channel 'order-channel-SetUserID'.
Admin should send the message to that channel and you should look for it on the front end and make the changes on the DOM.
In your controller when you submit the changes of the status of the order run the event with the channel name
event(new OrderEvent($user_id, 'Hi, Your order is processed!'));
Now your event should look similar to this:
class OrderEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $user_id;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($user_id, $message)
{
$this->user_id = $user_id;
$this->message = $message;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('order-channel.' . $this->user_id);
}
public function broadcastAs()
{
return 'order-event';
}
}
Of course you can change your class Name etc... I'm just giving an idea.
it's important to send the changes on the same channel with this user or else you will make changes to other users that are visiting your website.
EDITED
Here is what else you need to configure.
In app/Providers/EventServiceProvider.php
You need to put the event in protected $listen
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
OrderEvent::class => [
OrderEventListener::class,
],
];
In app/Listeners You should create OrderEventListener.php and set it up as follow:
<?php
namespace App\Listeners;
use App\Events\OrderEvent;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Pusher;
class OrderEventListener
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param \App\Events\OrderEvent $event
* #return void
*/
public function handle(OrderEvent $event)
{
$pusher = new Pusher(env('PUSHER_APP_KEY'),
env('PUSHER_APP_SECRET'), env('PUSHER_APP_ID'), [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true
]);
$pusher->trigger($event->broadcastOn(),
$event->broadcastAs(), $event->data);
}
}
check your Debug Console in pusher dashboard? If you can see the event firing there all you need to do is show the message with javascript. If no event is running then something in your code is missing.

Magento 2 update invoice state through REST API giving error

I am having project in magento enterprise version :2.3.7-p3
I'm trying to update Magento 2 invoice state via Rest API call : {{magento_api_url}}/V1/invoices/ and method is post below are payload for api
{
"entity": {
"entity_id": 8147,
"state": 2
}
}
but I am getting this error :
Fatal error: Uncaught Error: Call to a member function getId() on null in
/var/www/html/vendor/magento/module-sales/Model/ResourceModel/Order/Invoice.php:58
Could some one help me?
As by default megento issue, So we can not make changes in core file, So for this I have make one alternative solution...
I have created one custom invoice interface in my custom module with same API end point : {{magento_api_url}}/V1/invoices/ in webapi.xml file and defined the our custom model with preference in di.xml file and update the invoice state successfully.
Below are the code snippet
Custom Interface
interface InvoiceCustomInterface
{
/**
* save api
* #param \Magento\Sales\Api\Data\InvoiceInterface $entity Invoice interface
* #return \Magento\Sales\Api\Data\InvoiceInterface Invoice interface
*/
public function save($entity);
}
Webapi.xml
<route url="/V1/invoices/" method="POST">
<service class="Vendor\Module_Nmae\Api\InvoiceCustomInterface" method="save"/>
<resources>
<resource ref="Vendor_Module_Nmae::Module_Nmae_invoice" />
</resources>
</route>
di.xml
<preference for="Vendor\Module_Nmae\Api\InvoiceCustomInterface" type="Vendor\Module_Nmae\Model\Api\Invoice"/>
Model file
class Invoice implements InvoiceCustomInterface
{
protected $logger;
/**
* #var InvoiceRepositoryInterface
*/
private $invoiceRepository;
public function __construct(
LoggerInterface $logger,
InvoiceRepositoryInterface $invoiceRepository
)
{
$this->invoiceRepository = $invoiceRepository;
$this->logger = $logger;
}
/**
* #inheritdoc
* #param $entity
*/
public function save($entity)
{
try {
$invoiceRepo = $this->invoiceRepository->get($entity->getEntityId());
$invoiceRepo->setState($entity->getState());
$this->invoiceRepository->save($invoiceRepo);
} catch (\Exception $e) {
$this->logger->info($e->getMessage());
}
return $invoiceRepo;
}
}
So this solution will resolved the issue.

Magento 2 event/observer for create shipment

I'm trying to send an SMS notification to the client after creating a shipment.
In M1 I can do that with this event:
<sales_order_shipment_save_after>
But in Magento 2 there is no event triggering after creating the shipment.
you can use sales_order_shipment_save_after event
for this you need to create etc/events.xml file to define your event
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_order_shipment_save_after">
<observer name="emizentechshipment" instance="Emizentech\MyModule\Observer\ProcessShipment" />
</event>
</config>
than you need to create Observer\ProcessShipment.php file
<?php
namespace Emizentech\MyModule\Observer;
use Magento\Framework\Event\ObserverInterface;
class ProcessShipment implements ObserverInterface
{
/**
*
* #param \Magento\Framework\Event\Observer $observer
* #return $this
*/
public function execute(\Magento\Framework\Event\Observer $observer)
{
$shipment = $observer->getEvent()->getShipment();
$order = $shipment->getOrder();
// your code for sms here
}
}

Include mail functionality in magento custom module

I have my custom module Customer feedback/Inquiry form in which customer can ask Inquiry related to product or they can able to give feedback related to store.In admin side i listed out all the feedbacks in admin grid.
Now I want to integrate the Mail functionality like when I click on particular feedback edit section there will be separate section for mail body where i will enter the reply, click on send button and mail goes to particular customer which mail Id has been already present in that particular edit section.
Here is code for my AdminHtml controller file
<?php
class Foo_Bar_Adminhtml_BazController extends Mage_Adminhtml_Controller_Action
{
public function indexAction()
{
// Let's call our initAction method which will set some basic params for each action
$this->_initAction()
->renderLayout();
}
public function newAction()
{
// We just forward the new action to a blank edit form
$this->_forward('edit');
}
public function editAction()
{
$this->_initAction();
// Get id if available
$id = $this->getRequest()->getParam('id');
$model = Mage::getModel('foo_bar/baz');
if ($id) {
// Load record
$model->load($id);
// Check if record is loaded
if (!$model->getId()) {
Mage::getSingleton('adminhtml/session')->addError($this->__('This baz no longer exists.'));
$this->_redirect('*/*/');
return;
}
}
$this->_title($model->getId() ? $model->getName() : $this->__('New Baz'));
$data = Mage::getSingleton('adminhtml/session')->getBazData(true);
if (!empty($data)) {
$model->setData($data);
}
Mage::register('foo_bar', $model);
$this->_initAction()
->_addBreadcrumb($id ? $this->__('Edit Baz') : $this->__('New Baz'), $id ? $this->__('Edit Baz') : $this->__('New Baz'))
->_addContent($this->getLayout()->createBlock('foo_bar/adminhtml_baz_edit')->setData('action', $this->getUrl('*/*/save')))
->renderLayout();
}
public function saveAction()
{
if ($postData = $this->getRequest()->getPost()) {
$model = Mage::getSingleton('foo_bar/baz');
$model->setData($postData);
try {
$model->save();
Mage::getSingleton('adminhtml/session')->addSuccess($this->__('The baz has been saved.'));
$this->_redirect('*/*/');
return;
}
catch (Mage_Core_Exception $e) {
Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
}
catch (Exception $e) {
Mage::getSingleton('adminhtml/session')->addError($this->__('An error occurred while saving this baz.'));
}
Mage::getSingleton('adminhtml/session')->setBazData($postData);
$this->_redirectReferer();
}
}
public function deleteAction()
{
// check if we know what should be deleted
$itemId = $this->getRequest()->getParam('id');
if ($itemId) {
try {
// init model and delete
/** #var $model Magentostudy_News_Model_Item */
$model = Mage::getModel('foo_bar/baz');
$model->load($itemId);
if (!$model->getId()) {
Mage::throwException(Mage::helper('foo_bar')->__('Unable to find a Baz.'));
}
$model->delete();
// display success message
$this->_getSession()->addSuccess(
Mage::helper('foo_bar')->__('The Baz has been deleted.')
);
} catch (Mage_Core_Exception $e) {
$this->_getSession()->addError($e->getMessage());
} catch (Exception $e) {
$this->_getSession()->addException($e,
Mage::helper('foo_bar')->__('An error occurred while deleting the baz.')
);
}
}
// go to grid
$this->_redirect('*/*/');
}
public function messageAction()
{
$data = Mage::getModel('foo_bar/baz')->load($this->getRequest()->getParam('id'));
echo $data->getContent();
}
/**
* Initialize action
*
* Here, we set the breadcrumbs and the active menu
*
* #return Mage_Adminhtml_Controller_Action
*/
protected function _initAction()
{
$this->loadLayout()
// Make the active menu match the menu config nodes (without 'children' inbetween)
->_setActiveMenu('sales/foo_bar_baz')
->_title($this->__('Sales'))->_title($this->__('Baz'))
->_addBreadcrumb($this->__('Sales'), $this->__('Sales'))
->_addBreadcrumb($this->__('Baz'), $this->__('Baz'));
return $this;
}
/**
* Check currently called action by permissions for current user
*
* #return bool
*/
protected function _isAllowed()
{
return Mage::getSingleton('admin/session')->isAllowed('sales/foo_bar_baz');
}
}
I want some hooks from which i will able to send mail to particular customer.
Here is the image of my admin grid section
The most easiest way is to create a new transactional mail and set the subject to a placeholder and the same for the body.
this is the transactional mail function:
/**
* Send transactional email to recipient
*
* #param int $templateId
* #param string|array $sender sneder informatio, can be declared as part of config path
* #param string $email recipient email
* #param string $name recipient name
* #param array $vars varianles which can be used in template
* #param int|null $storeId
* #return Mage_Core_Model_Email_Template
*/
public function sendTransactional($templateId, $sender, $email, $name, $vars=array(), $storeId=null)
so the first to do is, create a new transactional mail under System->Transactional Mails. Just fill it with some random stuff for now. then
go to where ever you want to send the email and add
Mage::getModel('core/email_template')
->sendTransactional(
{the transactional email id we just created},
$sender,
$recepientEmail,
$recepientName,
array(
'subject' => '{your subject}',
'body' => '{you body}'
)
);
replace {your subject} and {your body} with the corresponding from you input fields.
after doing that go back to your transactional email template and replace our random stuff with that:
enter {{var subject}} in the subject field
and {{var body}} in die content field of the transactional mail
i didn't tried this but it should work.
hope that helps

Why Magento return wrong class in the .phtml file?

I have 3d-party extention that add new tabs while product edit at the backend. Now I want to add one more tab there.
New tab should have "add" button and let user to add new item, In addition It should have the list with added items. First of all, I have looked at extention code. They have added similar tab using
extends Mage_Adminhtml_Block_Widget
implements Varien_Data_Form_Element_Renderer_Interface
So I try to folow their way and add my one. Code below.
$this->addTab('cancellpolicy', array(
'label' => Mage::helper('catalog')->__('Cancellation Policies'),
'content' => $this->_translateHtml($this->getLayout()->createBlock('Apptha_Reservation_Block_Adminhtml_Catalog_Product_Edit_Tab_Cancellationpolicy')->toHtml()),
));
Above I add new tab and then I create new block class below
class Apptha_Reservation_Block_Adminhtml_Catalog_Product_Edit_Tab_Cancellationpolicy
extends Mage_Adminhtml_Block_Widget
implements Varien_Data_Form_Element_Renderer_Interface
{
/**
* Form element instance
*
* #var Varien_Data_Form_Element
*/
protected $_element;
/**
* Customer Groups cache
*
* #var array
*/
protected $_customerGroups;
/**
* Websites cache
*
* #var array
*/
protected $_websites;
public function __construct(){
$this->setTemplate('reservation/product/edit/tab/cancellationpolicy.phtml');
}
public function getProduct(){
return Mage::registry('product');
}
public function render(Varien_Data_Form_Element_Abstract $element){
$this->setElement($element);
return $this->toHtml();
}
protected function _prepareLayout()
{
$this->setChild('add_button',
$this->getLayout()->createBlock('adminhtml/widget_button')
->setData(array(
'label' => Mage::helper('catalog')->__('Add Room Type(s)'),
'onclick' => 'roomtypesControl.addItem()',
'class' => 'add'
)));
return parent::_prepareLayout();
}
/**
* Set form element instance
*
* #param Varien_Data_Form_Element_Abstract $element
* #return Apptha_Reservation_Block_Adminhtml_Catalog_Product_Edit_Tab_Cancellationpolicy
*/
public function setElement(Varien_Data_Form_Element_Abstract $element){
$this->_element = $element;
return $this;
}
/**
* Retrieve form element instance
*
* #return Apptha_Reservation_Block_Adminhtml_Catalog_Product_Edit_Tab_Cancellationpolicy
*/
public function getElement(){
return $this->_element;
}
public function getWebsites()
{
if (!is_null($this->_websites)) {
return $this->_websites;
}
$websites = array();
$websites[0] = array(
'name' => $this->__('All Websites'),
'currency' => Mage::app()->getBaseCurrencyCode()
);
if (Mage::app()->isSingleStoreMode() || $this->getElement()->getEntityAttribute()->isScopeGlobal()) {
return $websites;
}
elseif ($storeId = $this->getProduct()->getStoreId()) {
$website = Mage::app()->getStore($storeId)->getWebsite();
$websites[$website->getId()] = array(
'name' => $website->getName(),
'currency' => $website->getConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE),
);
}
else {
$websites[0] = array(
'name' => $this->__('All Websites'),
'currency' => Mage::app()->getBaseCurrencyCode()
);
foreach (Mage::app()->getWebsites() as $website) {
if (!in_array($website->getId(), $this->getProduct()->getWebsiteIds())) {
continue;
}
$websites[$website->getId()] = array(
'name' => $website->getName(),
'currency' => $website->getConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE),
);
}
}
$this->_websites = $websites;
return $this->_websites;
}
public function getValues(){
return Mage::getModel('reservation/roomtypes')->getCollection()
->addEntityIdFilter($this->getProduct()->getId())
->addStoreIdFilter($this->getProduct()->getStoreId())
->getItems();
}
}
And then add reservation/product/edit/tab/cancellationpolicy.phtml template file. A the beginig of template I get
<?php Mage::log(get_class($this->getElement())); ?>
<?php $_htmlId = $this->getElement()->getHtmlId() ?>
<?php $_htmlClass = $this->getElement()->getClass() ?>
<?php $_storeId = $this->getProduct()->getStoreId() ?>
<?php $_htmlName = $this->getElement()->getName() ?>
<?php $_readonly = $this->getElement()->getReadonly() ?>
<?php $_multiWebsite= 0 && !Mage::app()->isSingleStoreMode() ?>
And here I get error:
Fatal error: Call to a member function getHtmlId() on a non-object in /var/www/vhosts/bluning.com/httpdocs/app/design/adminhtml/default/default/template/reservation/product/edit/tab/cancellationpolicy.phtml on line 10
Mage::log(get_class($this->getElement()));
give me "Mage_Core_Block_Template" but why? As per my code getElement() should return "Apptha_Reservation_Block_Adminhtml_Catalog_Product_Edit_Tab_Cancellationpolicy"
So why Magento return wrong class in the .phtml file?
UPDATE
config.xml has section
<blocks>
<reservation>
<class>Apptha_Reservation_Block</class>
</reservation>
</blocks>
UPDATE2
I have placed Mage::log inside getElement function and after calling. It returns different values:
inside: Apptha_Reservation_Block_Adminhtml_Catalog_Product_Edit_Tab_Cancellationpolicy
outside: Mage_Core_Block_Template
Crazy
The line :
$this->getLayout()->createBlock('Apptha_Reservation_Block_Adminhtml_Catalog_Product_Edit_Tab_Cancellationpolicy')
is totally invalid. You need to respect the magento framework syntax. (it'ns not just a class instantiation)
See my answer here for details on how to access resoruces in magento : Get all invoices in Magento
To get it work you need to call it via :
$this->getLayout()->createBlock('apptha_reservation/adminhtml_catalog_product_edit_tab_cancellationpolicy')
ps: if "apptha_reservation" is your declared block XML tag in your config.xml
Using debugger I have found issue.
$this->getElement()
It return NULL because It hasnt been set properly. It should be set in the observer. Code is below:
public function attachPolicyEditor($observer) {
$form = $observer->getForm();
if ($policies = $form->getElement('apptha_hotel_cancellationpolicy')) {
$policies->setRenderer(
Mage::getSingleton('core/layout')->createBlock('reservation/adminhtml_catalog_product_edit_tab_cancellationpolicy')
);
}
}
attachPolicyEditor is called by adminhtml_catalog_product_edit_prepare_form observer.

Resources