Magento 2 – How to Create Order Programmatically with Invalid State Change Error

magento2orders

I have a function to create order Programmatically, but run after twice, there is an error message:

string(3407) "{"message":"Invalid state change requested","trace":"#0 \/home\/m22\/public_html\/vendor\/magento\/framework\/Interception\/Interceptor.php(121): Magento\\Quote\\Model\\QuoteRepository\\Plugin\\AccessChangeQuoteControl->beforeSave(Object(Magento\\Quote\\Model\\QuoteRepository\\Interceptor), Object(Magento\\Quote\\Model\\Quote))\n#1 \/home\/m22\/public_html\/vendor\/magento\/framework\/Interception\/Interceptor.php(153): Magento\\Quote\\Model\\QuoteRepository\\Interceptor->Magento\\Framework\\Interception\\{closure}(Object(Magento\\Quote\\Model\\Quote))\n#2 \/home\/m22\/public_html\/generated\/code\/Magento\/Quote\/Model\/QuoteRepository\/Interceptor.php(78): Magento\\Quote\\Model\\QuoteRepository\\Interceptor->___callPlugins('save', Array, Array)\n#3 \/home\/m22\/public_html\/vendor\/magento\/module-quote\/Model\/QuoteManagement.php(520): Magento\\Quote\\Model\\QuoteRepository\\Interceptor->save(Object(Magento\\Quote\\Model\\Quote))\n#4 \/home\/m22\/public_html\/vendor\/magento\/module-quote\/Model\/QuoteManagement.php(406): Magento\\Quote\\Model\\QuoteManagement->submitQuote(Object(Magento\\Quote\\Model\\Quote), Array)\n#5 \/home\/m22\/public_html\/vendor\/magento\/module-quote\/Model\/QuoteManagement.php(364): Magento\\Quote\\Model\\QuoteManagement->submit(Object(Magento\\Quote\\Model\\Quote))\n#6 \/home\/m22\/public_html\/app\/code\/namespace\/plugin\/Helper\/Data.php(104): Magento\\Quote\\Model\\QuoteManagement->placeOrder('16')\n#7 \/home\/m22\/public_html\/app\/code\/namespace\/plugin\/Model\/Calculator.php(217): namespace\\plugin\\Helper\\Data->createMageOrder(Array)\n#8 [internal function]: namespace\\plugin\\Model\\Calculator->createOrder('dllm')\n#9 \/home\/m22\/public_html\/vendor\/magento\/module-webapi\/Controller\/Rest.php(330): call_user_func_array(Array, Array)\n#10 \/home\/m22\/public_html\/vendor\/magento\/module-webapi\/Controller\/Rest.php(239): Magento\\Webapi\\Controller\\Rest->processApiRequest()\n#11 \/home\/m22\/public_html\/vendor\/magento\/framework\/Interception\/Interceptor.php(58): Magento\\Webapi\\Controller\\Rest->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#12 \/home\/m22\/public_html\/vendor\/magento\/framework\/Interception\/Interceptor.php(138): Magento\\Webapi\\Controller\\Rest\\Interceptor->___callParent('dispatch', Array)\n#13 \/home\/m22\/public_html\/vendor\/magento\/framework\/Interception\/Interceptor.php(153): Magento\\Webapi\\Controller\\Rest\\Interceptor->Magento\\Framework\\Interception\\{closure}(Object(Magento\\Framework\\App\\Request\\Http))\n#14 \/home\/m22\/public_html\/generated\/code\/Magento\/Webapi\/Controller\/Rest\/Interceptor.php(39): Magento\\Webapi\\Controller\\Rest\\Interceptor->___callPlugins('dispatch', Array, Array)\n#15 \/home\/m22\/public_html\/vendor\/magento\/framework\/App\/Http.php(135): Magento\\Webapi\\Controller\\Rest\\Interceptor->dispatch(Object(Magento\\Framework\\App\\Request\\Http))\n#16 \/home\/m22\/public_html\/generated\/code\/Magento\/Framework\/App\/Http\/Interceptor.php(24): Magento\\Framework\\App\\Http->launch()\n#17 \/home\/m22\/public_html\/vendor\/magento\/framework\/App\/Bootstrap.php(256): Magento\\Framework\\App\\Http\\Interceptor->launch()\n#18 \/home\/m22\/public_html\/index.php(39): Magento\\Framework\\App\\Bootstrap->run(Object(Magento\\Framework\\App\\Http\\Interceptor))\n#19 {main}"}"

here is the function:

public function createMageOrder($orderData) {
    $store=$this->_storeManager->getStore();
    $websiteId = $this->_storeManager->getStore()->getWebsiteId();
    $customer=$this->customerFactory->create();
    $customer->setWebsiteId($websiteId);
    $customer->loadByEmail($orderData['email']);// load customet by email address
    if(!$customer->getEntityId()){
        //If not avilable then create this customer 
        $customer->setWebsiteId($websiteId)
                ->setStore($store)
                ->setFirstname($orderData['shipping_address']['firstname'])
                ->setLastname($orderData['shipping_address']['lastname'])
                ->setEmail($orderData['email']) 
                ->setPassword($orderData['email']);
        $customer->save();
    }

    $cartId = $this->cartManagementInterface->createEmptyCart(); //Create empty cart
    $quote = $this->cartRepositoryInterface->get($cartId); // load empty cart quote
    $quote->setStore($store);
    // if you have allready buyer id then you can load customer directly 
    $customer= $this->customerRepository->getById($customer->getEntityId());
    $quote->setCurrency();
    $quote->assignCustomer($customer); //Assign quote to customer

    //add items in quote

    foreach($orderData['items'] as $item){
        $product=$this->_product->load($item['product_id']);

        //$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/templog.log');
        //$logger = new \Zend\Log\Logger();
        //$logger->addWriter($writer);
        //$logger->info($product);

        $product->setPrice($item['price']);
        $quote->addProduct($product, intval($item['qty']));
    }

    //Set Address to quote
    $quote->getBillingAddress()->addData($orderData['shipping_address']);
    $quote->getShippingAddress()->addData($orderData['shipping_address']);

    // Collect Rates and Set Shipping & Payment Method

    $shippingAddress=$quote->getShippingAddress();
    $shippingAddress->setCollectShippingRates(true)
                    ->collectShippingRates()
                    ->setShippingMethod('flatrate_flatrate'); //shipping method
    $quote->setPaymentMethod('checkmo'); //payment method
    $quote->setInventoryProcessed(false); //not effetc inventory

    // Set Sales Order Payment
    $quote->getPayment()->importData(['method' => 'checkmo']);
    $quote->save(); //Now Save quote and your quote is ready

    // Collect Totals
    $quote->collectTotals();

    // Create Order From Quote
    $quote = $this->cartRepositoryInterface->get($quote->getId());
    $orderId = $this->cartManagementInterface->placeOrder($quote->getId());
    $order = $this->order->load($orderId);

    $order->setEmailSent(0);
    $increment_id = $order->getRealOrderId();
    if($order->getEntityId()){
        $result['order_id']= $order->getRealOrderId();
    }else{
        $result=['error'=>1,'msg'=>'Your custom message'];
    }
    return $result;
}

anyone know how to fix that?

—————–update—————–
vendor\magento\module-quote\Model\QuoteRepository\Plugin\AccessChangeQuoteControl.php

        case UserContextInterface::USER_TYPE_GUEST:

            $isAllowed = true;

            break;

I need to add $isAllowed = true part of code, but what is

$quote->getCustomerId() == $this->userContext->getUserId()?

Best Answer

Not sure what the problem is. but I can give you a place to start debugging.
The only place in the core where this error message is triggered is Magento\Quote\Model\QuoteRepository\Plugin\AccessChangeQuoteControl::beforeSave.
The message is triggered if the result of the method isAllowed from the same class is false.
Check why this method is returning false.

Related Topic