1

I need to add my custom detail in cart along with product detail and transfer these details in order too. I want to use additional option functionality for this.

1 Answer 1

1
  1. For AddtoCart add events.xml file in app/code/[VendorName]/CustomModule/etc/frontend folder
<event name="checkout_cart_product_add_after">
    <observer name="customprice" instance="[VendorName]\CustomModule\Observer\CustomPrice" />
</event>
  1. Create CustomPrice.php file on [VendorName]\CustomModule\Observer folder

<?php
namespace [VendorName]\CustomModule\Observer;

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

class CustomPrice implements ObserverInterface
{
    /**
     *
     * @var type \Magento\CatalogRule\Model\Rule 
     */
    protected $rule;
    /**
     * 
     * @param RequestInterface $request
     * @param \Magento\CatalogRule\Model\Rule $rule
     */
    public function __construct(
        \Magento\Framework\App\RequestInterface $request,
        \Magento\CatalogRule\Model\Rule $rule,
        Json $serializer = null
    )
    {
        $this->rule = $rule;
        $this->_request = $request;
        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
    }
    
    /**
     * 
     * @param \Magento\Framework\Event\Observer $observer
     */
    public function execute(\Magento\Framework\Event\Observer $observer) {
        $optionsSize = $this->_request->getPost('options-size')?$this->_request->getPost('options-size'):'';
        $optionsFinish = $this->_request->getPost('options-finish')?$this->_request->getPost('options-finish'):'';
        $optionsCminch = $this->_request->getPost('options-finish')?$this->_request->getPost('cminch'):'in';
        $customizationDetails = $this->_request->getPost('customization_details')?$this->_request->getPost('customization_details'):'';
        
        /* Default option */
        $item = $observer->getEvent()->getData('quote_item');         
        $item = ( $item->getParentItem() ? $item->getParentItem() : $item );
        $product = $item->getProduct();

        $candidates['value'] = 0.00;
        $candidates['order_quantity'] = 0;

        if($product->getTypeId() != 'giftvoucher'){
            $finishOption = array(
                'label' => 'Finish',
                'value' => 'Natural',
            );
            $sizeOption = array(
                'label' => 'Size',
                'value' => $product->getDefaultHeight().' W X '.$product->getDefaultWidth().' H inch',
            );
            $productId = $product->getId();

            if($optionsSize || $optionsFinish)
            {
                $customPrice = $item->getProduct()->getFinalPrice();
                $productId = $this->_request->getPost('product');
                if($optionsSize)
                {
                    $customSize = explode(':',$optionsSize);
                    $unitPrice = $product->getUnitPrice();
                    $fixedPrice = $product->getFixedPrice();
                    $customPrice = ceil(($unitPrice*$customSize[0]*$customSize[1]/10000)+$fixedPrice);
                    if($optionsCminch=='cm')
                    {
                    $sizeOption = array(
                             'label' => 'Size',
                             'value' => $customSize[0].' W X '.$customSize[1].' H cm',
                        );
                    }else{
                        $sizeOption = array(
                             'label' => 'Size',
                             'value' => round($customSize[0]*0.393701).' W X '.round($customSize[1]*0.393701).' H inch',
                        );
                    }
                    //$itemsOptions[] = $sizeOption;
                    $weight = round(($customSize[0] * $customSize[1] / 10000) * 18);
                    $weight = ceil(2.20462 * $weight);
                    $item->setWeight($weight);
                }
                if($optionsFinish){
                    $customFinish = json_decode(trim($optionsFinish), true);
                    $customPrice = $customPrice + ceil($customPrice*$customFinish['price']/100);
                    $finishOption = array(
                             'label' => 'Finish',
                             'value' => $customFinish['title'],
                        );
                    //$itemsOptions[] = $finishOption;
                }
                if($customizationDetails){
                    $customizationArray = array(
                             'label' => 'Details',
                             'value' => $customizationDetails,
                        );
                    $itemsOptions['Details'] = $customizationArray;
                }
                //$item->getCustomTierPrice($customPrice);
                $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); // Instance of Object Manager
                $priceHelper = $objectManager->create('Magento\Framework\Pricing\Helper\Data'); // Instance of Pricing Helper
                $customPrice = $priceHelper->currency($customPrice, false, false);
            
                $customCalculatedPrice = round($this->rule->calcProductPriceRule($product,$customPrice));
                if($customCalculatedPrice){
                    $customPrice = $customCalculatedPrice;   
                }

                //$customPrice = round($customPrice);

                $item->setCustomPrice($customPrice);
                $item->setOriginalCustomPrice($customPrice);
                
            }
            $itemsOptions['finishOption'] = $finishOption;
            $itemsOptions['sizeOption'] = $sizeOption;

            $itemAllOptions = [];

            foreach ($itemsOptions as $itemsOption) {
                $itemAllOptions[] = $itemsOption;
            }

            $item->addOption(
                array(
                    'product' => $productId,
                    'code' => 'additional_options',
                    'value' => $this->serializer->serialize($itemAllOptions)
                )
            );
            $item->getProduct()->setIsSuperMode(true);

            $currencysymbol = $objectManager->get('Magento\Store\Model\StoreManagerInterface');
            $currency = $currencysymbol->getStore()->getCurrentCurrencyCode();

            $catalogSession = $objectManager->get('\Magento\Catalog\Model\Session');

            $candidates['value'] = $customPrice * $item->getProduct()->getQty();
            $candidates['product_id'] = $productId;
            $candidates['order_quantity'] = $item->getProduct()->getQty();
            $candidates['currency'] = $currency;
            $catalogSession->setPrestAddToCart($candidates);

            $logger->info(print_r($candidates, true)); 
        }/* end product type condition */
    }
}

  1. For after submit quote and order place. Create events.xml file in app/code/[VendorName]/CustomModule/etc folder
<event name="sales_model_service_quote_submit_before">
    <observer name="ordercustomoption" instance="[VendorName]\CustomModule\Observer\OrderCustomOption" />
</event>

  1. Create OrderCustomOption.php file on [VendorName]\CustomModule\Observer folder
<?php
namespace [VendorName]\CustomModule\Observer;

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

class OrderCustomOption implements ObserverInterface
{
    public function __construct(
    Json $serializer = null
    ) {
        $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        try {
            $quote = $observer->getQuote();
            $order = $observer->getOrder();
            $quoteItems = [];
 
            // Map Quote Item with Quote Item Id
            foreach ($quote->getAllVisibleItems() as $quoteItem) {
                $quoteItems[$quoteItem->getId()] = $quoteItem;
            }
 
            foreach ($order->getAllVisibleItems() as $orderItem) {
                $quoteItemId = $orderItem->getQuoteItemId();
                $quoteItem = $quoteItems[$quoteItemId];
                $additionalOptions = $quoteItem->getOptionByCode('additional_options');

                if(isset($additionalOptions)){
                    // 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);
                }
            }
        } catch (\Exception $e) {
            echo $e->getMessage();
        }
    }

    
    private function getQuoteItemById($id)
    {
        if(empty($this->quoteItems))
        {
            /* @var  \Magento\Quote\Model\Quote\Item $item */
            foreach($this->quote->getItems() as $item)
            {
                //filter out config/bundle etc product
                if(!$item->getParentItemId() && $item->getProductType() == \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
                {
                    $this->quoteItems[$item->getId()] = $item;
                }
            }
        }
        if(array_key_exists($id, $this->quoteItems))
        {
            return $this->quoteItems[$id];
        }
        return null;
    }
}

1
  • Worked for me, pretty much a plug and play solution (don't try to put the events.xml in the frontend dir - it needs to be global. One minor note, the method getQuoteItemById doesn't seem to be called, should it be removed?
    – Dan Norris
    Aug 30, 2022 at 14:30

Your Answer

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

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