Dynamics AX 2012 R3 features a new warehouse management solution. An essential part of this solution is the completely new reservation engine that was designed to separate order reservations from the reservations related to warehouse work. This allows the movement of goods within the warehouse even if they are already reserved. As a result, some of the quantity fields in the InventSum table may now produce incorrect results. Let me illustrate the problem with an example before we discuss the correct APIs for getting the available and reserved inventory quantities.
Imagine the following scenario
- There is an item that uses warehouse management processes
- The following physical inventory exists for the item (some dimensions like site, inventory status, license plate are irrelevant and are omitted throughout the scenario):
Warehouse: W1, Location: L1, Physical inventory: 6
Warehouse: W1, Location: L1, Physical inventory: 6
- A sales order with one line is created and reserved:
Warehouse: W1, Quantity: 5
Warehouse: W1, Quantity: 5
- The sales order is released to warehouse. As a result warehouse work is created:
Work type: Pick, Warehouse: W1, Location: L1, Quantity: 5
Work type: Put, Warehouse: W1, Location: Baydoor, Quantity: 5
Work type: Put, Warehouse: W1, Location: Baydoor, Quantity: 5
- Now we have the following inventory transactions:
- So once we roll up the transactions into the InventSum table the contents of the table will look like this:
- And now let’s calculate on hand quantities for warehouse W1 like we used to do it in versions prior to AX 2012 R3 (sum up InventSum quantities for warehouse W1):
At this point you will most likely exclaim: “Wait a second! This makes no sense! We just wanted to ship 5 items and we have 6 items on stock. One item should still be available! And how did we manage to physically reserve 10 items when we only have 6 items in the warehouse!”
And this is exactly the reason why summing up available and reserved quantities from the InventSum table may produce incorrect results for items that use warehouse management processes.
But this still doesn’t explain how we managed to physically reserve 5 items for the sales and another 5 items for the pick work when we only had 6 items on stock. The reason is that the sales reservation was taken on the warehouse level of the reservation hierarchy to ensure that we keep enough on hand in the warehouse to ship the reserved quantity. The pick work reservation was taken on the location level and it ensures that the reserved quantity will still be physically available when the warehouse worker comes to the warehouse location to pick it. Work reservation does not affect physical availability on the warehouse level. This means that the new reservation engine will be able to figure out that we still have one item available on the warehouse level.
Here is another important example that demonstrates how reservations that are done on the warehouse level affect available quantities on the location level:
- The following inventory transactions exist for the item
- After the transactions are aggregated the InventSum table contains the following information
Now if you look at the available quantity for location L2 you will most likely ask: “But how is it possible that 20 items are available on location L2 when we only have 30 in the warehouse and 25 are already reserved? Only 5 items can possibly be reserved (e.g. for sales) on L2!”
The new reservation engine takes care of the issue. For each of the levels of the reservation hierarchy it stores available and reserved quantities in the WHSInventReserve table which allows the engine to calculate availability correctly.
So now that it’s clear why using the InventSum table directly is incorrect it’s time to describe the correct approach. To work with available quantities regardless of whether the item is using warehouse management processes or not the InventIAvailability interface was introduced.
The following list contains the InventSum fields and methods that should not be used directly and the corresponding InventIAvailability methods that should be used instead:
Corresponding InventIAvailability method
To support warehouse management processes you should remove any references to the fields and methods described above and replace them with appropriate calls to InventIAvailability.
Two major APIs were introduced for retrieving item availability:
The InventAvailabilityProvider class provides availability information for on hand inventory based on various criteria. It can be used in business logic, e.g. if you need to check whether there is enough on hand available before you can proceed with an inventory operation. Following is an example of using the API:
availPhysical = InventAvailabilityProvider::findByItemDim(inventTable, inventDim).parmInventAvailability().availPhysical();
You can find more information in the XML documentation of the InventAvailabilityProvider class.
In scenarios where you want to display available quantities on a form you can use the InventAvailabilityFormCache class. It is responsible for retrieving and caching available on hand quantities per item per inventory dimension combination. To use it on a form you need to:
- Declare an InventAvailabilityFormCache field in classDeclaration of the form.
- Initialize the cache field in the init method of the form:
public void init()
inventAvailabilityFormCache = InventAvailabilityFormCache::construct();
- Flush the cache in the executeQuery method of the primary data source that the InventSum data source is joined to:
public void executeQuery()
- Create display methods for available on hand fields that need to be displayed on the form.
If InventDim is joined to InventSum then the display methods should be declared on the InventSum data source:
public display InventQtyReservPhysical reservPhysical(InventSum _inventSum)
return inventAvailabilityFormCache.availabilityFromSumJoinedWithDim(_inventSum, inventDim_ds).reservPhysical();
Note that the availabilityFromSumJoinedWithDim method should be used.
Otherwise, if InventSum is joined to InventDim then the display method should be declared on the InventDim data source:
public display InventQtyReservPhysical reservPhysical(InventDim _inventDim)
return inventAvailabilityFormCache.availabilityFromDimJoinedWithSum(_inventDim, inventSum_ds).reservPhysical();
Note that the availabilityFromDimJoinedWithSum method should be used.
For an example in R3 please see the InventOnhandItem form.
The InventOnHandQty class is one of the most frequently used APIs for retrieving on hand information in business logic. It has been modified to support warehouse management processes and no code upgrade is required for code that references the InventOnHandQty class.
The standard reservation engine is used for items that do not use warehouse management processes. Thus referring to InventSum directly will produce correct results if your solution does not need to support warehouse management processes (Warehouse and Transporation management configuration key under Trade is turned off). So in this case upgrading code as described above can be deferred as long as none of the AX installations with your solution use warehouse management processes.
The service has been updated to provide correct results for items that use warehouse management processes. However you need to keep in mind that summing up available or reserved quantities that were retrieved through the service is not correct (see the first scenario in this blog post).
If your solution refers to the available or reserved quantity fields from the InventSum table using direct SQL then you will need to implement the same algorithm that is implemented in the InventAvailabilityProvider class:
- If the item does not use warehouse management processes then get the total quantities from the InventSum table as before.
- If the item uses warehouse management processes then you can use the sp_WHSOnHand stored procedure to get AvailPhysical and AvailOrdered quantities.
- If the item uses warehouse management processes then you can take ReservPhysical and ReservOrdered quantities from the WHSInventReserve table. See the implementation in the WHSInventReserveQty class.
Do you know if there is any way to populate the WHSInventReserve table with the proper values? We are exploring using the warehouse management in R3 and find that this table is empty and holds no revervation info. The R2-R3 upgrade process does not populate it and the official line we have been getting is that warehouse management cannot be turned on for existing businesses. We would have to invoice or cancel all sales orders, purchase orders, production orders and then turn it on - which is an unworkable requirement..
Unfortunately at the moment there is no straightforward upgrade story for moving from WMS/WMS2 to the new warehouse management solution. It is a migration rather. The reason why inventory transactions need to be closed (sales order invoiced e.t.c.) is because the storage dimension group on every item that will be used in the new warehouse management processes will have to be changed. The new storage dimension group will have two extra dimensions enabled (License plate and Inventory status). You'll need to figure out a way which License plate/Inventory status values to assign to your existing on hand.
We have the migration story on our backlog. Let me try to find more information about it and get back to you.
This seems a ridiculous situation -irrespective of reservation the item dimension group has to be changed for all items and we have history with a different dimension configuration in the same database and as Tom mentions for open orders the situation is compounded. For clients who upgraded or implemented / re-implemented less than year back to be hear this is not acceptable and will hand an own goal to competition..
Unfortunately, as I mentioned before, there is no straightforward migration story yet and there is no definite timeline for when it will be supported.
Thank you for a very useful article!
I think you should be more explicit on what is in, and what is out when talking about migrating to R3.
I believe that "Warehouse management I" is still supported with the WHS functions. So basic picking, and receiving is still available.
Only the functions related to "Warehouse management II" are/should be disabled. These include such features as "Pallet management", and "Advanced" warehouse management such as stock zones and stock areas, with intelligent put-away strategies.
In terms of migration, changing Pallet ID to Licence plate doesn't seem to me to be a big problem. I would be more worried about the general warehouse flows and processes, and as far as I can see this would be a reimplementation - the underlying concepts in WMS II and WMS R3 are too far removed for a simple switch-over
Vanya, can you please confirm that I have understood correctly?
You are absolutely correct. As long as you want to keep using WMS I or WMS II no code or data upgrade is needed. However If you want to take advantage of the new Warehouse management processes then we are talking about a reimplementation. We have plans about making this type of migration as straightforward as paossible, however there is no clear time line for this improvement. More specifically, it will not be released in the near future.
It seems that there should be a way to rebuild WHSInventReserve, in the same way the consistency check works on InventSum. If there were a rebuild option for WHSInventReserve it would solve two problems: any data errors (our situation) or migration requirements from WMSII to WAX.
There is a class that can change a hierarchy (which seems to use InventSum as a base, and not the transactions) that isn't too far off simply rebuilding the table.
thank you for your very useful article.
I have another question outside this specific Topic, but also concerning reservation. Maybe you could answer this: My theoretical understanding of reservation hierarchy is: first i can reserve the item only in a site. while i know the specific warehouse i can "move" the reservation to this warehouse. Do you know if it's possible? If yes, how does it work?
Thank you ver much.
Out of the box it is not possible to achieve what you describe.
We are working on a blog posting with more details of the inner workings of the reservation system that will include tips and hints on how to modify the system to better control the levels that the reservations occur on.
During Technical conference in 2013 I gave a presentation on the reservation system. This presentation included a customization that showed how you could move a reservation from the warehouse level to the status level, which is almost the same as you want to do. The move was achieved by unreserving and re-reserving again with a different reservation strategy.
If you have interest in this, I can try to upload it somewhere.
Lennart Conrad (Microsoft).
I would be very great if you could provide this presentation somewhere to download it.
Matthias (working for Microsoft Gold Partner)
The presentation should be available here : mbs.microsoft.com/.../Technical Deep Dive of the Key Features in the New WMS Solution Video
thank you very much for your support. I assigned to this page and now I have some more documentation:-)
I need the same as Simon.
I prepared and run classes to change storage dimension group,
mark items as WMS items
prepared and run classes to update dimension for all transaction (licence plate and Invent status added)
now Invent sum values directly in the table is ok,
but WHSInventReserve have wrong values.
I strongly need class to rebulid WHSInventReserve same as InventSumRecalcItem for inventSum.
Can anybody help??
There is a hotfix KB3064487
afte you apply it, the inventsumRecaltItem class will take care and recreate the WHSInventReserve Table for that item.
invetSumRecalcItem = new InventSumRecalcItem('itemid', false, checkfix::fix);
Thank you Dimitar!
That's exactly what I need:)
As we can see on KB release date it's pretty new! I almost prepared my own class similar to this recalculation but MBS was faster:)
MBS guys finally prepared something useful!