0

I want add surprise functionality so when custom try to place an order, one simple product will get automatically added to their cart. I want to add that item after customer click on place order button. To achieve that, I have used Observer checkout_submit_before and loading the quote id.

Here is my observer code. I have loaded the qupte and added my surprise item to the quote. Issue is, it's adding item in quote_item table but it's not adding item into order. In quote_item table I can see the new SKU for that particular Quote. I'm missing something here. Can anyone please guide me? I also tried to convert Quote Item to Order item using ToOrderItem class but no luck. I tried so many things for so many hours but still at the same point.

<?php

  namespace Jackson\Surprise\Observer;

  use Magento\Quote\Api\CartRepositoryInterface; 
  use Magento\Quote\Model\QuoteFactory;
  use Magento\Quote\Model\Quote\Item\ToOrderItem as ToOrderItemConverter;

class Surprise implements \Magento\Framework\Event\ObserverInterface
{

/**
 * @var CartRepositoryInterface
 */
public $cartRepository;

private $productRepository;
private  $quote;

/**
 * @var ToOrderItemConverter
 */
protected $quoteItemToOrderItem;


public function __construct(
    \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
    CartRepositoryInterface $cartRepository,
    ToOrderItemConverter $quoteItemToOrderItem,
    QuoteFactory $quote
){
    $this->cartRepository = $cartRepository;
    $this->quote = $quote;
    $this->productRepository = $productRepository;
    $this->quoteItemToOrderItem = $quoteItemToOrderItem;
}
/**
 * @param \Magento\Framework\Event\Observer $observer
 * @return $this
 */
public function execute(\Magento\Framework\Event\Observer $observer)
{
    $writer = new \Zend\Log\Writer\Stream(BP . '/var/log/mylogfile.log');
    $logger = new \Zend\Log\Logger();
    $logger->addWriter($writer);

    $logger->info("=========start1============");
    $order = $observer->getEvent()->getQuote();
    $quoteId = $order->getEntityId();
    $logger->info($quoteId);
    if ($quoteId) {
        $logger->info("=========start2============");

        $sku = 'LYLP';
        $product = $this->productRepository->get($sku);
         $cart = $this->quote->create()->loadActive($quoteId);

        $cart->addProduct($product, $this->makeAddRequest($product, $sku, 1));
        $cart->setItemsCount($cart->getItemsCount() + 1);
        $cart->setItemsQty((float)$cart->getItemsQty() + 1);
        $orderItems = [];
        foreach ($cart->getAllItems() as $quoteItem) {
            $itemId = $quoteItem->getId();

            if (!empty($orderItems[$itemId])) {
                continue;
            }

            $parentItemId = $quoteItem->getParentItemId();
            /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $parentItem */
            if ($parentItemId && !isset($orderItems[$parentItemId])) {
                $orderItems[$parentItemId] = $this->quoteItemToOrderItem->convert(
                    $quoteItem->getParentItem(),
                    ['parent_item' => null]
                );
            }
            $parentItem = isset($orderItems[$parentItemId]) ? $orderItems[$parentItemId] : null;
            $orderItems[$itemId] = $this->quoteItemToOrderItem->convert($quoteItem, ['parent_item' => $parentItem]);
        }


        $cart->collectTotals();
        $cart->save();


        /*            $cart = $this->cartRepository->getActiveForCustomer(8);

                    $cart->addProduct($product, 1);
                    //   $quote->addProduct($product, $this->makeAddRequest($product, $sku, 1));
                    $cart->collectTotals();
                    $this->cartRepository->save($cart);
                    //$cart->save();
        $quote = $this->cartRepository->getForCustomer(8);
        $quote->addProduct($product, 1);
        $quote->collectTotals();
        $quote->save($quote);*/

        $logger->info("=========save2============");
    }


}

private function makeAddRequest(\Magento\Catalog\Model\Product $product, $sku = null, $qty = 1)
{
    $data = [
        'product' => $product->getEntityId(),
        'qty' => $qty
    ];



    $request = new \Magento\Framework\DataObject();
    $request->setData($data);

    return $request;
}

}

1 Answer 1

0

You can use observer sales_order_place_before so that you can add the product before saving the order. checkout_submit_before should also work, but I am not sure why it is not working for your.

in etc/events.xml add this code:

<?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_before">
        <observer instance="Jackson\Surprise\Observer\Frontend\Sales\OrderPlaceBefore" name="jackson_surprise_observer_frontend_sales_orderplacebefore_sales_order_place_before"/>
    </event>
</config>

Now your observer Jackson\Surprise\Observer\Frontend\Sales\OrderPlaceBefore code will be this:

<?php
namespace Jackson\Surprise\Observer\Frontend\Sales;

class OrderPlaceBefore implements \Magento\Framework\Event\ObserverInterface
{
    protected $_productRepository;
    protected $formKey;
    protected $quoteRepository;
    protected $toOrderItem;

    public function __construct(
        \Magento\Catalog\Model\ProductRepository $productRepository,
        \Magento\Checkout\Model\Cart $cart,
        \Magento\Framework\Data\Form\FormKey $formKey,
        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
        \Magento\Quote\Model\Quote\Item\ToOrderItem $toOrderItem
    ){
        $this->_productRepository = $productRepository;
        $this->formKey = $formKey;
        $this->quoteRepository = $quoteRepository;
        $this->toOrderItem = $toOrderItem;
    }
    /**
     * Execute observer
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @return void
     */
    public function execute(
        \Magento\Framework\Event\Observer $observer
    ) {
        $order = $observer->getEvent()->getOrder();
        $quoteId = $order->getQuoteId();
        $quote = $this->quoteRepository->get($quoteId);
        $sku = "my_sky";
        $this->makeAddRequest($order, $quote, $sku);
    }

    private function makeAddRequest($order, $quote, $sku, $qty = 1)
    {
        try {
            $product = $this->_productRepository->get($sku);
        } catch (\Magento\Framework\Exception\NoSuchEntityException $e){
            return;
        }

        $stockItem = $product->getExtensionAttributes()->getStockItem();
        $stockqty = $stockItem->getQty();

        if ($stockqty > $qty) {
            $params = array(
                'form_key' => $this->formKey->getFormKey(),
                'product' => $product->getId(), //product Id
                'qty' => $qty //quantity of product
            );

            $request = new \Magento\Framework\DataObject();
            $request->setData($params);
            $quote->addProduct($product, $request);
            $quote->collectTotals();
            //$this->_cart->save();

            foreach ($quote->getAllVisibleItems() as $item) {
                if ($product->getId() == $item->getProduct()->getId()) {
                    /**
                     * collect item price
                     */
                    $item->save();
                    $existData = $order->getItemByQuoteItemId($item->getId());
                    $orderItem = $this->toOrderItem->convert($item);

                    if ($existData) {
                        $existData->addData($orderItem->getData());
                    } else {
                        /**
                         * add new product to
                         */
                        if ($item->getParentItem()) {
                            $item->setParentItem(
                                $order->getItemByQuoteItemId($item->getParentItem()->getId())
                            );
                        }
                        $order->addItem($orderItem);
                    }
                }
            }
        }
    }
}

#Edited

I think in your code this part is missing:

foreach ($quote->getAllVisibleItems() as $item) {
            if ($product->getId() == $item->getProduct()->getId()) {
                /**
                 * collect item price
                 */
                $item->save();
                $existData = $order->getItemByQuoteItemId($item->getId());
                $orderItem = $this->toOrderItem->convert($item);

                if ($existData) {
                    $existData->addData($orderItem->getData());
                } else {
                    /**
                     * add new product to
                     */
                    if ($item->getParentItem()) {
                        $item->setParentItem(
                            $order->getItemByQuoteItemId($item->getParentItem()->getId())
                        );
                    }
                    $order->addItem($orderItem);
                }
            }
        }
5
  • CollectTotals is already there. even without form key Item is getting added in quote but not in order. There should be some code to pass to order. May be we need to reload quote? Commented May 27, 2021 at 6:35
  • I have done similar task before, I can update my answer, but you need to change your observer and coding style for the. I have working code Commented May 27, 2021 at 15:41
  • post it as answer please. Commented May 27, 2021 at 15:47
  • Answer updated, please check Commented May 27, 2021 at 15:53
  • Did you resolve your issue? Commented May 28, 2021 at 10:17

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.