3

I'm trying to extend the class "QuoteManagement", but when I try to make the payment, an error is returned.

My code:

di.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\Quote\Model\QuoteManagement" type="Multicategoria\Quote\Model\QuoteManagement" />
</config>

module.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Multicategoria_Quote" setup_version="1.0.0" />
     <sequence>
            <module name="Magento_Backend"/>
             <module name="Magento_Sales"/>
            <module name="Magento_Quote"/>
            <module name="Magento_Checkout"/>>
        </sequence>
</config>

New class:

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Multicategoria\Quote\Model;


use Magento\Quote\Model\QuoteManagement as MagentoQuoteManagement;
use Magento\Framework\Event\ManagerInterface as EventManager;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Api\Data\PaymentInterface;


/**
 * Class QuoteManagement
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 * @SuppressWarnings(PHPMD.TooManyFields)
 */
//class QuoteManagement implements \Magento\Quote\Api\CartManagementInterface
class QuoteManagement extends MagentoQuoteManagement
{

     /**
     * @var EventManager
     */
    protected $eventManager;

    /**
     * @var \Magento\Quote\Api\CartRepositoryInterface
     */
    protected $quoteRepository;

    /**
     * @var \Magento\Checkout\Model\Session
     */
    protected $checkoutSession;

    /**
     * @var QuoteFactory
     */
    protected $quoteFactory;

    /**
     * @param EventManager $eventManager 
     * @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository 
     * @param \Magento\Checkout\Model\Session $checkoutSession 
     * @param QuoteFactory $quoteFactory 
     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
     */
    public function __construct(
        EventManager $eventManager,
        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, 
        \Magento\Checkout\Model\Session $checkoutSession, 
        \Magento\Quote\Model\QuoteFactory $quoteFactory
    ) {
        $this->eventManager = $eventManager; 
        $this->quoteRepository = $quoteRepository; 
        $this->checkoutSession = $checkoutSession; 
        $this->quoteFactory = $quoteFactory; 
    }

    /**
     * @inheritdoc
     */
    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
            $product_id = $item->getProduct()->getId();
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $product = $objectManager->create('Magento\Catalog\Model\Product')->load($product_id);

            $itemsPerVendor[$product->getSellerId()][] = $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 "teste";
    }}

Error:

"Fatal Error: 'Uncaught Error: Call to a member function create() on null in \/opt\/lampp\/htdocs\/backendmulti\/vendor\/magento\/module-quote\/Model\/QuoteManagement.php:451\nStack trace:\n#0 \/opt\/lampp\/htdocs\/backendmulti\/vendor\/magento\/module-quote\/Model\/QuoteManagement.php(407): Magento\\Quote\\Model\\QuoteManagement->submitQuote(Object(Magento\\Quote\\Model\\Quote\\Interceptor), Array)\n#1 \/opt\/lampp\/htdocs\/backendmulti\/app\/code\/Multicategoria\/Quote\/Model\/QuoteManagement.php(130): Magento\\Quote\\Model\\QuoteManagement->submit(Object(Magento\\Quote\\Model\\Quote\\Interceptor))\n#2 \/opt\/lampp\/htdocs\/backendmulti\/vendor\/magento\/framework\/Interception\/Interceptor.php(58): Multicategoria\\Quote\\Model\\QuoteManagement->placeOrder(43, NULL)\n#3 \/opt\/lampp\/htdocs\/backendmulti\/vendor\/magento\/framework\/Interception\/Interceptor.php(138): Multicategoria\\Quote\\Model\\QuoteManagement\\Interceptor->___callParent('placeOrder', Array)\n#4 \/opt\/lampp\/htdocs\/backendmulti\/vendor\/magento\/module-braintree\/Plugin\/OrderCancellation.php(63): Multicategoria\\Quote\\Model\\QuoteM' in '\/opt\/lampp\/htdocs\/backendmulti\/vendor\/magento\/module-quote\/Model\/QuoteManagement.php' on line 451"

Can anyone help me fix this problem?

1

Remove __construct from your overwrite class(Multicategoria\Quote\Model\QuoteManagement). Following part you should remove:

public function __construct(
    EventManager $eventManager,
    \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, 
    \Magento\Checkout\Model\Session $checkoutSession, 
    \Magento\Quote\Model\QuoteFactory $quoteFactory
) {
    $this->eventManager = $eventManager; 
    $this->quoteRepository = $quoteRepository; 
    $this->checkoutSession = $checkoutSession; 
    $this->quoteFactory = $quoteFactory; 
}

This is a totally wrong way without calling parent class __construct. Also, you access the same variable that already has in the parent class. So don't need to declare again here.

If you want still __construct in your class then try following code.

<?php
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

namespace Multicategoria\Quote\Model;


use Magento\Quote\Model\QuoteManagement as MagentoQuoteManagement;
use Magento\Framework\Event\ManagerInterface as EventManager;
use Magento\Framework\Exception\LocalizedException;
use Magento\Quote\Api\Data\PaymentInterface;
use Magento\Authorization\Model\UserContextInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\StateException;
use Magento\Quote\Model\Quote\Address\ToOrder as ToOrderConverter;
use Magento\Quote\Model\Quote\Address\ToOrderAddress as ToOrderAddressConverter;
use Magento\Quote\Model\Quote as QuoteEntity;
use Magento\Quote\Model\Quote\Item\ToOrderItem as ToOrderItemConverter;
use Magento\Quote\Model\Quote\Payment\ToOrderPayment as ToOrderPaymentConverter;
use Magento\Sales\Api\Data\OrderInterfaceFactory as OrderFactory;
use Magento\Sales\Api\OrderManagementInterface as OrderManagement;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Quote\Model\QuoteValidator;
use Magento\Quote\Model\CustomerManagement;

/**
 * Class QuoteManagement
 *
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 * @SuppressWarnings(PHPMD.TooManyFields)
 */
//class QuoteManagement implements \Magento\Quote\Api\CartManagementInterface
class QuoteManagement extends MagentoQuoteManagement
{
    public function __construct(
        EventManager $eventManager,
        QuoteValidator $quoteValidator,
        OrderFactory $orderFactory,
        OrderManagement $orderManagement,
        CustomerManagement $customerManagement,
        ToOrderConverter $quoteAddressToOrder,
        ToOrderAddressConverter $quoteAddressToOrderAddress,
        ToOrderItemConverter $quoteItemToOrderItem,
        ToOrderPaymentConverter $quotePaymentToOrderPayment,
        UserContextInterface $userContext,
        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
        \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository,
        \Magento\Customer\Model\CustomerFactory $customerModelFactory,
        \Magento\Quote\Model\Quote\AddressFactory $quoteAddressFactory,
        \Magento\Framework\Api\DataObjectHelper $dataObjectHelper,
        StoreManagerInterface $storeManager,
        \Magento\Checkout\Model\Session $checkoutSession,
        \Magento\Customer\Model\Session $customerSession,
        \Magento\Customer\Api\AccountManagementInterface $accountManagement,
        \Magento\Quote\Model\QuoteFactory $quoteFactory,
        \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory = null,
        \Magento\Customer\Api\AddressRepositoryInterface $addressRepository = null
    ) {
        parent::__construct(
            $eventManager,
            $quoteValidator,
            $orderFactory,
            $orderManagement,
            $customerManagement,
            $quoteAddressToOrder,
            $quoteAddressToOrderAddress,
            $quoteItemToOrderItem,
            $quotePaymentToOrderPayment,
            $userContext,
            $quoteRepository,
            $customerRepository,
            $customerModelFactory,
            $quoteAddressFactory,
            $dataObjectHelper,
            $storeManager,
            $checkoutSession,
            $customerSession,
            $accountManagement,
            $quoteFactory,
            $quoteIdMaskFactory,
            $addressRepository
        );
    }

    /**
     * @inheritdoc
     */
    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
            $product_id = $item->getProduct()->getId();
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $product = $objectManager->create('Magento\Catalog\Model\Product')->load($product_id);

            $itemsPerVendor[$product->getSellerId()][] = $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 "teste";
    }
}

You can do this using plugin without overwriting whole class.

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.