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;
}

}

asked May 26, 2021 at 23:09

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);
 }
 }
 }
answered May 27, 2021 at 4:21
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

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.