Magento 2 – How to Customize Order Numbers by Overriding Magento\SalesSequence\Model\Sequence

magento-communitymagento2orderssales-order

Magento 2 is using the class Magento\SalesSequence\Model\Sequence to generate a reserved order number prior to actually placing an order. I would like to override this class to create custom increment numbers but the fact that the variables are private prevents the subclass from accessing them.

As suggested on Mage2.pro, having the properties declared as protected instead would be simpler.

Not Conceivable Solutions

Editing Core Files

I'm able to achieve my goal by directly editing the core file Magento\SalesSequence\Model\Sequence – which is of course not the solution I'm looking for.

Observers

I'm aware that it is possible to use observer to set the order number later in the process but I imperatively need the order number to be set when initially reserved as other extensions will be relying on it.

Plugins [UPDATE]

Using an after plugin on the getCurrentValue() function, I am able to retrieve the system generated number and entirely control the returned number. This would work perfectly if I would be able to access the meta variable to identify for which entity_type the function is currently executed. Still, this variable is private and therefore inaccessible.


Online Information

At the time of writing, I was not able to find any useful information online related to this new method used by Magento 2 for assigning order numbers. Everything seems to be build so that Prefixes, Suffixes and even the pattern can be changed easily but nothing is integrated within the Community Edition admin interface.

Important Note

I'm looking for a solution which will allow to add dynamic information to the resulting order number, not simply static Prefixes or Suffixes added through the sales_sequence_profile database table.

Different Entity Types

Also the Sequence class is used for generating different numbers for different entity_type as invoice, creditmemo and shipment based on the data stored in the sales_sequence_meta database table. This means that the method responsible for dynamically creating new numbers must have access to this sequence meta to identify for which entity type it is currently creating a number allowing it to be adapted in consequence.


Indications from someone who was able to achieve this goal would be very appreciated!

Any suggestion is welcomed!

Best Answer

I finally realized that the class Magento\SalesSequence\Model\ResourceModel\Meta is responsible for setting the active_profile to the meta object used by the Magento\SalesSequence\Model\Sequence class to generate the final number.

The active_profile is read from the sales_sequence_profile databate table which contains fixed value. Someone with only static requirements can simply manually edit these table fields or create a very simple module for accessing and editing the profiles already used by Magento default.

In my case using dynamic variables, not only based on a specific store view but on current date for example is a requirement therefore I couldn't rely on these static database values.

Solution - Overriding the Meta class

I was able to achieve my goal by simply overriding the class Magento\SalesSequence\Model\ResourceModel\Meta. While this class is usually solicited for grabing the current sequence profile from the database, with a simple override we can adapt it so it passes the Prefix and Suffix to the Magento\SalesSequence\Model\Sequence class which will use them to generate the final number. This class also gives us access to some useful parameters as the entity_type and store_id via the $object variable.

Working Example

NameSpace/Module/etc/di.xml

<?xml version="1.0"?>

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
    <preference for="Magento\SalesSequence\Model\ResourceModel\Meta" type="NameSpace\Module\Override\SalesSequence\ResourceModel\Meta" />
</config>

NameSpace/Module/Override/SalesSequence/ResourceModel/Meta.php

<?php
namespace NameSpace\Module\Override\SalesSequence\ResourceModel;

class Meta extends \Magento\SalesSequence\Model\ResourceModel\Meta
{

    protected function _afterLoad(\Magento\Framework\Model\AbstractModel $object)
    {

        $entityType = $object->getEntityType(); //order/invoice/creditmemo/shipment
        $storeId = $object->getStoreId(); //CURRENT STORE ID

        $activeProfile = $this->resourceProfile->loadActiveProfile($object->getId());
        $activeProfile->setPrefix('ORD-'); //SET CUSTOM PREFIX - DEFAULT: store_id
        $activeProfile->setSuffix('A'); //SET CUSTOM SUFFIX
        $activeProfile->setStartValue('1'); //SET START VALUE - DEFAULT: 1
        $activeProfile->setStep('1'); //SET INCREMENT STEP - DEFAULT: 1

        //[UPDATE] USEFUL FOR SHARED ORDER NUMBERS WITHIN MULTIPLE STORES
        $object->setSequenceTable('custom_table'); //SET CUSTOM INCREMENT TABLE - DEFAULT: sequence_{entity_type}_{store_id}


        //SET DATA TO active_profile
        $object->setData(
            'active_profile',
            $activeProfile
        );

        return $this;
    }

}
?>

This above solution gives some flexibility but does not allow to edit the number padding or to reset the sequence after a certain period.

Edit Pattern & Padding

To edit the Pattern, one might simply override the DEFAULT_PATTERN constant inside the Magento\SalesSequence\Model\Sequence class.

Reseting Sequence after X Period

This should be possible by simply resetting the AUTO_INCREMENT for the specific sequence_{entity_type}_{store_id} table following certain conditions from inside our Meta class. This way, as our number will be generated by the Sequence class, the next value will start over from the start_value.

Related Topic