6

We are trying to add custom option or custom value in quote item so that we can also get it in order item.

We are able to add custom value in quote using following code but it is get returning value in order item

  $quote = $this->quoteRepository->getActive($cartId);
    foreach ($quote->getAllItems() as $item) {
            $item->setCustomValue(1);
            $item->save();

     }
1
  • Did you ever find a solution to this?
    – jamil
    Jan 17, 2018 at 16:13

2 Answers 2

6

You can achieve by a plugin in Magento 2.2.*

First of all, we need to create an observer file and one Magento event file to implement this functionality.

<?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="catalog_product_load_after">
        <observer name="set_additional_options" instance="CompanyName\ModuleName\Model\SetAdditionalOptions" />
    </event>    
</config>

Once you have created this file, now you need to Create another file and named as: CompanyName\ModuleName/Model/SetAdditionalOptions.php

<?php
namespace CompanyName\ModuleName\Model;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Serialize\Serializer\Json;

class SetAdditionalOptions implements ObserverInterface
{
    protected $_request;    
    public function __construct(RequestInterface $request, Json $serializer = null) 
    {
        $this->_request = $request;
        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
    }

    /**
     * @param \Magento\Framework\Event\Observer $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        // Check and set information according to your need
        $product = $observer->getProduct();                    
        if ($this->_request->getFullActionName() == 'checkout_cart_add') { //checking when product is adding to cart
            $product = $observer->getProduct();
            $additionalOptions = [];
            $additionalOptions[] = array(
                'label' => "Release Date", //Custom option label
                'value' => $product->getReleaseDate(), //Custom option value
            );                        
            $product->addCustomOption('additional_options', $this->serializer->serialize($additionalOptions));
        }
    }

}

Now, We need to create a plugin for the retrieve custom option from cart to order.

First We need to create 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">
    <type name="Magento\Quote\Model\Quote\Item\ToOrderItem">
        <plugin name="unique_name" type="CompanyName\ModuleName\Model\Plugin\Quote\ToOrderItem" sortOrder="1" />
    </type>
</config>

Once you have created this file, now you need to Create another file and named as: CompanyName\ModuleName\Model\Plugin\Quote\ToOrderItem.php

<?php
namespace ZCompanyName\ModuleName\Model\Plugin\Quote;

use Magento\Quote\Model\Quote\Item\ToOrderItem as QuoteToOrderItem;
use Magento\Framework\Serialize\Serializer\Json;
class ToOrderItem
{    
    public function __construct(Json $serializer = null) 
    {        
        $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
            ->get(\Magento\Framework\Serialize\Serializer\Json::class);
    }

    public function aroundConvert(QuoteToOrderItem $subject,
        \Closure $proceed,
        $item,
        $data = []
    ) {
        // Get Order Item
        $orderItem = $proceed($item, $data);               

        $additionalOptions = $item->getOptionByCode('additional_options');        
        // Check if there is any additional options in Quote Item                    
        if (count($additionalOptions) > 0) {
            // Get Order Item's other options
            $options = $orderItem->getProductOptions();
            // Set additional options to Order Item
            $options['additional_options'] = $this->serializer->unserialize($additionalOptions->getValue());
            $orderItem->setProductOptions($options);
        }

        return $orderItem;
    }
}

5
  • I have added the di.xml but after that, I could not able to place an order, is throw me the "An error occurred on the server. Please try to place the order again", kindly check and update the answer
    – senthil
    May 10, 2018 at 11:47
  • Which version are you use? May 11, 2018 at 13:08
  • Thanks for the detailed and under-appreciated answer shah, I needed something similar and slightly modified your code for my use.
    – jamil
    Jul 27, 2018 at 16:29
  • @shahdhairya, this is not working. Can you please help for admin area? Oct 1, 2019 at 7:22
  • Although it works, I definitely think that there are other events, which are triggered less often, that could also do the job, such as checkout_cart_update_item_complete or checkout_cart_product_update_after. Nonetheless, it works, and I'm very happy with your contribution at the moment! :) Dec 5, 2019 at 8:40
0

Shahs Answer is working. For anyone that has the problem that during checkout the error occured "An error occurred on the server. Please try to place the order again" has to refactor the if condition.

The reason that it is breaking in checkout is due to getOptionByCode() not returning a countable/iterable and therefor count() throws an exception. It either returns an option or null and therefor the check has to be if(!is_null($additionalOptions)) and not if(count($additionalOptions) > 0).

Hope I could help somebody with that solution. Cheers for the solution shah

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.