Question

Can Magento be configured in a way, that multiple store views of the same website can share the same order increment_id number range? And if so, how?

For example, with a multistore setup like this in core_store:

store_id        code    website_id    group_id
       0       admin             0           0
       1       alpha             1           1
       2       bravo             2           2
       3     charlie             2           2

Now a new store view delta is added:

store_id        code    website_id    group_id
       4       delta             1           1

Assuming alpha's last order increment id currently is 1000123, how to achieve:

next sell    order number
    alpha         1000124
    delta         1000125
    delta         1000126
    alpha         1000127

Same question goes for multiple store views sharing the same invoice increment_id number range, and/or sharing the same creditmemo increment_id number range.

Does Magento support this out-of-the-box?

Was it helpful?

Solution

I'd imagine that this would be quite difficult. Increment id's are stored in the eav_entity_store table and unsurprisingly each store has it's own entry which is updated when an order (and quote, invoice etc) is created. To get all stores to use the same incrementer you would need to somehow rewrite this logic so it used the same row in the DB. Quite what impact this may have on other areas of the site is something else that would need to be considered.

OTHER TIPS

You can override orders, shippings, invoices and credit memos increment model by rewriting the "eav/entity_increment_numeric" class providing custom logic in a Model of yours.

Take a look at the ancestor classes (Mage_Eav_Model_Entity_Increment_Numeric and Mage_Eav_Model_Entity_Increment_Abstract) in order to understand how to provide your own logic.

You can the differentiate logic between different entities by checking the $entityTypeCode parameter of the getNextId() function you will override.

Another (more invasive) way is that of specifying a different increment model for each entity type by overwriting (via install script) the value of the "increment_model" column of the "eav_entity_type" table. Personally I prefer the "rewrite" solution mentioned above.

Pay attention: increment ids have a uniqueness constraint in latest Magento versions so you can't store the same increment id for two different entities of the same type. In other words you can't have two different invoices with the same increment id.

Hope it helps.

While digging deeper, I realized that eav_entity_type.increment_per_store may be helpful.

It is. But only for the case, when you want all store views (globally, no matter which website they're defined in) of your Magento installation to share the same order increment_id number range.

This doesn't solve my specific issue, but maybe it's helpful to some others, so here we go:

To activate global sharing of your order numbers, set eav_entity_type.increment_per_store of the order entity to 0 ,

This leads to Mage_Eav_Model_Entity_Type::fetchNewIncrementId() using store_id = 0 when loading the eav_entity_store record of the order entity, no matter which store view it really belongs to.

If no such record exists, Magento creates one, using store_id and increment_prefix of 0.

public function fetchNewIncrementId($storeId = null)
{
    if (!$this->getIncrementModel()) {
        return false;
    }

    if (!$this->getIncrementPerStore() || ($storeId === null)) {
        /**
         * store_id null we can have for entity from removed store
         */
        $storeId = 0;
    }

    // Start transaction to run SELECT ... FOR UPDATE
    $this->_getResource()->beginTransaction();

    $entityStoreConfig = Mage::getModel('eav/entity_store')
        ->loadByEntityStore($this->getId(), $storeId);

    if (!$entityStoreConfig->getId()) {
        $entityStoreConfig
            ->setEntityTypeId($this->getId())
            ->setStoreId($storeId)
            ->setIncrementPrefix($storeId)
            ->save();
    }

    $incrementInstance = Mage::getModel($this->getIncrementModel())
        ->setPrefix($entityStoreConfig->getIncrementPrefix())
        ->setPadLength($this->getIncrementPadLength())
        ->setPadChar($this->getIncrementPadChar())
        ->setLastId($entityStoreConfig->getIncrementLastId())
        ->setEntityTypeId($entityStoreConfig->getEntityTypeId())
        ->setStoreId($entityStoreConfig->getStoreId());

    /**
     * do read lock on eav/entity_store to solve potential timing issues
     * (most probably already done by beginTransaction of entity save)
     */
    $incrementId = $incrementInstance->getNextId();
    $entityStoreConfig->setIncrementLastId($incrementId);
    $entityStoreConfig->save();

    // Commit increment_last_id changes
    $this->_getResource()->commit();

    return $incrementId;
}

This should work for any entity type using the eav/entity_increment_numeric model, like order, invoice, shipment and creditmemo.

Be aware though, that I couldn't find any official documentation of increment_per_store yet. And that there's no option in the Magento backend letting you configure this.

This may or may not mean, that it's not thought to be used officially.

Use at your own risk. If your changes wreak havoc, don't blame me. You've been warned^^

It's not supported out-of-the-box. I also wanted to do this once to have a second storeview for an A/B Test share the same increment_id from the original store.

I tried to match those 2 numbers the simple way when checkout_submit_all_after is fired, but felt very uncomfortable with it, so I dropped it. I guess with more storeviews and a lot of traffic this can result in a real mess so you have to dig deeper in Magentos logic.

Solution:

Having a differing order/invoice/creditmemo etc... number range is quite nice, for different countries, which most often means on a store group level.

But having different number ranges on store view level is a bad thing if you use store views for different languages, which might be done in 90% of all cases.

Luckily it is not that difficult as proposed in this thread:

What we are going to do is we fetch the default store view id instead of using the store view id the method is called with. We are doing this by resolving the store group for the current store view and fetch its default store view id. Then every store view of a specific store group uses the same number range format (the one from the default store view).

Create this class:

class Funky_Module_Model_Entity_Type extends Mage_Eav_Model_Entity_Type
{
    /**
     * Retreive new incrementId
     *
     * @param int $storeId
     * @return string
     * @throws Exception
     */
    public function fetchNewIncrementId($storeId = null)
    {
        if (!$this->getIncrementModel()) {
            return false;
        }

        if (!$this->getIncrementPerStore() || ($storeId === null)) {
            /**
             * store_id null we can have for entity from removed store
             */
            $storeId = 0;
        }

        //FIX START:
        $groupId = Mage::getModel('core/store')->load($storeId)->getGroupId();
        $group =  Mage::getModel('core/store_group')->load($groupId);
        $storeId = $group->getDefaultStoreId();
        //FIX END:

        // Start transaction to run SELECT ... FOR UPDATE
        $this->_getResource()->beginTransaction();

        try {

            $entityStoreConfig = Mage::getModel('eav/entity_store')
                ->loadByEntityStore($this->getId(), $storeId);

            if (!$entityStoreConfig->getId()) {
                $entityStoreConfig
                    ->setEntityTypeId($this->getId())
                    ->setStoreId($storeId)
                    ->setIncrementPrefix($storeId)
                    ->save();
            }

            $incrementInstance = Mage::getModel($this->getIncrementModel())
                ->setPrefix($entityStoreConfig->getIncrementPrefix())
                ->setPadLength($this->getIncrementPadLength())
                ->setPadChar($this->getIncrementPadChar())
                ->setLastId($entityStoreConfig->getIncrementLastId())
                ->setEntityTypeId($entityStoreConfig->getEntityTypeId())
                ->setStoreId($entityStoreConfig->getStoreId());

            /**
             * do read lock on eav/entity_store to solve potential timing issues
             * (most probably already done by beginTransaction of entity save)
             */
            $incrementId = $incrementInstance->getNextId();
            $entityStoreConfig->setIncrementLastId($incrementId);
            $entityStoreConfig->save();

            // Commit increment_last_id changes
            $this->_getResource()->commit();
        } catch (Exception $e) {
            $this->_getResource()->rollBack();
            throw $e;
        }

        return $incrementId;
    }

}

Add this rewrite to config.xml of your module:

<global>
   <models>
            <eav>
                <rewrite>
                     <entity_type>Gigaset_Core_Model_Entity_Type</entity_type>
                </rewrite>
            </eav> 
    ...

If you have a nicer way, without having to rewrite spread the knowledge. Have fun. Dont hack the core.

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