Code highlighting

Sunday, October 18, 2020

[Tutorial] Piece by piece picking process with Advanced Warehouse Management in Dynamics 365 SCM


We are often asked - is it possible to configure the system to require the workers on the floor to scan each item they are picking, to ensure a more accurate picking operation where multiple same/similar items need to be picked. This is, for example, very common in the Retail industry, or in smaller distribution centers dealing with apparel or footwear. In this blog post I will demonstrate exactly that, so read on.

Let's quickly go over the setup required.


In this walkthrough, I will be picking a single sales order (This works just as well for Transfer orders), which has 4 sales lines, each for a different quantity of a product variant varying by size and color. For this example, I've chosen to use a product, which represents a box of shoes. Here is how the order looks:

Piece picking sales order
Sales order with 4 lines

DemoShoe is a product master with Size and Color product dimensions, which has the different product variants defined, and is configured to use Advanced warehouse management.
It has sufficient inventory, some in BULK locations, and some in FLOOR locations. The only difference for this example is whether or not the locations are license plate controlled, and does not have any impact on the core scenario.

On-hand availability for DemoShoe

Now, the important bit - since we plan to be scanning in the products one by one, we need to properly define the bar codes for the different product variants. This is shown below:

Product variant bar code setup for DemoShoe

Obviously, you want to define a different bar code for each product variant.

You also need to set the Quantity/Unit pair according to the picking process - in our case, since we want to be picking one box of shoes with each scan, it will be 1 ea. 

And, very important, you need to enable this bar code for scanning, so that it'll get used when we scan in the value on the mobile device. 

Note. The Scanning field is usually shown on the General tab, I've personalized the page to show it in the grid just for convenience of the screenshot.

After we release the sales order to warehouse (the configuration for this is not relevant for the demo), we get the following work order generated.

Work order for DemoShoes

For processing this work, we will use a standard User directed mobile device menu item. It is configured to generate the target license plate, but that's irrelevant for the demo. 

Mobile device menu item for sales order picking

What is important however is to configure the work confirmation for this menu item, enabling the Piece picking option, as shown below.

Here, I have specified that a maximum of 4 piece picking scans will be required, but if I need to pick more, I can just enter the remaining quantity in full instead. 

I have also enabled location confirmation, and product confirmation is enabled automatically with piece picking (the product confirmation field is the one used to scan in each product variant bar code).

Work confirmation for Pick operation


1. We start by scanning in the ID of the work order

1. Work ID

2. We are asked to pick the first work line, and start by confirming we have indeed reached the needed location, FL-015

2. Location confirmation

3. As FL-015 is a License plate tracked location, we need to scan in the license plate we are picking from, in this case, LP_Demo_01

3. License plate scan

4. Now is when we reach the product confirmation screen, and where the magic starts. 
We scan in the bar code for the correct variant, 38 Black

4. Picking first shoe box

5. We are brought back to the same screen again, asking us to scan in the product. 
However, if we go to the details tab, we can see something has changed. 
We have now 1 of 2.00 confirmed
That means our input was in fact registered, and we just need to keep scanning the next variant of the 2 required.

5. Piece picking in action - qty confirmed

6. We scan in the second box of 38 Black shoes, and are directed to specify the Target LP we are going to move the items on. In this case, it's automatically generated based on menu item setup, so we just confirm.

6. Target LP

Now, you might have noticed, that the data shown on the main screen wasn't super helpful for us, as we did not immediately at a glance see how many items we have already scan-confirmed. Maybe not an issue, but for the purpose of the demo, let's adjust it, so that the piece picking quantity confirmation is more prominent. 

We can do this by modifying the display priority of the corresponding fields in the Warehouse app field priority form. An example is shown below

Mobile app field priority higher for piece pick qty

I have kept the item description and product dimensions high enough to help visually confirm the size and color of the product being picked.

7. With that out of the way, let's re-enter the picking flow and observe the updated main screen information, when picking the second work line. I've skipped location and license plate confirmation screens

7. New visual for piece picking

8. Now we've reached picking from a non license plate tracked BULK location. The process is exactly the same, minus the scan of the license plate to pick from.

8. Piece picking from a BULK location

9. You might have noticed that the last work line was for a total quantity of 5 pairs of 41 White shoes. 

This exceeds the maximum set during work confirmation, meaning that I am redirected to a different screen after scanning 4 pairs, where I need to enter the remaining quantity using a standard quantity field instead.

Now, 4 is an arbitrary number I set as maximum for this demo. In reality, most will probably have this higher, only to account for certain really larger volume picks.

9. Remaining picking quantity exceeding max piece picking qty

10. Once the remaining quantity is entered (in our case it was just 1 remaining item), all the picks are complete, and we are directed to do the Put of all 10 pairs of shoes we picked.

10. Put to Baydoor

Note that at any point in time in the process, we could switch to the Details tab and manually enter the picking quantity by selecting the little edit icon next to Qty

This is in a way a back door, so I do not recommend that you use it, but thought I would mention it, also to get feedback on how useful this is, and if that's something your company uses on a frequent basis.

Backdoor - Edit Qty field


That's it. Now you're a master of piece by piece picking in shipping operations when Advanced Warehouse management is used. 

Does this functionality meet the mark? Let us know how you use it and if anything is missing!

In the next post we'll discuss what options are available for piece by piece scans in the receiving warehouse process.

Wednesday, July 15, 2020

Flights vs Feature management - practical overview


The primary purpose of flights and features both is to implement a controlled roll-out of new functionality into the product, so as not to disrupt existing business operations. One of Microsoft's primary goals with OneVersion is to ensure we do not break anyone.

By their nature, both the flights and the features are transient in nature, i.e., they will be removed from the product after some time, leaving the new functional behavior as default going forward.

Let's now break it down a bit more, looking closer at what a flight is, and what a feature is, and who has control over them, and when they are enabled/disabled.
  • A flight is a switch, which controls a certain, usually small, piece of business logic in the product, leading it one way or the other. Microsoft is in control of the state of the flight for customers in PROD. The decision to enable or disable a flight, as long as that does not impact the functionality of the environment, is not initiated by the company in most cases. Flights are, generally speaking, always OFF by default.
  • A toggle is a business logic / X++ construct, that is typically based on flights. Similar to flights, it is either On or Off. So what's interesting here is what the default out of the box state of the toggle is.
    • An "enabled by default" toggle, or, as it's more commonly known, a Kill Switch, is used for smaller changes, and the product behavior is changed right away, with no additional action from the users. Kill switches is a way for Microsoft to introduce bug fixes, yet safeguard against potential functional regressions, and as such, ensure we do not break anyone. If controlled by a flight, enabling the flight would turn the toggle and the new behavior off. Example: WHSShipmentConsolidationLoadLineLoadIdToggle
      • A kill switch will get removed after around a year from the moment of introduction, making the new behavior apply to everyone always from then on. 
    • A "disabled by default" toggle is used much less frequently
      • To enable certain troubleshooting logic that is performance intensive and thus undesirable in PROD. Example: WHSInventOnHandForLevelCalculatorMissingSiteIdLogToggle
      • To hide incomplete or work-in-progress features, so they cannot be enabled in PROD. Examle: WHSDockInventoryManagementFeature
      • Enabling the flight would mean enabling the toggle
  • A feature is, in a similar way, a toggle, which controls a usually larger piece of business logic, and is typically controlled by the superusers in the company. For this, they use the Feature management dashboard. Example: WHSWaveLabelPrintingFeature
    • Features go through a life cycle, where they are
      • In Development
        • Not available for use by end users in PROD
      • Private preview
        • Available for use by end users, including in PROD, but only based on prior agreement with Microsoft
        • Linked to a flight, which Microsoft needs to enable for the feature to appear
      • Public preview
        • Available for use by end users in PROD, based on decision to enable and configure the feature by superusers.
      • Generally available / Released
        • This is now the default behavior of the system, everyone has it. Depending on the feature, can still be configured "off".
    • There are corresponding kill switches in place to disable new feature behavior if a severe issue is discovered with the feature. Only reserved for very rare cases.
    • You can read more about Feature management here.

In an ideal world, partners/superusers should not need to know/worry about flights, and should control the behavior of the system solely through the Feature management dashboard. 

All of the above applies to PROD environments. The story with DEV/UAT environments is a bit different today for flights, where the partner/superuser has much more control. 

Note. Self-Service Deployment environments are controlled a bit differently, where above is also true for UAT type environments.

DEV / UAT environments

You can control the state of flights through the SysFlighting table. This is sometimes referred to as "static flighting". 
It's nicely described in an old post I found here, so I'll just paste the one line SQL statement you can use here instead:


It's really as simple as that, but remember to evaluate, if the toggle is enabled by default or disabled by default before you start adding flights there. Maybe the logic is already doing what you want.

Tip For Inventory, Warehouse and Transportation toggles it is very easy, as you can see it from the name of the class the toggle extends from:

  • WHSEnabledByDefaultToggle
  • WHSDisabledByDefaultToggle

FAQ / Typical scenarios

I enabled the flight in UAT/GOLD by inserting into SysFlighting, but when going live, the flight in PROD is not enabled. Microsoft, please insert the record for me.

Flights in PROD are controlled in a completely different way, not through the SysFlighting table, and are also not enabled on customer's request, but only when it makes sense after evaluation by Microsoft.

Important. You should not expect that just because you turned on a flight in UAT/DEV, and liked what you saw, you'll get the same in PROD. Microsoft can reject your request for enabling particular flighted (private preview) behavior in your PROD environment.

If you discovered what you believe to be a functional or performance regression, and you managed to link it to a particular kill switch, please log a support request with detailed repro steps, so Microsoft can evaluate and fix. We will then typically enable the corresponding flight to mitigate short term.

I'm trying to disable a flight but it's not working. I inserted a row in SysFlighting and marked it as Enabled=0, but system still behaves in the same way as before

Flights are, generally speaking, only Enabled. So it just really depends on what kind of toggle this is in X++. If this is a "kill switch", enabling the flight will revert the behavior to how it was before the changes. If this is a private preview feature, enabling the flight will enable the new behavior (or simply show the feature in the Feature management dashboard)

This is easy to understand if you look at the actual implementation in the WHSEnabledByDefaultToggle class.
public boolean isEnabled()
    if (flightName == carbonFlightName)
        return !isFlightEnabled(flightName);

This is basically reversing the condition for the flight. Meaning, enabling the flight will disable the toggle.

I enabled a feature, but I did not mean to, and now I cannot disable it

Some features are indeed designed in a way, where it is not allowed to disable them. The common reason here is that as part of enabling this feature, or as a result of using the feature for a short time, data was modified, which makes it difficult to revert to the old behavior. 

Also, not all features have a separate dedicated configuration switch in the product, so after you enable the feature, the product will in most cases start behaving in a different way.

So please carefully read the description of the feature, as well as evaluate the consequences of enabling it in UAT, before enabling it in PROD.

Microsoft enabled a private preview feature flight for me, but I still cannot see the feature in Feature management dashboard

Make sure you have clicked on "Check for updates" in the dashboard after 10-15 minutes after the flight was enabled.

Tip Microsoft also has a way of checking if the flight / feature is evaluated as On or Off for a specific environment, which can help you troubleshoot any issues, if it comes to that.

What is the difference between a Feature and regular Module parameters? For example, a Feature in HR - "Filter active positions" (This feature enables a position list filtered to only active positions). Why it is not an HR module parameter?

A feature is meant for controlling the roll-out of functionality, while a configuration parameter is meant for allowing the user flexibility in setting up their system. 

In the specific example above the intention with the "Filter active positions" feature is to expose it to all users (it's available in Feature management dashboard for everyone to see and enable), but in a manner which would not introduce new menu items / forms until this explicit decision is taken by the superuser, so as to ensure any documentation and internal task guides are properly updated beforehand. It is NOT the intention to make this behavior configurable going forward, and all companies will have access to the relevant menu item eventually (note, how the new FeatureClass property is set on it accordingly), while the feature class will be removed from the product. This approach also allows Microsoft to simplify the product, avoiding addition of unnecessary parameters.

That is not to say that both cannot co-exist. A module parameter or even whole new configuration screens can be added for proper setup of a new feature. They will only be exposed to the end users once the feature is enabled in Feature management. But then for the feature to function according to business expectations one or more settings need to be configured. An example of this is WHSShipConsolidationPolicyFeature feature, which you need to configure after enabling by setting up Shipment consolidation policies in the corresponding form.

More questions?

Please leave comments below, and I'll try to clarify!

Thursday, September 19, 2019

[Announcement] New version of Dynamics 365 Finance and Operations - Warehousing released

Our Warehouse Mobile App has been updated to version

Please find below the high-level list of changes coming with the new release:

·        Multiple connection settings now possible
·        Work list filter now disappears when scrolling down
·        Work list filters can now be sorted ascending or descending by clicking on the arrow
·        Now possible to dismiss errors
·        Added log out button to the action menu
·        Multiple bug fixes 

The biggest change that comes with this release is the ability to setup multiple connection settings, which allows to later easily switching between, say, UAT and PROD environments. Great time saver!

If you do not have auto-updates enabled, please go ahead and update manually

If you experience issues with the update, please let us know!


Tuesday, May 21, 2019

[Development tutorial] Sample test + tips for using ATL (Acceptance Test Library) to implement tests in Warehouse management

Hopefully, by now everyone is familiar with the fact that we shipped our internal test framework for all ISVs, partners and customers to use.
We have published pretty detailed documentation about the framework on

I, however, learn much better when looking at samples. We have shipped a couple sample tests in each area with the 10.0.3 release.
In this post, I would like to share another sample test case and walk through the different types of commands possible in ATL, focusing also on the part that drives mobile device flow operations.

Important note

ATL is not meant as a replacement for good quality production code, and should not be used to execute business logic in PROD environments

Sample test

This test will validate a very simple inbound flow where I want to validate I can confirm the putaway location by the location check digit:
  • Create a new purchase order for a WHS-enabled item to a WHS-enabled warehouse
  • Perform the registration of the item through the mobile device
  • Perform the putaway through the mobile device
    • Confirm the location confirmation is shown and is asking for the check digit
    • Enter the check digit of the putaway location instead of the location ID
    • Complete the putaway
  • Validate the work lines are updated to Closed (not really the point of the check digit test, but just to show the capability)

public void confirmLocationWithCheckDigit_SimplePurchOrderOneItem_Success()




 var work =;


 var poPutaway = rf.login().purchaseOrderPutaway().setWork(work).confirmPick();

 poPutaway.parmCheckDigitControl().assertIsEnabled(); // Will automatically happen within set method below
 poPutaway.setCheckDigit(checkDigit); // This will confirm the Put to this location



 this.assertEquals(WHSWorkStatus::Closed, work.parmWorkStatus(), 'Work should be closed');



Looks pretty simple, doesn't it? And does not really require comments, as the code is pretty self explanatory for the most part, "even a functional consultant can read it" :)
A number of things I would like to call out here:
  • Notice the name of the test method. We always try to name the method according to the Given/When/Then pattern (also explicitly called out in the method body), more specifically, When_Given_Then(). Or, for those more familiar with AAA, Arrange_Act_Assert()
    • Note the method name does not start with test. You can still do that, but we prefer being explicit through decorating the method with the SysTestMethod attribute
  • I skipped the test setup part - I'll post that below. Normally that would include steps generic for all tests, while the Given part in here would only contains a few things special to this particular test. In this test, we 
    • create a purchase order line for a small quantity of a WHS-enabled item
    • do the PO receipt through the mobile device, to create the putaway work.
  • There is A LOT of defaulting that happens in these fluent calls. When writing code, you need to pay attention and override any default value. For example, 
    • When setting inventory dimensions for the PO line, I only specify the warehouse, but that in turn sets the Site as part of the business logic. The Inventory status is also defaulted based on the Warehouse parameters. 
    • When logging it to the mobile device in rf.login(), the default worker is used. However you can overwrite that and specify another worker to log in with. 
  • The WMA flows should look like you'd have it on the actual device, with scanner actually sending a caret return aka clicking OK after entry. Note, that defaulting is also supported here, where we just proceed without explicitly specifying a unit
    • Here, however, I used a dedicated method, confirmUnitSelection(), to improve readability. Inside, in the implementation, it's a simple OK button click. 
    • It is possible to override this behavior, by disabling the automatic submission on the flow class. This way, you'll have the ability to for example set multiple controls at the same time before OK'ing, etc. 
  • ATL allows for most areas to rely on either a special entity class, or the underlying record. Generally speaking, we always prefer to use the entity over the record. For example, take a look at how I retrieve the work entity for the putaway work created after registration.
  • Process Guide flows are tested with a different set of classes at this point. We'd be interested to hear your feedback on, which approach is more convenient. 
  • When doing putaway, I also use a "dummy" method, confirmPick() to confirm the pick up of the LP from the RECV location. These methods, however, could be doing some additional validation
    • We have, for example, implemented some like confirmPutToBaydoor(), which will confirm we are in fact in a Put step, and the Location control has a value where it is of type "Final shipping location". Think through these scenarios when extending ATL
  • We can also access the controls shown on the current screen right now, to perform additional validation, for example. I showcase that with the CheckDigit control, simply checking that it is enabled for data entry.
    • This already happens automatically in the next call to setCheckDigit(), so you should consider where you really need this.
    • assertIsEnabled() will also ensure the control is in fact visible.
  • Lastly, I wanted to show how specs are used in a real example, where we in assertExpectedLines() specify the 2 lines we expect to see on the putaway work after execution of the putaway. This allows for really flexible validation of the data, that also is easy to read and understand.
  • Check out how the flow class shows up in the debugger - it displays the XML with the controls, which really helps understand where you are in the flow if something in the test goes very wrong!

Entire test class

Below is the full listing of the xpp class with the test, including variable declarations and setup.
You can also download it from my OneDrive

public final class DEV_PurchaseOrderReceivingAndPutawayScenarioTests extends SysTestCase
    AtlDataRootNode                     data;
    AtlDataInvent                       invent;
    AtlDataInventOnHand                 onHand;
    AtlDataWHS                          whs;
    AtlDataWHSMobilePortal              rf;
    AtlDataPurch                        purch;

    InventTable                         item;
    InventLocation                      warehouse;
    WMSLocation                         putawayLocation;
    AtlEntityPurchaseOrder              purchaseOrder;

    private const WMSCheckText          CheckDigit = '12345';
    private const PurchQty              PurchaseQuantity = 1;

    public void setUpTestCase()

        data = AtlDataRootNode::construct();
        invent = data.invent();
        onHand = data.invent().onHand();
        whs = data.whs();
        rf = whs.rf();
        purch = data.purch();



        item = invent.items().whs();
        warehouse = whs.warehouses().whs();

        putawayLocation = whs.locations().floor();
        putawayLocation.checkText = CheckDigit;


        var poPutawayMenuItem = rf.menuItems().purchaseOrderPutaway();
        rf.menuItems().setupWorkConfirmation(poPutAwayMenuItem.MenuItemName, WHSWorkType::Put, NoYes::No, NoYes::Yes);


        purchaseOrder = data.purch().purchaseOrders().createDefault();


 public void confirmLocationWithCheckDigit_SimplePurchOrderOneItem_Success()




  var work =;


  var poPutaway = rf.login().purchaseOrderPutaway().setWork(work).confirmPick();

  poPutaway.parmCheckDigitControl().assertIsEnabled(); // Will automatically happen within set method below
  poPutaway.setCheckDigit(checkDigit); // This will confirm the Put to this location



  this.assertEquals(WHSWorkStatus::Closed, work.parmWorkStatus(), 'Work should be closed');




A few extra notes:

  • We recommend that you create a base test class for your test automation, that will hide the ATL navigation variable declaration and initialization, along with potentially some common setup, like I have at the beginning of the setupTestCase() method, setupBasicPrerequisites() and worker initialization.
  • Note the use of SysTestCaseAutomaticNumberSequences attribute on the class. This allows not to worry about configuring them manually, just let the framework do it for you.
  • Note that my test will not use an existing partition and company. It should generally work in USMF as well though, and it's up to you to decide how much data setup you want to rely on.

OK, that's it for this post. It's a bit of a brain dump, but please read through the points, and don't hesitate to reach out with questions.

Hope this helps

Monday, May 06, 2019

Announcement: MDCC is looking for Dynamics 365 Finance and Operations engineers

I'm really happy to share that we've updated the description of open positions (Example: to really reflect the focus of the team here in Lyngby, Denmark.

And we couldn't be more serious about finding the right talent to help us build an even better product within Supply Chain Management on the Microsoft Dynamics 365 Finance and Operations platform.

So, regardless of your level of experience (in the positive direction), if you love AX and want to make it better, if you are passionate about business problems, warehousing, manufacturing or sales, and if you are great at and enjoy solving complex technical challenges, apply today for one of the open positions we have!