Back to the release learning center
The single most defining component of any WMS, unanimously agreed upon by any operational or warehouse management executive on the planet, is performance. In a warehouse, you have to be able to pick and ship products efficiently. The system cannot slow you down, it has to at least move at the same speed as the people in the warehouse.
For those of us who have experienced the Warehouse management module in Microsoft Dynamics 365 Supply Chain Management, we know all too well the performance challenges that can come. The module was developed to make full use of the transactional nature of D365’s inventory system: inventory transactions (InventTrans), inventory dimensions (InventDim), and on-hand inventory (InventSum). The thought process is sound: D365 is a transactional ERP, and it is highly desirable if not a requirement to have full traceability of all movements inventory makes when moving in, through, and out of a warehouse. Before Microsoft acquired the Warehouse management module, the inventory movement framework was extended to track updates during work execution in the WMS. As work is executed in the warehouse, transactions are generated to reflect those movements. In the most typical example of picking the goods and staging them before loading, it looks something like this:
A single work unit consisting of movements from a bulk location to staging and from staging to an outbound dock would generate eight inventory transactions. Each of the four work lines on this work unit generates two inventory transactions due to the movements from the location to the user (and vice-versa). The creation of each of these inventory transactions generates inventory dimension records. The existence of these extra inventory dimensions and inventory transactions leads to increased strain on the WMS when inserting, updating, or reading any of these records. This includes processes such as work creation, work execution, reading on-hand inventory, posting packing slip updates, etc. Without getting into the technical details here, one could see how expansive of a problem this might become even when dealing with a simple work structure like the one above.
But what happens if we look at a more complex work structure, such as picking two different items that are batch-controlled (i.e. – the batch number is specified on the work)? Using the same movements as above, the work lines and transaction generation would then look something like this:
This same movement structure with the addition of picking a second item and using batch has doubled the number of inventory transactions, despite picking the same item across both initial pick lines. You can take this same example and apply the logic to any picking activity that uses tracking dimensions or license plates. Imagine building a pallet with 20 items, each with its own batch, and you can start to see the scale of the existing problem that will grow and get worse with time. To exasperate the issue, it’s nearly impossible to properly archive any of the data that causes these performance issues due to the critical nature of the data’s existence in the data model.
This issue has been known for years and has had no simple fix. Various features have been introduced to bypass the issue (see deferred put processing). However, Microsoft has introduced a proper resolution to this problem: a holistic rework of the data model that drives inventory movements from work execution. Enter warehouse-specific inventory transactions.
Enable warehouse-specific inventory transactions
Microsoft has a great write-up on how to enable this feature, take a look here to enable and configure it (note – it’s pretty straightforward): Microsoft Learn | Warehouse Transactions.
How it works
The concept is simple and can be broken down into a few components:
- De-normalized data structures.
- Work-level inventory reservations reworked.
- Built-in archiving.
- Limited breaking changes.
To truly solve the issue, you need to get rid of the concept of inventory transactions controlling the reservations and intra-work movements. A new data structure has been introduced to bypass the need to create these work inventory transactions: warehouse inventory transactions and warehouse inventory item sets.
Not pictured in WHSInventoryItemSetElement – InventDimension1 – 12, Russian localization fields.
WHSInventoryTransaction represents the storage dimensions for a particular work unit, and WHSInventoryItemSetElement represents the tracking dimensions, item, and quantity for a particular work unit.
How it works is straightforward:
- When work is created, a record is created in WHSInventoryTransaction of type PhysicalReservation with the relevant storage dimensions of the work.
- Simultaneously, a record is created in WHSInventoryItemSetElement, representing each item, quantity, and tracking dimension combination that exists for the work, related to the originating WHSInventoryTransaction record.
- This is what informs the reservation engine of what dimensions, item, and quantity need to be reserved.
- When a work line is executed, the following actions take place:
- Inventory is unreserved via a RemovedPhysicalReservation type WHSInventoryTransaction record.
- Inventory is issued from the relevant dimensions via a RegisteredIssue type WHSInventoryTransaction record.
- Inventory is received to the relevant dimensions via a RegisteredReceipt type WHSInventoryTransaction record.
The process visualized looks something like this:
The introduction of these entities entirely replaces the need for traditional inventory transactions in work execution. Whereas beforehand a two-step work unit (pick from location, put to staging, pick from staging, put to dock door) would generate a minimum of eight inventory transactions, the new process generates zero. The only inventory transactions that remain in the new process are the source order document transactions (i.e. – the sales order-level reservation and the final pick against the sales line).
The InventMovement framework, responsible for processing the inventory transactions to move inventory, has been reworked: WHSInventMov_Work, WHSInventMov_WorkFrom, and WHSInventMov_WorkTo have been deprecated. A new class has been introduced, WHSInventoryTransactionWorkController, which triggers the creation of the records in WHSInventoryTransaction and WHSInventoryItemSetElement.
Archiving
As mentioned, data expansion is a huge concern when it comes to warehouse performance. Microsoft has introduced alongside this new powerful framework a mechanism to archive all relevant warehouse inventory transactions and item set element data once a work unit is closed or canceled.
If the value is set to 0 here, the WHSInventoryTransaction and WHSInventoryItemSetElement data is immediately archived to a single new data structure, WHSInventoryTransactionArchive.
If the value is set to >0, a reference record for the relevant work unit is inserted into the WHSInventoryTransactionArchiveQueueEntry table. Once the days threshold has been passed, the data is then archived. By default, the value is set to 0, and the data is immediately archived.
This is relatively useful data to have around during testing: developer testing, user acceptance, and maybe during the first week or so of go-live. However, outside of these periods, there’s really no reason to keep this data around, and you may as well archive it as soon as you don't need it for daily operational purposes (typically a week).
Breaking changes
However desirable it is to have no breaking changes, it’s just not a reality with this level of change. Microsoft has done a commendable job to reduce the possibility of breaking changes but there are likely going to be some things you will have to look at before you implement this feature. Here is a quick overview of what we’ve noticed so far:
- WHSInventMov_Work and child classes WHSInventMov_WorkFrom, WHSInventMov_WorkTo.
- These are deprecated. If you have extensions here, you need to re-engineer them.
- InventUpdate and child InventUpd_Estimated, InventUpd_Reservation, InventUpd_Financial classes.
- There are changes here. It can’t be guaranteed that any of the extensions here will be OK – they should be tested.
- Any changes in InventUpd_FinancialLite (the light movement framework introduced years ago) will need to be re-engineered as this class is deprecated.
- WHSInventReserve appears unchanged and the data here is populated as it was before, now via a different mechanism.
- WHSWorkInventTrans is largely unchanged, with the exception of the InventTransIdFrom and InventTransIdTo. Those fields are not populated in the new model.
- This is important to note – many deeper-level customizations around work reporting or manipulation of work would rely on this data here. Definitely check processes or customizations that relied on inventory transaction data during work as this would need to be re-engineered.
- WHSInvent::moveWorkTransactionQuantities() is where you can see the WHSInventoryTransactionWorkController class constructed if it’s determined the relevant work type should use the new warehouse inventory transactions mechanism.
Demonstration
Let’s look at a simple work unit example. A single pick/put pair, item J0001 from the ASRS to BAYDOOR, 1 box, batch J0001-B0002:
Once created, we see a new record in WHSInventoryTransaction and in WHSInventoryItemSetElement:
The first record in WHSInventoryTransaction is of type PhysicalReservation, and this is what is holding the reservation of the related WHSInventoryItemSetElement records. Once the first line is picked, the work is updated to reflect the pick execution:
As this occurs, several actions occur in the new data model:
The reservation is removed in WHSInventoryTransaction at the same dimensions where the reservation exists. Stock is issued from new storage dimensions, specifically the ASRS location, as well as the batch (as this is a batch-controlled item) represented by a new record in WHSInventoryItemSetElement (GUID003). Then the stock is received against the user location and the license plate, represented on WHSInventoryTransaction, against the same WHSInventoryItemSetElement record as the stock issuance. Finally, the inventory is re-reserved using the PhysicalReservation type WHSInventoryTransaction record at the site/warehouse/status/location level.
As the final work step is completed, we see the work moved to a closed state:
The same model is used to move inventory in this last step, and the data model is updated as such to reflect how this occurred:
Again, the process is kicked off by the removal of the physical reservation at the site/warehouse/status/location storage dimensions. Then stock is issued from the user location and license plate storage dimensions, along with the batch (represented by a new WHSInventoryItemSetElement record containing the batch ID), and finally, the stock is received at the final work location (BAYDOOR).
From the user's perspective, aside from the performance, they see no changes. Nothing about the execution of the work has changed and nothing in the system is different from a day-to-day operations perspective.
A new warehouse transactions form is available from the work line, allowing users to investigate the warehouse inventory transactions created as per this process:
Conclusion
This is another game-changing feature from Microsoft, something that’s been needed for a long time. The feature is live and mandatory as of 10.0.36, however that doesn’t mean the warehouse inventory transactions are actually being generated and used. You still have to enable the individual work types in Warehouse management parameters, so it is practically still not enabled post 10.0.36 (rightfully so, as auto-enabling this feature could be hugely detrimental to business operations if not properly vetted).
Microsoft is reporting numbers in the realm of 300-900% increases in overall work execution performance depending on volume, uniqueness of inventory dimensions used in work processing, etc. We are in the midst of conducting our own tests with customers and will report back in a new post our observations once we’ve finished this work. But for now, we can definitively say this is a feature worth investigating sooner rather than later.
Relevant links
For more information, check out the following links:
Presentation by Marta Przanowsk & Dmytro Pohorielov from Microsoft | They do an excellent job of introducing the concept and get into some details not covered in this guide.
LinkedIn Post by Michael Pontoppidan - Principal Engineering Manager at Microsoft | Outlining the clear performance benefits offered by the upgrade to warehouse-specific inventory transactions.
Follow up post by InterRadish outlining a practical example for Warehouse-specific inventory translations | Provides real coded examples of how to practically translate a highly customized code base into this new model.