Question

I was trying to create orders and quotes programmatically, in an API resource that is consumed by a Mobile Application, and i was successful. However every now and then I got a UNQ_SALES_FLAT_ORDER_INCREMENT_ID error. I google around and realized that:

  • The (increment_last_id) field in the (eav_entity_store) table is incremented by 1on each order as it normally should
  • The (increment_id) field in the (sales_flat_order) table seems to jump/skip several number from the (increment_last_id), sometimes the difference is 20, sometimes the difference is 50, very random

So I digged deeper on how Magento assigns the order increment id and observed the following:


app\code\core\Mage\Sales\Model\Service\Quote.php

The $quote->reserveOrderId() line reserve the order id of this quote:

public function submitOrder()
{
    $this->_deleteNominalItems();
    $this->_validate();
    $quote = $this->_quote;
    $isVirtual = $quote->isVirtual();

    $transaction = Mage::getModel('core/resource_transaction');
    if ($quote->getCustomerId()) {
        $transaction->addObject($quote->getCustomer());
    }
    $transaction->addObject($quote);

    $quote->reserveOrderId();

app\code\local\Mage\Sales\Model\Quote.php

The Quote model then checks if the quote already have a reserved order id or not, if it does not have one, it assigns it automatically, and this is the part that is really causing the issue. I don't know why if a quote doesn't have a reserved order id, the id is automatically assigned, by adding the current store increment id + a random value:

/**
 * Generate new increment order id and associate it with current quote
 *
 * @return Mage_Sales_Model_Quote
 */
public function reserveOrderId()
{
    if (!$this->getReservedOrderId()) {
        $this->setReservedOrderId($this->_getResource()->getReservedOrderId($this) + $this->getRandInt() );
    } else {
        //checking if reserved order id was already used for some order
        //if yes reserving new one if not using old one
        if ($this->_getResource()->isOrderIncrementIdUsed($this->getReservedOrderId())) {
            $this->setReservedOrderId($this->_getResource()->getReservedOrderId($this) + $this->getRandInt() );
        }
    }
    return $this;
}

app\code\core\Mage\Sales\Model\Resource\Quote.php

And just for reference, this is where $this->_getResource()->getReservedOrderId($this) generates the next increment:

public function getReservedOrderId($quote)
{
    $storeId = (int)$quote->getStoreId();
    return Mage::getSingleton('eav/config')->getEntityType(Mage_Sales_Model_Order::ENTITY)
        ->fetchNewIncrementId($storeId);
}

So after all the above I came to the conclusion that I need to set the quote reserved order id manually before submitting the order, something like:

<!-- ... creating quote and adding products -->
$quote->getPayment()->importData(array('method' => 'cashondelivery'));
$quote->collectTotals();
<!-- do i need to manually assign it this way -->
$quote->setReservedOrderId($quote->getResource()->getReservedOrderId($quote));
$quote->save();
$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();
$increment_id = $service->getOrder()->getRealOrderId();

So my question right now is:

  1. should i assign the reserved order id to the quote the way im doing it above, so i don't get a random order increment id? Most of the answers on stackoverflow about creating an order by code doesn't mention this line, so not sure whether it has consequences or not.
  2. why Magento is assigning the order incrementn id the way it does randomly, if it already does not have one.

Thanks and sorry for the lengthy post.

Was it helpful?

Solution

Magento is known to deliver surprising and unexpected implementations in almost every aspect of the application.

But, no, not this. It is too much.

The actual code is

if($this->_getResource()->isOrderIncrementIdUsed($this->getReservedOrderId())) {
    $this->setReservedOrderId($this->_getResource()->getReservedOrderId($this));
}

Please check across versions:

https://github.com/OpenMage/magento-mirror/blob/1.9.3.9/app/code/core/Mage/Sales/Model/Quote.php

It would be great if you have this file under version control so you can track back who added the extra random integer code, and, my oh my, why? :)

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top