Allowing physical negative inventory may have undesirable consequences in inventory accounting, especially if the inventory costing principle is Actual and the valuation method is either FIFO or Weighted average.
Most of the issues that are related to physical negative inventory can be mitigated by using the correct configuration and maintenance of data.
The following table lists the required setup for the Item model groups.
The purchase from the supplier always takes place at a unit cost of 7,500.00.
The following table lists the events as they occur, in chronological order.
The system starts issuing from inventory at cost per unit of 18,750.00 even though the cost of purchase has not exceeded 7,500.00.
Why does this happen?
In order to explain this in better detail, let’s add a few more columns on the rightmost side, in green. These new columns represent the inventory balance after posting the specific transaction. The inventory balance is also known as InventSum.
The issue is that the inventory balance of 1 piece at 18,750.00 is overvalued because the item has never been purchased at a cost higher than 7,500.00. The reason for this overvaluation is that the first issue transaction leaves inventory at a cost per unit of 0.00. The wrong cost estimation will continue to ripple through the following transactions.
The only way to get the inventory balance back in sync is to run either the Recalculation or Inventory close jobs.
The Inventory close will apply the selected Inventory model, in which case is FIFO, and then adjust the cost on the issue transactions accordingly.
Note: If the inventory balance is negative when executing the inventory close, the balance will not be adjusted. A full adjustment can only occur when the balance is positive, and enough receipts exist that can adjust the issues.
By default, all items should have an active cost. If you plan to allow temporary physical negative inventory, which is a valid scenario in certain business, it’s essential to apply an active cost before creating any transactions on the item.
An inventory dimension can have a Physical value and a Financial value. The setting of the Physical value controls whether a dimension is active for Inventory management and Warehouse management. The setting of the Financial value controls whether a dimension is active for Inventory accounting in Cost management.
Note: An inventory dimension can have an active Physical value but no Financial value. However, it can’t have an active Financial value but no Physical value.
The term cost object was introduced in Microsoft Dynamics 365 for Finance and Operations, Enterprise edition. It represents a key concept that is used in the management of business costs. A cost object is an entity that costs and quantities accumulated for. For example, a cost object entity can be either a product or product variants, such as variants for style and color.
A cost object is derived from the item ID and the inventory dimensions that have an active Financial value.
There are three groups of inventory dimensions: product, storage, and tracking. Each inventory dimension can have a set of dimensions associated with it. For each dimension, you can set up the following inventory dimension values.
When an item is created, a set of inventory dimension groups can be assigned to it. The following table shows how you can define a cost object.
In the following example, the cost objects are defined by Item + Color + Site.
The inventory objects can be used to report the physical quantity at any level in the warehouse that is defined by Item + Color + Site + Warehouse.
It’s crucial that you understand the concepts. The configuration and implementation of these concepts have a significant impact on the whole system, especially in Inventory management and Cost management.
After the configuration is implemented, it’s almost irreversible. Any change will require significant resources and will affect system usage itself.
In the rest of the document, we will use the Speaker item as an example. The inventory valuation method is set to Moving average.
After a few transactions have been posted, the following inventory transaction entries are generated in the Inventory subledger.
The inventory close job was run as of January 31, 2017. Because the inventory valuation method was Moving average, no adjustments were posted.
As part of the fiscal period–end process, an Inventory value report that shows the ending inventory balance in quantity and value is required. To meet this requirement, the inventory value report framework was introduced. The framework lets you create custom reports by including more data points that depend on the type of business. It also lets you define the level of aggregation for cost objects.
Note: The inventory value report is designed to print only the values per cost object or aggregations of cost objects.
You create an Inventory by cost object report, based on the configuration in the following table.
The report will look like this.
Note: The Warehouse column will remain blank, because the Speaker item doesn’t have any cost object that includes the Warehouse dimension. Inventory dimension Warehouse is only set to Physical.
To meet the customer’s request, you could configure the storage dimension group differently. In this case, the Warehouse dimension is configured so that it has a Financial value.
This configuration affects how the Speaker item is handled by the system. The cost object and inventory object now have the same level of granularity.
The configuration also directly affects the inventory valuation. In this example, the FIFO, Weighted average, or Moving average inventory valuation method will be applied per cost object, and the overall result will differ.
The result will also differ when the Inventory value report is run by using the same configuration that is described in the previous section.
The Warehouse column now has a value, and the inventory value is 26.00 instead of 24.00.
Note: When you activate the Financial value for the Warehouse inventory dimension, you might affect performance. All transfers between warehouses are now considered financial movements, and financial movements can cause cycles in the Inventory close job. If the Warehouse inventory dimension is used only to physically track inventory, these will be closed as non-financial transfers before the cost calculation begins and the changes of cycles reduced.
You can create a custom report that sums inventory transactions and settlements by InventDim ID.
The old Physical inventory by inventory dimension report was designed for that purpose. In the report dialog box, users could select any inventory dimensions, regardless of whether they were part of the defined cost objects.
This approach works, provided that the inventory dimensions that you select are part of the defined cost object. However, if you select an inventory dimension that isn’t part of the cost object, the report starts to print incorrect results.
The following table shows the result of printing balances per item and inventory dimensions.
Note: The inventory cost is calculated at a level above the inventory dimension and warehouse. Therefore, the cost on issue transaction from warehouse WH11 explains why the inventory value per warehouse can become negative.
If the value of a physical location must be reported, a sum of transactions per location, as described in the previous section, isn’t the solution.
The correct approach is to calculate the value per location by using the following simple formula:
Value = Cost object, cost × physical object, quantity
In Microsoft Dynamics AX 2012 R3, a new report that is named Inventory aging was introduced. As the name of the report implies, this report does more than just report the value by physical location. It can also show the age of the current inventory in the user-defined buckets.
In the report dialog box, enter the following information.
The following table shows only the first section of the Inventory aging report, but the user-defined buckets have been omitted.
If your organization must provide inventory value by any physical location, you don’t have to update the current configuration of inventory dimension groups. This change can be very intrusive, and also affects the cost calculation and performance. We also don’t recommend that you build a custom report for this purpose.
The Inventory aging report is designed to calculate the cost per cost object and then can apply it to any physical level that is selected on the report. This report is designed to automatically detect the level that the cost object is defined at per item. It then applies the formula to calculate the value by physical location.
Cumulative update 13 for Microsoft Dynamics AX 2012 R3 is now available for download on Lifecycle Services, PartnerSource and Customersource. In this blog post, we will give you an overview of the feature improvements for warehouse and transportation management. If you want more details about the release of CU13, see the Dynamics AX In-Market Engineering blog. The knowledge base article for Cumulative Update 13 is KB4032175.
This is a backporting of an enhancement added to a later version of the product.
The traditional way of using the system is still supported.
For more informatin, see Set up short picking item reallocation.
For more information, see: Product confirmation for cluster picking.
A transfer order that is released to warehouse will generate work of the type Transfer issue and this work can then be picked from the production output location and put to a location that is determined by the Transfer issue location directive for work.
In the latest version of Dynamics 365 for Finance and Operations, Enterprise Edition we put a lot of effort to make it easier to create initial configuration of the Cost Accounting module.
Take a look how simple it is!
We last looked at the Warehouse Mobile Devices Portal (WMDP) in detail in a series of blog posts here, here, and here. The last one covered how to build custom solutions and walked through building a new sample workflow for the WMDP. This post will be updating that sample to cover some of the changes that have occurred with the Advanced Warehousing solution and the Dynamics 365 for Finance and Operations – Enterprise Edition warehousing application.
The Warehouse Mobile Devices Portal (WMDP) interface, which is an IIS-based HTML solution (described in detail here), is being deprecated in the July 2017 release of Dynamics 365 for Finance and Operations (see deprecated features list here). Replacing this is a native mobile application shipping on Android and Windows 10 devices. The mobile app is a complete replacement for the WMDP and contains a superset of capabilities – all existing workflows available in the WMDP will operate in the new mobile app. You can find more detail on the mobile app here and here.
The process for customizing the new mobile app is largely unchanged – you can still utilize the X++ class hierarchy discussed in the previous blog post. However – I want to walk through some of the differences that enable customizations to exist as purely extensions. The previous solution required a small set of overlayered code. Moving forward this practice is being discouraged and we recommend all partners and customers create extensions for any customizations.
As before, we will be focusing on building a new workflow around scanning and weighing a container. The inherent design concept behind the Advanced Warehousing solution is unchanged – you will still need to think and design these screens in terms of a state machine – with clear transitions between the states. The definition of what we will build looks like this:
Just as in the previous blog post – to add a new “indirect work mode” workflow we will need to add values to the two enumerations WHSWorkExecuteMode and WHSWorkActvity. The new enum names need to match exactly as one will be used to instantiate the other deep inside the framework. Note that both should be added as enumeration extensions built in a custom model. Once this has been done it will be possible to create the menu item in the UI – since the WHSWorkActvity enumeration controls the list of available workflows in the UI:
You can see the extension enumeration values in the following screenshots:
The core logic will exist within a new class you will create, which will be derived from the WhsWorkExecuteDisplay base class. This class is largely defined the same way as the WMDP-based example, however there is now a much easier way to introduce the mapping between the Execute Mode defined in the Menu Item and the actual class which performs the workflow logic – we can use attributes to map the two together. This also alleviates the need to overlay the base WHSWorkExecuteDisplay class to add support for new derived classes (as the previous WHSWorkExecuteDisplay “factory method” construct forced us to do).
The new class will be defined like this:
class conWhsWorkExecuteDisplayContainerWeight extends WhsWorkExecuteDisplay
Note that all the new classes I am adding in this example will be prefixed with the “con” prefix (for Contoso). Since there is still no namespace support it is expected partner code will still leverage this naming scheme to minimize naming conflicts moving forward.
The displayForm method is required – and acts as the primary entry point to the state machine based workflow. This is completely unchanged from the previous example:
class conWhsWorkExecuteDisplayContainerWeight extends WhsWorkExecuteDisplay
container displayForm(container _con, str _buttonClicked = '')
container ret = connull();
container&nbsp;&nbsp;&nbsp;&nbsp;con = _con;
pass = WHSRFPassthrough::create(conPeek(_con, #PassthroughInfo));
con = conDel(con, #ControlsStart, 1);
ret = this.getContainerStep(ret);
ret = this.getWeightStep(ret, con);
ret = this.processWeightStep(ret, con);
ret = this.updateModeStepPass(ret, WHSWorkExecuteMode::WeighContainer, step, pass);
A detailed analysis of this code can be found in the previous blog post – we will skip forward to the definition of the getContainerStep method, which is where the first screen is defined. The two methods used to define the first screen are below:
private container getContainerStep(container _ret)
_ret = this.buildGetContainerId(_ret);
step = conWeighContainerStep::EnterWeight;
container buildGetContainerId(container _con)
container&nbsp;&nbsp; ret = _con;
ret += [this.buildControl(#RFLabel, #Scan, 'Scan a container', 1, '', #WHSRFUndefinedDataType, '', 0)];
ret += [this.buildControl(#RFText, conWHSControls::ContainerId, "@WAX1422", 1, pass.lookupStr(conWHSControls::ContainerId), extendedTypeNum(WHSContainerId), '', 0)];
ret += [this.buildControl(#RFButton, #RFOK, "@SYS5473", 1, '', #WHSRFUndefinedDataType, '', 1)];
ret += [this.buildControl(#RFButton, #RFCancel, "@SYS50163", 1, '', #WHSRFUndefinedDataType, '', 0)];
Note that I am using a class to define any custom constants required for the Warehousing logic. This was typically done with macros in the previous version – but these can cause some issues in extension scenarios. So instead we are encouraging partners to define a simple class that can group all their constants together – which can then be referenced as you see in the code above. The only area where this does not work is in attribute definitions – this will still need a Macro or String definition. Here is mine so far for this project:
public static const str ContainerId = "ContainerId";
public static const str Weight = "Weight";
The other important thing to notice in the above code is that I have explicitly defined the data type of the input field (in this case extendedTypeNum(WHSContainerId)). This is important as it tells the framework exactly what type of input field to construct – which brings us to the new classes you need to add to support the new app functionality.
In the previous version of this blog we discussed the fact that since we are adding new fields to the warehousing flows that are not previously handled in the framework we must modify (i.e. overlayer) some code in the WHSRFControlData::processControl method. This allows the framework to understand how to handle the ContainerId and Weight fields when they are processed by the WMDP framework.
In the new model these features are controlled through two new base classes to customize and manage the properties of fields. The WHSField class defines the display properties of the field in the mobile app – and it is where the default input mode and display priorities are extracted when the user configures the system using the process described here. The WhsControl class defines the logic necessary for processing the data into the field values collection. For my sample, we need to add support for the ContainerId field – so I have added the following two new classes:
class conWhsControlContainerId extends WhsControl
public boolean process()
class conWHSFieldContainerId extends WHSField
private const WHSFieldClassName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "@WAX1422";
private const WHSFieldDisplayPriority Priority = 65;
private const WHSFieldDisplayPriority SubPriority = 10;
private const WHSFieldInputMode&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputMode&nbsp;&nbsp; = WHSFieldInputMode::Scanning;
private const WHSFieldInputType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputType&nbsp;&nbsp; = WHSFieldInputType::Alpha;
protected void initValues()
this.defaultName&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = Name;
this.defaultPriority&nbsp;&nbsp;&nbsp; = Priority;
this.defaultSubPriority = SubPriority;
this.defaultInputMode&nbsp;&nbsp; = InputMode;
this.defaultInputType&nbsp;&nbsp; = InputType;
Obviously my conWhsControlContainerId class is not doing much – it is just taking the data from the control and placing it into the fieldValues map with the ContainerId name – which is how I will look for the data and utilize it later in the system. If there was more complex validation or mapping logic I could place that here. For example, the following is a snapshot of the process logic in the WhsControlQty class – this manages the logic for entering in quantity values from the mobile app:
public boolean process()
Qty qty = WHSWorkExecuteDisplay::str2numDisplay(data);
if (qty &lt;= 0)
if (mode == WHSWorkExecuteMode::Movement &amp;&amp; WHSRFMenuItemTable::find(pass.lookup(#MenuItem)).RFDisplayStatus)
if (mode == WHSWorkExecuteMode::Movement &amp;&amp; fieldValues.exists(#Qty))
pass.parmQty(qty ? data : '');
fieldValues.parmQty(qty ? data : '');
//When 'Display inventory status' flag is unchecked, need the logic for #FromInventoryStatus and #InventoryStatusId
The buildGetWeight method is very similar to the previous UI method – the only real difference is the Weight input data field. Note that we don’t need to define a custom WHSField class for this field because it already exists in the July Release.
There was another minor change that was necessary before I could get the expected behavior, and it points to a slight change in the framework itself. In the previous version of the code when I reported that the weight was successfully saved I did so with an “addErrorLabel” call and passed in the WHSRFColorText::Error parameter to display the message at the top of the screen. This same code in the new warehousing app will now cause the previous step to be repeated, meaning I will not get the state machine transition I expect. Instead I need to use the WHSRFColorText::Success parameter to indicate that I want to display a status message but it should not be construed as an error condition.
container processWeightStep(container _ret, container _con)
containerTable = WHSContainerTable::findByContainerId(pass.lookupStr(conWHSControls::ContainerId),true);
containerTable.Weight = pass.lookupNum(conWHSControls::Weight);
_ret = conNull();
&lt;strong&gt; _ret = this.addErrorLabel(_ret, 'Weight saved', WHSRFColorText::Success);
_ret = this.getContainerStep(_ret);
_ret = conNull();
_ret = this.addErrorLabel(_ret, 'Invalid ContainerId', WHSRFColorText::Error);
_ret = this.getContainerStep(_ret);
The mobile app as well as the AOS perform a significant amount of caching, which can sometimes make it difficult to add new classes into the framework. This is because the WHS code is heavily leveraging the SysExtension framework. I find that having a runnable class included in the project which simply calls the SysExtensionCache::clearAllScopes() method can help resolve some of these issues.
At this point I have a fully functional custom workflow that will display the new fields correctly in the mobile app. You can see the container input field and weight input below. Note that if you want to have the weight field display the “scanning” interface you can change the “preferred input mode” for the Weight EDT on the “Warehouse app field names” screen within the Dynamics 365 environment itself.
The Dynamics 365 for Operations project for this can be downloaded here. This code is provided “as-is” and is meant only as a teaching sample and not meant to be used in production environments. Note that the extension capabilities described in this blog are only available in the July Release of Dynamics 365 for Operations and Finance or later.