2

I am trying to split the order based on vendor during checkout process. If there are two products in cart from different vendor, order needs to be split based on vendor. I have followed the answer mentioned here and here. Here is the code.

use Magento\Quote\Model\Quote as QuoteEntity;
class QuoteManagement extends \Magento\Quote\Model\QuoteManagement
{

    public function submit( QuoteEntity $quote, $orderData = []) {
        $sortedItems = array();
        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $logger = \Magento\Framework\App\ObjectManager::getInstance()->get('\Psr\Log\LoggerInterface');
        $logger->debug('Quote overriden');
        foreach ($quote->getAllItems() as $item) {
            $product_id = $item->getProduct()->getId();  
            $logger->debug($item->getName());
            $product = $objectManager->get('Magento\Catalog\Model\Product')->load($product_id);
            $vendor=$product->getResource()->getAttribute('vendor')->getFrontend()->getValue($product);
            if (!isset($sortedItems[$vendor])) {
                $sortedItems[$vendor] = $item;
            }
        }

        $logger->debug(json_encode($sortedItems));
        foreach ($sortedItems as $vendor => $items) {
        foreach ($quote->getAllItems() as $item) {
            $quote->getItemsCollection()->removeItemByKey($item->getId());
        }
        foreach ($items as $item) {
            $quote->addItem($item);
        }
        $quote->setTotalsCollectedFlag(false)->collectTotals();

       parent::submit($quote, $orderData);
    }

        return $this;
    }
}

For some reason the $sortedItems returns vendor in key and value is empty and checkout redirects back to cart page.

Any help on splitting the order during the checkout would be appreciated.

  • What is your payment method? – Sohel Rana Mar 15 '17 at 7:06
  • @SohelRana I am testing with "Money order" payment method. Ideally, split order should work with online payment gateway like bill desk or ccavenue – blakcaps Mar 15 '17 at 7:08
  • It's not working if payment goes to third party site, like paypal website standard. otherwise it's possible – Sohel Rana Mar 15 '17 at 7:10
  • Do you mean order split will not work if third party online payment gateway is used for payments? – blakcaps Mar 15 '17 at 7:12
  • it's work only direct payment like auth.net, paypal pro etc. – Sohel Rana Mar 15 '17 at 7:16
1

First, You should not use the ObjectManager $product = $objectManager->get('Magento\Catalog\Model\Product')->load($product_id); directly!

Also, it seems you may be trying the same approach you would in Magento 1 style. Which can work, but with the code base a work in progress daily it's best to take the proper approach to ensure backwards and forward compatibility.

With that said, you probably will find your answer in the Type models

Hope this helps!

0

I know this is not exactly the same requirement, but you probably can follow the solutions I found for this Post should only be required to go through each item first adding them to an array per each vendor. Example:

public function placeOrder($cartId, PaymentInterface $paymentMethod = null)
{
    $quote = $this->quoteRepository->getActive($cartId);
    $paymentMethodString = $quote->getPayment()->getMethod(); // edit 19.10.17

    // get data from addresses and remove ids
    $billingAddress = $quote->getBillingAddress()->getData();
    $shippingAddress = $quote->getShippingAddress()->getData();
    unset($billingAddress['id']);
    unset($billingAddress['quote_id']);
    unset($shippingAddress['id']);
    unset($shippingAddress['quote_id']);

    $itemsPerVendor = [];
    foreach($quote->getAllItems() as $item) {
        // I don't know how do you keep track of your product vendor, use this as reference only
        $itemsPerVendor[$item->getProduct()->getProductVendor()][] = $item;
    }

    foreach($itemsPerVendor as $vendor => $items) {
        // init Quote Split
        $quoteSplit = $this->quoteFactory->create();
        $quoteSplit->setStoreId($quote->getStoreId());
        $quoteSplit->setCustomer($quote->getCustomer());
        $quoteSplit->setCustomerIsGuest($quote->getCustomerIsGuest());
        if ($quote->getCheckoutMethod() === self::METHOD_GUEST) {
            $quoteSplit->setCustomerEmail($quote->getBillingAddress()->getEmail());
            $quoteSplit->setCustomerGroupId(\Magento\Customer\Api\Data\GroupInterface::NOT_LOGGED_IN_ID);
        }

        // save quoteSplit in order to have a quote id for item
        $this->quoteRepository->save($quoteSplit);

        foreach ($items as $item) {
            // add item
            $item->setId(null); // init item id for force to be added to quoteSplit collection
            $quoteSplit->addItem($item);
        }

        // set addresses
        $quoteSplit->getBillingAddress()->setData($billingAddress);
        $quoteSplit->getShippingAddress()->setData($shippingAddress);

        // recollect totals into the quote
        $quoteSplit->setTotalsCollectedFlag(false)->collectTotals();

        // set payment method // edit 19.10.17
        $quoteSplit->getPayment()->setMethod($paymentMethodString);
        if ($paymentMethod) {
            $quoteSplit->getPayment()->setQuote($quoteSplit);
            $data = $paymentMethod->getData();
            $quoteSplit->getPayment()->importData($data);
        }

        // dispatch this event as Magento standard once per each quote split
        $this->eventManager->dispatch('checkout_submit_before', ['quote' => $quoteSplit]);
        $this->quoteRepository->save($quoteSplit);
        $order = $this->submit($quoteSplit);
        $orders[] = $order;

        if (null == $order) {
            throw new LocalizedException(
                __('An error occurred on the server. Please try to place the order again.')
            );
        }

    }
    // disable origin quote
    $quote->setIsActive(false);
    $this->quoteRepository->save($quote); // edit 19.10.17

    $this->checkoutSession->setLastQuoteId($quoteSplit->getId());
    $this->checkoutSession->setLastSuccessQuoteId($quoteSplit->getId());
    $this->checkoutSession->setLastOrderId($order->getId());
    $this->checkoutSession->setLastRealOrderId($order->getIncrementId());
    $this->checkoutSession->setLastOrderStatus($order->getStatus());

    $this->eventManager->dispatch('checkout_submit_all_after', ['orders' => $orders, 'quote' => $quote]);

    /**
     * the API declaration and interface describe this function returning int, you can't return an array.
     * in order to do that you will have to create a new end point for that.
     */
    return $order->getId();
}
  • I tried as you provided code, the order is split perfectly but order total is not calculated properly (It display complete order total to each order). – Kishor Hase Nov 13 '17 at 12:28
  • Hi Web Spider, please debug on collectTotals(), maybe some extension or customization is messing it, or it's another Magento 2.x version and some code is different, this solution should works on M2.1 – Matias Hidalgo Nov 16 '17 at 12:42
  • I am working on magento 2.2 version. – Kishor Hase Nov 17 '17 at 16:31
  • have you found any solution? i need split order based on vendor. If you have working code please share. – Dinesh Apr 19 at 14:05
  • I tried your code but it is showing wrong sub totals and grnad totals. – Dinesh Apr 20 at 8:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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