Code highlighting

Sunday, December 02, 2018

[Tutorial] Automating Release to Warehouse process through Wave Template configuration


Currently many companies resort to manually choosing which shipments need to be added to a wave we are about to process, which is slow and error prone, as the user needs to check up on each of the shipments, understand where it is headed, what types of items are on it, which mode of delivery is used, etc.

Today I would like to show a demo example of how to configure wave templates, as to allow a more optimal distribution of orders, based on, say, delivery mode, or some other cut-off criteria. Automatically, without any user interaction.


I will not be talking about Automatic release of sales/transfer orders to warehouse in this post. We'll discuss that at a later point in time. Today it is only about making sure certain orders are grouped on a single wave automatically, based on defined criteria, so that they can be processed in the warehouse at the same time. This of course comes hand in hand with automatic release, which would enable a pretty much automatic operation for certain orders

Wave template configuration

Imagine that I would like to accumulate and then process all 2-day shipping orders at once, every second day, so I have the picking done before 4 pm that day when the UPS (or other 3PL) truck arrives to pick them up.
For these orders I want to pick as fast as possible, and the inventory is typically already at the locations and does not need special packaging, so I will not include replenishment and containerization steps into it, and will configure my work template to take the goods straight to the bay doors. 
I would also like to limit the number of shipments on each of the waves to 10, so as to not overwhelm my workers. Instead, I'll release another wave later in the day if necessary.
Generally, I'd like the wave to be processed automatically as soon as 10 shipments have accumulated, but throughout the day my Wave planner might process another wave, depending on the situation.

Here's how my wave template would look for this case:

2 day shipping wave template configuration for warehouse 24

Here's how I have configured the corresponding query:
Note. No need to add any filters on Site or Warehouse, as these will be automatically added.

I want to only look at shipments for Sales orders, and only those that have a 2 DAY shipping mode of delivery. Pretty simple. If I wanted, I could make this much more granular, by adding additional table joins and adding filters on them.

2 day shipping wave template query

Sales orders

Now let's create a couple sales orders, set the Mode of delivery correctly, reserve the inventory and release the orders to the warehouse.

Note. The field that is transferred to the shipment is taken from one of two:

  • Mode field on the sales order, if the Mode of delivery is not filled in.
  • Mode set on the Carrier associated with the specified Mode of delivery.
Mode of delivery specified on Sales order 000910
I only added one simple line for the example, on both sales orders.

Sales line for Sales order 000910

Release to warehouse

When we release the first order to the warehouse, we will create a new shipment, which will have the correct Mode of delivery. We will then proceed to search for a wave template that matches it, based on Site, Warehouse, as well as the defined query. Our newly created wave template should succeed here.
We will not however be able to find an existing Wave in status Created, that would match the Site and Warehouse for the shipment that is also using the same wave template. Which means we will go and create a new Wave
Note. A new wave is created because of the Wave template setting Automate wave creation

When we release the second order to the warehouse though, we will find the wave created above, and because the conditions for adding to the same wave are met, and the wave template has Assign to open waves marked as Yes, we will add the shipment to the found wave instead of creating a new one.

Here's how the resulting wave looks:

Wave created based on the two sales orders


Q: What if there is more than one wave in status Created, that was created based on the "right" wave template, and is for the same Site and Warehouse as the newly created shipment? Which wave will the shipment get assigned to?
A: The first of the waves that matches all of the criteria which also does not exceed the thresholds.

Q: Can I use fields directly from the sales order in the wave template query?
A: Yes, but you will need to join to get them. The right way would be to first join the load lines for the shipment, then the order lines related to the load lines, and then the sales order headers related to the sales lines. (Not directly from the shipment, even thought that will work just fine for certain businesses that always have only 1 shipment per 1 order)


As you can see, setting up a wave template that will group multiple shipments and create a new wave if necessary is relatively simple - you just need to get a few of the specifics correct in the setup, and then everything will work like a charm.

In one of the next posts we will combine this configuration with automatic release of sales orders, to achieve full automation of sales order release process, where no user interaction is necessary at all past the sales order creation and confirmation step.

Friday, November 16, 2018

[Development Tutorial] Tired of WHSWorkExecuteDisplay*? ProcessGuide to the rescue!

If you have ever tried extending the warehouse mobile flows in Dynamics 365 Finance and Operations, you know the code is very complex and extremely difficult to make sense of and modify without introducing regressions in unpredictable scenarios.

This was of course on our mind as well for some time, which is now I am pleased to announce the release of a new framework for implementing such flows, called ProcessGuide framework.

You can read the documentation we've published so far here:

We will incrementally start converting the existing flows, and you should do the same with yours.
Give it a try and let us know if you have any feedback by leaving a comment here or reaching out directly!


Wednesday, October 17, 2018

[Tutorial] Reading On-Hand information for Warehouse enabled items

Having difficulty understanding your own business data is probably not something you would expect to happen to you, but I know many people, including many 10+ AX experts who have a difficult time following the information about item availability when it comes to warehouse related items.

In this blog post, I will try to walk you through a specific example, line by line, column by column.

Note I am assuming that everyone is familiar with the general way we show on-hand information, specifically that you can summarize it by a different set of dimensions, viewing it aggregated by warehouse, location, or any other combination of dimensions.

What's the challenge?

The problems start when you need to account for the reservation hierarchy of the warehouse enabled item, and displaying how much is available at the different reservation hierarchy levels.

On-hand view, summarized by Site, Warehouse, Inventory status, Location and License plate

On-hand for item A0001, summarized by all storage dimensions

On-hand view, summarized by Site, Warehouse

On-hand for item A0001, summarized by Site and Warehouse

Step-by-step analysis of the data

  1. If we look at the Physical Inventory column, the on-hand there is always at the lowest dimension level – meaning we only see values for rows where you have all of the dimensions specified, down to the License plate level.
    1. That’s why in the first row, where there’s no location/license plate, the Physical inventory is shown as blank (0). Same for the 5th row, where for location FL-001 with blank LP there’s nothing in physical inventory. (RED)
    2. Note that for BULK-001 there is physical inventory, even though there is no LP – that’s because this location is not tracked at License Plate level, so the Location IS the lowest level (ORANGE)
    3. For some of the lines shown, there simply isn’t on-hand, but we used to have on-hand on them, which is why they show up. (YELLOW)
    4. The rest (GREEN) are quantities that are on license plates on corresponding locations. You can sum up and see the total quantity of this item we have in the warehouse is 205 (but, again, that’s not displayed in the first row, unless you change which dimensions are displayed – if you only display Site and Warehouse, for example, that’s what you would see – 205. See screenshot #2 above)
  2. Reservations are done at different dimension levels. So, for example, Sales order reservations are at “Above-location” level, while Work reservations are at “Location” level. Reservations at other levels are also possible
    1. That’s why in the first row, we have 30 in the Physical Reserved column – that is 3 different sales orders having a reservation against the quantity 10 each. They don’t care which location/license plate we take the items from, as long as we have enough on the warehouse/status level. (BLUE)
    2. Work reservation are at the location level. That’s what we have in row 5, where 2 work orders each reserve 10 units, and those units are to be picked exactly from location FL-001, but we do not care which license plate they will be taken from. (DARK BLUE).
    3. All the other rows are empty, as we have no reservation at the location+LP level here (Even though it is possible, generally speaking)
  3. Available physical column is where it gets a bit more tricky to understand. Let’s take it bottom up, so it’s easier to understand
    1. On third line, we have 100 physically there, and there are no reservations for any of it, so all of it is available. Thus, it’s 100
    2. Same for the 4th line, 10 there and all of it is available.
    3. Now, important part here. On FL-001, LP 24, I have 90 physically, but 20 is reserved. So why the heck is 75 available, instead of 70? (PURPLE)
                                                    i.     It is due to the reservation being on a higher level. The reservation is done at the location level, so when calculating available, it accounts for other license plates in this location as well, LP 000USMF-000..55 has 5 on it.
                                                   ii.     Another way to think of it – how many items can I take away from this License plate, so my existing reservations are still respected. The answer is – 75, because you’d have 15 left on this LP and 5 more on the other LP within the same location. The warehouse-level reservation is also still respected, because we have enough in other locations.
    1. On FL-001, 000USMF-00..55, we have 5 available. That’s what is physically there, and because we have enough in the other LP, all of this is available for taking for another purpose.
    2. The total quantity available at the location level matches what I described above, and equals 75, as it has 95 physically on it on multiple LPs, and 20 is reserved for work.
    3. On the warehouse level, we have 205 physically, and we need 30 for sales orders, so 175 is available to be reserved for other purposes. As you can see, that’s not a direct sum-up of the other rows. Same as the available quantity on FL-001 was not a sum of what is available at each LP. The calculation logic is the same here.

Additional information

If you are still curious for more after reading the below, check out this great 1 hour presentation my colleague Lennart did at a conference a while back, explaining the reservation engine and on-hand impact:

Monday, October 15, 2018

Telemetry as part of the Dynamics 365 Finance and Operations life-cycle

How much telemetry are we collecting?

A lot, like, really a lot!

That includes kernel level information, like an online user session requesting web access to a particular AOS to perform business operations through the web UI, a web service request to handle a mobile device operation, an OData request for exporting or importing data, exceptions and other infolog messages displayed to the user, etc.

It also includes specific application-level information, like details about each step during an inventory update, or information about the different wave processing steps, the specific flow happening on the warehouse mobile device, etc.

And we keep adding to it to have more and more granular information about what exactly is happening in the system at any particular point in time.

How can I access all this telemetry?

You can find it under "View Raw Logs" under Environment Monitoring in LCS.
It's very well described in the following two articles, so please read through those at this point:
You can then use the different search options described above to query out the specific events you are interested in.

What about Warehouse - specific telemetry, say, Wave processing?

Depending on the version of the product you are running, it differs slightly. 

Here's how you would search for wave processing events on releases before Fall release of 2018:

Raw logs search criteria

Note The above query options is a preview feature, so is most probably not visible to you yet.

If you then wanted to filter on a specific wave, for example, you could add that to the search criteria as well. 
Note that due to compliance, all of the information is not exposed directly, but rather RecIds are used. So you'd need to retrieve the RecId of the wave you wanted to investigate.

Here's some of the fields you should take note of:
  • The TIMESTAMP column would tell you when exactly the event occurred
  • RoleInstance would show, which AOS the activity happened on. This could be useful when troubleshooting caching and other cross-AOS issues
  • ActivityId is a way for you to limit to only a specific smaller process (for example, a specific allocation thread), and dig deeper, for example, to analyze the slow queries that happened as part of that activity
  •  infoMessage would contain information about the actual wave step performed, as well as specific details about the step, like how many load lines were processed, how long it took, etc.
TaskName: WhsPerformanceTaskStop, ruleName: waveProcessing, actionPerformed: runWaveStep, durationInMilliSeconds: 0, details: {"allocatedLoadLines":"500","custom":"no","waveId":"5637815827","waveStep":"WhsPostEngineBase.allocateWave"}

From Fall release onward

You could search for WHSPerformanceTaskStart/Stop directly in the TaskName instead of as part of infoMessage. The rest still applies.

What about mobile device telemetry - do we capture that?

Of course we do :)

Just search for TaskName == WhsUserActivityEvent
This event contains the same basic information as mentioned above, as well as stuff specific to the mobile flow:
  • Company, Site and Warehouse, where the warehouse user is operating. (RecIds)
  • WorkExecuteMode and step for the specific flow. You'll need to lookup the actual step in code
  • GUID of the mobile device user session
  • WorkTransType, as well as WorkTable and WorkLine RecIds being processed
  • RequestXML - this is the actual request, except all the data and labels are scrubbed, so it shows just what controls are shown on the screen
This event, if you search for it in code, is invoked at the very end of processing the user input from the mobile app.

You can correlate these events with those of TaskName == RequestContext, where the url of the request contains "/api/services/WHSMobileAppServices/WHSMobileAppService/getNextFormHandHeld" - this is the actual web service call as it arrives at the AOS, so the point in time when the AOS starts handling the mobile app flow step. 

Everything that happens in between with the same ActivityID is part of the flow, whether that is slow queries, error messages or other relevant events.

I don't see these events - what should I do?

We have back-ported a lot of the telemetry through hotfixes. Search for it on LCS for your specific release. 
But I would also like to take this opportunity and move up to the latest release. There is soo much goodness in there!

Should partners be adding telemetry?

  • If you are a client, I suggest that you start insisting your partners adds telemetry with any new code the push into production.
  • If you are a partner, I suggest you start adding it asap - you'll save yourself a lot of time going forward, if the customer has an issue with your code. Since you cannot just debug in production any longer, you'll need to rely much more on alternative ways of telling you what exactly happened. Telemetry is the solution.

Where do we start? Do we have some examples?

We are working on the guidance for this and will share this out very soon.

Yes, all of the application telemetry is added directly as part of the application code, so should not be too difficult to find.
I suggest that you rely on the same event "InfoLogMark" as shown below as well.
Consider adding a using statement to reduce the invocation.

                                      Exception::Info, strFmt('TaskName: , etc.', );

What else should be captured out of the box that is critical for you?

Let me know in the comments!

Wednesday, June 06, 2018

[Learning] Transportation management in Dynamics 365 Finance & Operations

I don't talk much about TMS in this blog, so I decided to correct that a bit, and post a set of educational links for those interested in starting up with Transportation management in AX.

If you are already familiar with all the concepts, you probably won't gain that much from these, but for those just starting up, I think it can provide a great overview of what the system can do.

You can start by reviewing the presentation one of my colleagues did a while back.

For a more in depth look, you can go through the TMS learning course (note it is based on AX 2012 R3, but the functionality is largely still the same in the latest release):

A couple more learning videos are available through the below link:

Transportation management implementation guide and white papers available can be found through our SCM team blog posts:

And, finally, we have a permanent page on, that you can access through the below link. This is where most of the upcoming functional changes and updates will be communicated going forward.

And, of course, if you have further questions after this, please reach out, so we can connect you with the right people to help.


Saturday, June 02, 2018

Extensibility: You can now log extensibility requests for Microsoft through LCS

If you weren't living under a rock for the last 2 years, you have already heard about us locking down overlayering starting with the latest release of  Dynamics 365 for Finance and Operations 8.0, and relying solely on the extension model of developing customizations going forward.

But, of course, as this is a moving target, not everything can be done through extensions in the current release.
You will discover that some customizations, which were possible with overlayering, cannot be done through extensions. To enable the same business requirements without overlayering, we have added many extension capabilities and expect to add more going forward. For some customizations that were done with overlayering, you will need to log requests, to make us aware of what you need.
So, how do you log such requests?

Starting in June 2018 you can now log extensibility requests through your LCS project.
Prior to logging a request, make sure you've evaluated alternatives, and have all the necessary information as part of the request for Microsoft to have an easier time adjusting the core code to your specific requirements.

Here's how the "New extensibility support request" form looks like on LCS:

Add a new extensibility request

Follow the below link to find out more details and read through a step-by-step guide on logging extensibility requests: