How to get the custom order attributes in default order Api response in magento 2.3 - magento

I have created a new custom order attribute named delivery_date and shown the same in sales order grid but i am not getting the custom attribute in my order Api response.
The error I am getting is Fatal error: Uncaught Error: Call to undefined method Magento\Sales\Api\Data\OrderExtension::setTipAndTrickAttribute()
Please help.
app/code/Amos/CustomOrder/etc/di.xml
<?xml version="1.0"?>
<!--
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
<virtualType name="Magento\Sales\Model\ResourceModel\Order\Grid" type="Magento\Sales\Model\ResourceModel\Grid">
<arguments>
<argument name="columns" xsi:type="array">
<item name="delivery_date" xsi:type="string">sales_order.delivery_date</item>
<item name="no_of_days" xsi:type="string">sales_order.no_of_days</item>
<item name="no_of_crew" xsi:type="string">sales_order.no_of_crew</item>
</argument>
</arguments>
</virtualType>
</config>
app/code/Amos/CustomOrder/etc/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_load_after">
<observer name="sales_order_load_delivery_date" instance="Magestore\TipAndTrick\Observer\Sales\OrderLoadAfter" />
</event>
</config>
Amos/CustomOrder/etc/extension_attributes.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
<extension_attributes for="Magento\Sales\Api\Data\OrderInterface">
<attribute code="delivery_date" type="string" />
</extension_attributes>
</config>
Amos/CustomOrder/Observer/Sales/OrderLoadAfter.php
<?php
namespace Amos\CustomOrder\Observer\Sales;
use Magento\Framework\Event\ObserverInterface;
class OrderLoadAfter implements ObserverInterface
{
public function execute(\Magento\Framework\Event\Observer $observer)
{
$order = $observer->getOrder();
$extensionAttributes = $order->getExtensionAttributes();
if ($extensionAttributes === null) {
$extensionAttributes = $this->getOrderExtensionDependency();
}
$attr = $order->getData('delivery_date');
$extensionAttributes->setTipAndTrickAttribute($attr);
$order->setExtensionAttributes($extensionAttributes);
}
private function getOrderExtensionDependency()
{
$orderExtension = \Magento\Framework\App\ObjectManager::getInstance()->get(
'\Magento\Sales\Api\Data\OrderExtension'
);
return $orderExtension;
}
}

To answer your question about the error you're using the wrong magic function. Your magic functions for that attribute is setDeliveryDate().
You also need to make sure your events.xml has the right class for the observer.
<observer name="sales_order_load_delivery_date" instance="Magestore\TipAndTrick\Observer\Sales\OrderLoadAfter" />
While your observer class is: Amos\CustomOrder\Observer\Sales\OrderLoadAfter
When you are using example material try not to forget to change the class, namespace and functions names among other things when you need to. You may also need an order repository plugin to actually get it into the API response.
<type name="Magento\Sales\Api\OrderRepositoryInterface">
<plugin name="your_name_here_extension_attribute"
type="<Vendor>\<Module>\Plugin\OrderRepositoryPlugin" />
</type>

Yes agree with above answer, you will need to write order repository plugin with get and getlist methods to get it into the API response.
Below are the code snippet
public function afterGet(OrderRepositoryInterface $subject, OrderInterface $order)
{
$this->addDeliveryDate($order);
return $order;
}
public function afterGetList(OrderRepositoryInterface $subject, OrderSearchResultInterface $searchResult)
{
$orders = $searchResult->getItems();
foreach ($orders as $order) {
$this->addDeliveryDate($order);
}
return $searchResult;
}
private function addDeliveryDate($order)
{
$adddeliveryDate = $order->getData(self::DELIVERY_DATE);
$extensionAttributes = $order->getExtensionAttributes() ?: $this->extensionFactory->create();
$extensionAttributes->setDeliveryDate($adddeliveryDate);
$order->setExtensionAttributes($extensionAttributes);
return $order;
}

Related

Magento 2 use custom block in extended template

I want to use a block in order to get some data in a template, but it's not working.
Here is my block
class Question extends \Magento\Framework\View\Element\AbstractBlock
{
protected $customerSession;
public function __construct(
Template\Context $context,
\Magento\Customer\Model\Session $customerSession
)
{
$this->customerSession = $customerSession;
parent::__construct($context);
}
public function test()
{
return "OK";
//return $this->customerSession->getCustomer()->getId();
}
}
And this is my catalog_product_view.xml
<?xml version="1.0"?>
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="product.info.details">
<block class="Magento\Catalog\Block\Product\View" name="question.tab" as="question" template="Semaine2_TP::product/delivery_info.phtml" group="detailed_info" >
<arguments>
<argument translate="true" name="title" xsi:type="string">Questions</argument>
</arguments>
<block name="question" class="Semaine2\TP\Block\Question" cacheable="false" template="Semaine2_TP::question/info.phtml" group="detailed_info"/>
</block>
</referenceBlock>
</body>
</page>
But with this, only the delivery_info.phtml is printed, and the info.phtml seems to be ignored.
Actually what I would like to be able to do is to use my test function from the block inside my delivery_info.phtml in order to get an action target URL for example or to get the customer if he is logged in.
But when I call $block in my phtml he always seems to search into the Magento\Catalog\Block\Product\View which is normal I guess.
New to magento 2 and no idea how to deal with this. Thanks for your assistance.
The right way is to use Magento View Models instead of Block classes to separate business logic
https://devdocs.magento.com/guides/v2.3/extension-dev-guide/view-models.html
catalog_product_view.xml:
<referenceBlock name="product.info.details">
<block name="question.tab" as="question" template="Semaine2_TP::product/delivery_info.phtml" group="detailed_info" >
<arguments>
<argument translate="true" name="title" xsi:type="string">Questions</argument>
</arguments>
<block name="question" cacheable="false" template="Semaine2_TP::question/info.phtml" group="detailed_info">
<arguments>
<argument name="view_model" xsi:type="object">Semaine2\TP\ViewModel\Question</argument>
</arguments>
</block>
</block>
</referenceBlock>
app/code/Semaine2/TP/ViewModel/Question.php:
<?php
namespace Semaine2\TP\ViewModel;
use Magento\Framework\Registry;
use Magento\Catalog\Model\Product;
use Magento\Framework\View\Element\Block\ArgumentInterface;
/**
* Class Question.
*/
class Question implements ArgumentInterface
{
/**
* #var Registry
*/
private $registry;
/**
* #var Product
*/
private $product;
/**
* #param Registry $registry
*/
public function __construct(
Registry $registry
) {
$this->registry = $registry;
}
/**
* Get current product.
*
* #return Product
*/
public function getProduct(): Product
{
if ($this->product === null) {
$this->product = $this->registry->registry('current_product');
}
return $this->product;
}
}
Are you calling $block->getChildHtml() in your delivery_info.phtml file?
Since you have a custom block and template, I think you need to explicitly call a toHtml for your block. You can also pass in your custom block name to the function, if not I believe all child block HTMLs will be printed.
I was extending the wrong Block.
The block need to extends use Magento\Catalog\Block\Product\View;
Sadly this magento native block is using deprecated arguments, but I think we can't escape from this if we want to be able to call the construct.

Magento 2 - Observer on event 'sales_order_place_after' not working

I am working on a magento 2 observer (without success), to execute a cURL request to a system with the orderid after a order is placed.
Currently I just send an email, but that's for testing purpose only
Working on a Plesk server with a fresh Magento 2.3.2 install (no sample data) and added 1 product. So, fresh webshop with 1 product in total.
Currently I have the following code:
/app/code/CompanyName/ModuleName/etc/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_place_after">
<observer name="companyname__modulename_observer_afterplaceorder" instance="CompanyName\ModuleName\AfterPlaceOrder" />
</event>
<config>
/app/code/CompanyName/ModuleName/AfterPlaceOrder.php
<?php
namespace CompanyName\ModuleName\Observer;
use Magento\Framework\Event\ObserverInterface;
use Psr\Log\LoggerInterface;
class AfterPlaceOrder implements ObserverInterface {
protected $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function execute(\Magento\Framework\Event\Observer $observer) {
Mage::log("Start execute module");
$headers = array();
$headers[] = "MIME-Version: 1.0";
$headers[] = "Content-type: text/html";
$headers[] = "From: Test SYSTEM";
$headers[] = "X-Mailer: PHP/".phpversion();
mail('testemail#companyname.com', 'Test message', "Order placed", implode("\r\n", $headers));
Mage::log("End of email");
}
}
I've also tried other events like:
- checkout_onepage_controller_success_action
- sales_order_place_after
- sales_order_place_before
- sales_order_save_after
Logs don't seem to work, mail doesn't send and tried die() but nothing works.
It's probably that the event is never fired, but I just can't figure out why.
Can you guys see the error?
P.S. What do you use to debug? Is there a better way then logging?
P.S. I'd also like to now if a observer is the best way for this. Any suggestions?
Thx in advance!
Your /app/code/CompanyName/ModuleName/etc/events.xml is missing the observer folder also the close of the config tag. You could use the event:
checkout_onepage_controller_success_action
<?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="checkout_onepage_controller_success_action">
<observer name="companyname__modulename_observer_afterplaceorder" instance="CompanyName\ModuleName\Observer\AfterPlaceOrder"/>
</event>
</config>
To get the orderid just use:
$orderId = $observer->getEvent()->getOrderIds();

Migrating Shipping Extension for Magento 1.9 to Magento 2.2

I am trying to migrate a custom magento 1.9 extension to magento 2.2. I have done a lot of searching and can't find information on the use case I'm trying to migrate. I originally followed this tutorial for the 1.9 extension. I understand there is a tool to help port extensions, but I am trying to do this manually as I couldn't get that tool to function for me.
The custom shipping extension would run each time the shopping cart was updated to calculate a custom shipping rate. The goal is to recreate this extension in magento 2.2 such that each time the shopping cart is opened or updated it will run and calculate a shipping cost which will then propagate through the checkout process.
Below is an overview of the magento 1.9 extension. Any advice on how to translate this to magento 2.2?
/app/etc/modules/Extensions_Shipper.xml
<?xml version="1.0"?>
<config>
<modules>
<Extensions_Shipper>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Shipping />
</depends>
</Extensions_Shipper>
</modules>
/app/code/local/Extensions/Shipper/etc/config.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<Extensions_Shipper>
<module>0.0.1</module>
</Extensions_Shipper>
</modules>
<global>
<models>
<extensions_shipper>
<class>Extensions_Shipper_Model</class>
</extensions_shipper>
</models>
</global>
<default>
<carriers>
<extensions_shipper>
<active>1</active>
<model>extensions_shipper/carrier</model>
<title>Shipping Options</title>
<sort_order>10</sort_order>
<sallowspecific>0</sallowspecific>
</extensions_shipper>
</carriers>
</default>
/app/code/local/Extensions/Shipper/Model/Carrier.php
<?php
class Extensions_Shipper_Model_Carrier extends Mage_Shipping_Model_Carrier_Abstract implements Mage_Shipping_Model_Carrier_Interface
{
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
//Are there magento 2.2 equivalence for the following?
$addressInfo = Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress()->getData();
$result = Mage::getModel('shipping/rate_result');
$items = Mage::getSingleton('checkout/session')->getQuote()->getAllItems();
$currentItem = Mage::getModel('catalog/product')->load($items[$itemsArray[$i]]->getProduct()->getId());
Mage::getSingleton('core/session')->addNotice('some text');
//$result = some calculations for shipping rate
return $result;
}
public function getAllowedMethods()
{
return array();
}
}
You can create an event observer on the checkout_cart_add_product_complete event to execute the logic to update the shipping costs.
namespace MyCompany\MyModule\Observer;
use Magento\Framework\Event\ObserverInterface;
class MyObserver implements ObserverInterface
{
public function __construct()
{
//Observer initialization code...
//You can use dependency injection to get any class this observer may need.
}
public function execute(\Magento\Framework\Event\Observer $observer)
{
//Observer execution code...
}
}
Subscribe to the event in 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="my_module_event_before">
<observer name="myObserverName" instance="MyCompany\MyModule\Observer\MyObserver" />
</event>
<event name="my_module_event_after">
<observer name="myObserverName" instance="MyCompany\MyModule\Observer\AnotherObserver" />
</event>
</config>
See Magento docs on events and observers: http://devdocs.magento.com/guides/v2.0/extension-dev-guide/events-and-observers.html
For a list of all Magento 2.2 events, see: https://cyrillschumacher.com/magento-2.2-list-of-all-dispatched-events/

Magento 2 Override by preference not working

Everything seems right but my overriding is not working
Trying to override a Model from
vendor/magento/module-catalog-url-rewrite/Model/ProductUrlPathGenerator.php
Path for di.xml app/code/Rltsquare/Customrewrite/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator" type="Rltsquare\Customrewrite\Model\CatalogUrlRewrite\ProductUrlPathGenerator" />
</config>
Path for Model file after overriding
app/code/Rltsquare/Customrewrite/Model/CatalogUrlRewrite/ProductUrlPathGenerator.php
<?php
/**
* Copyright © 2016 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Rltsquare\Customrewrite\Model\CatalogUrlRewrite;
use Magento\Store\Model\Store;
class ProductUrlPathGenerator extends \Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator
{
protected function prepareProductUrlKey(\Magento\Catalog\Model\Product $product)
{
$urlKey = $product->getUrlKey();
return 'products/'.$product->formatUrlKey($urlKey === '' || $urlKey === null ? $product->getName() : $urlKey);
}
}
Do i have to compile or run any other command after this type of overriding (preference)

Magento 2 Add to wish list return to the product detail page

Currently in Magento 2 after add the product to wish list it move to the wish list page. I am trying to move it back to the product detail page. So for it i try to override the Magento\Wishlist\Controller\Index\Add with the di preference
<preference for="Magento\Wishlist\Controller\Index\Add"
type="Eguana\CustomWishlist\Controller\Rewrite\Index\Add" />
And for it my controller is like this
namespace Eguana\CustomWishlist\Controller\Rewrite\Index;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Framework\App\Action;
use Magento\Framework\Data\Form\FormKey\Validator;
use Magento\Framework\Exception\NotFoundException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Controller\ResultFactory;
/**
* #SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class Add extends \Magento\Wishlist\Controller\Index\Add
{
public function __construct(Action\Context $context, \Magento\Customer\Model\Session $customerSession, \Magento\Wishlist\Controller\WishlistProviderInterface $wishlistProvider, ProductRepositoryInterface $productRepository, Validator $formKeyValidator)
{
parent::__construct($context, $customerSession, $wishlistProvider, $productRepository, $formKeyValidator);
}
/**
* Adding new item
*
* #return \Magento\Framework\Controller\Result\Redirect
* #throws NotFoundException
* #SuppressWarnings(PHPMD.CyclomaticComplexity)
* #SuppressWarnings(PHPMD.NPathComplexity)
* #SuppressWarnings(PHPMD.UnusedLocalVariable)
*/
public function execute()
{
echo 'abc';
}
}
My module.xml file is like this
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Eguana_CustomWishlist" setup_version="2.1.3">
<sequence>
<module name="Magento_Wishlist" />
</sequence>
</module>
</config>
But it is still calling the Magento Wishlist module controller. Can you please let me know is there any issue in my overriding process? Thank you very much.
In Magento2 Magento\Wishlist\Controller\Index\Add is overriden by another core module MultipleWishlist module Magento\MultipleWishlist\Controller\Index\Add so if you want to override the wishlist add controller then you should override the MultipleWishlist add controller.
I hope it will work for you and will save your time.
Thanks Abbas
In your module di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
<preference for="Magento\MultipleWishlist\Controller\Index\Add" type="Vendor\Module\Controller\MultipleWishlist\Add" />
<preference for="Magento\Wishlist\Controller\Index\Add" type="Vendor\Module\Controller\Wishlist\Add" />
</config>
Note : In override controller of MultipleWhislist
namespace Vendor\Module\Controller\MultipleWishlist;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Action;
use Magento\Framework\Controller\ResultFactory;
use Magento\Framework\Data\Form\FormKey\Validator;
use Magento\MultipleWishlist\Model\WishlistEditor;
use Magento\Wishlist\Controller\WishlistProviderInterface;
class Add extends \Vendor\Module\Controller\Wishlist\Add
{
It's working fine.

Resources