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();  
            $product = $objectManager->get('Magento\Catalog\Model\Product')->load($product_id);
            if (!isset($sortedItems[$vendor])) {
                $sortedItems[$vendor] = $item;

        foreach ($sortedItems as $vendor => $items) {
        foreach ($quote->getAllItems() as $item) {
        foreach ($items as $item) {

       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
    Commented Mar 15, 2017 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
    Commented Mar 15, 2017 at 7:08
  • It's not working if payment goes to third party site, like paypal website standard. otherwise it's possible
    – Sohel Rana
    Commented Mar 15, 2017 at 7:10
  • Do you mean order split will not work if third party online payment gateway is used for payments?
    – blakcaps
    Commented Mar 15, 2017 at 7:12
  • it's work only direct payment like auth.net, paypal pro etc.
    – Sohel Rana
    Commented Mar 15, 2017 at 7:16

2 Answers 2


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!


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();

    $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();
        if ($quote->getCheckoutMethod() === self::METHOD_GUEST) {

        // save quoteSplit in order to have a quote id for item

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

        // set addresses

        // recollect totals into the quote

        // set payment method // edit 19.10.17
        if ($paymentMethod) {
            $data = $paymentMethod->getData();

        // dispatch this event as Magento standard once per each quote split
        $this->eventManager->dispatch('checkout_submit_before', ['quote' => $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
    $this->quoteRepository->save($quote); // edit 19.10.17


    $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). Commented Nov 13, 2017 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 Commented Nov 16, 2017 at 12:42
  • I am working on magento 2.2 version. Commented Nov 17, 2017 at 16:31
  • have you found any solution? i need split order based on vendor. If you have working code please share.
    – Dinesh
    Commented Apr 19, 2019 at 14:05
  • I tried your code but it is showing wrong sub totals and grnad totals.
    – Dinesh
    Commented Apr 20, 2019 at 8:58

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.