Code highlighting

Showing posts with label WHS. Show all posts
Showing posts with label WHS. Show all posts

Saturday, October 17, 2020

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

Introduction

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.

Setup

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

Flow

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

Summary

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.

Sunday, December 02, 2018

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

Introduction

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.

Disclaimer

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


FAQ

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)

Conclusion

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.

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: https://www.youtube.com/watch?v=--_didmZKHo&t=4s

Saturday, April 15, 2017

Development tutorial link: Extending the Warehouse management functionality after application seal

Background


At the Dynamics 365 for Operations Technical Conference earlier this year, Microsoft announced its plans around overlayering going forward. If you have not heard it yet, here's the tweet I posted on it:


 AppSuite will be "soft sealed" in Fall 2017 release and "hard sealed" in Spring 2018 - move to use  in your solutions

However the application SYS code still has a number of areas which are difficult to impossible to customize without overlayering. One of such areas is the Warehouse management area.

Improvements

In the SCM team we have been focusing on improving our Extensibility story in the application, which also includes the above mentioned warehousing area.

Below are a few posts Michael posted recently describing some of the changes we have done in the Warehouse management area, which are now available as part of Microsoft Dynamics for Operations Spring 2017 preview.
This should allow customizing the warehousing functionality to a large degree without the need to overlayer the code.

Extending WHS – Adding a new flow
Extending WHS – Adding a new control type
Extending WHS – Changing behavior of existing control types
Extending WHS – Adding a new custom work type
Extending WHS – Adding a new location directive strategy

Please look through these changes and let us know if YOUR functional enhancements are still impossible, so we can get them addressed.

Thanks

Thursday, March 30, 2017

Development tutorial: Platform improvements for handling X++ exceptions the right way

A while back I wrote about a pattern we discovered in X++ code which could lead to serious data consistency issues. You can read it again and look at an example mfp wrote up here:
http://kashperuk.blogspot.dk/2016/11/tutorial-link-handling-exceptions-right.html

With the release of Platform update 5 for Dynamics 365 for Operations we should now be better guarded against this kind of issue.

Let's look at the below example (needs to be run in USMF company):

class TryCatchAllException
{
    public static void main(Args _args)
    {
        setPrefix("try/catch example");

        try
        {
            ttsbegin;

            TryCatchAllException::doSomethingInTTS();

            ttscommit;
        }
        catch
        {
            info("Inside main catch block");
        }

        info(strfmt("Item name after main try/catch block: %1", InventTable::find("A0001").NameAlias));
    }

    private static void doSomethingInTTS()
    {
        try
        {
            info("Doing something");
   
            InventTable item = InventTable::find("A0001", true);
            item.NameAlias = "Another name";
            item.doUpdate();

            throw Exception::UpdateConflict;

            // Some additional code was supposed to be executed here
        }
        catch
        {
            info("Inside doSomething catch block");
        }
  
        info("After doSomething try/catch block");

    }

}

Before Platform Update 5 the result would be:


As you can see, we 
  • went into doSomething()
  • executed the update of NameAlias for the item, 
  • then an exception of type UpdateConflict was thrown
  • At this point the catch-all block caught this exception without aborting the transaction, meaning the item is still updated. We did not abort the transaction because we did not think about this case before
  • We exit the doSomething() and commit the transaction, even though we got an exception and did not want anything committed (because the second part of the code did not execute)
  • As a result, the NameAlias is still modified.

Now with Platform Update 5 the result will be:

That is, we

  • went into doSomething(),
  • executed the update of NameAlias for the item,
  • then an exception of type UpdateConflict was thrown
  • At this point the catch-all did not catch this type of exception, as we are inside a transaction scope, so the exception was unhandled in this scope, and went to the one above
  • Since we are by the outer scope outside the transaction, the catch-all block caught the exception,
  • and the NameAlias is unchanged


So, again, we will simply not handle the 2 special exception types (UpdateConflict and DuplicateKey) any longer in a catch-all block inside a transaction scope, you will either need to handle them explicitly or leave it up to the calling context to handle.

This will ensure we do not get into this erroneous code execution path where the transaction is not aborted, but we never handle the special exception types internally.

Hope this helps!

Thursday, March 02, 2017

Announcement: Warehouse Mobile Devices Portal improvements with February update of AX 2012 R3

A monthly cadence AX 2012 R3 update for February has just come out on LCS, and with it a few changes our team has done that deal with overall behavior and performance of WMDP - the Warehouse Mobile Devices Portal used in the Advanced warehousing module.

I want to call them out here, and if you are reading my blog to keep up to date with the Warehousing changes, I strongly encourage you to install the below changes:


  • A functional enhancement, that allows you to start execution of a work order that has some lines awaiting demand replenishment, processing the lines that can be picked already now
  • A performance optimization, that avoids updating certain persisted counters on the wave when work goes through its stages. 
    • This also ensures they do not get out of sync, as they were used to make certain decisions about what is allowed for a work order
    • Can also be downloaded individually as KB3217157
  • An integrity enhancement, that ensures we always are in a valid state in DB, where each service call from WMDP is now executed within a single transaction scope
    • Can also be downloaded individually as KB3210293
    • Can be turned off in code for a selected WHSWorkExecuteDisplay* class, if needed
    • This is a great change ensuring we do not commit any data unless all went well, but might hypothetically impact your new/modified WMDP flows, if you handle your exceptions incorrectly today. If you do find issues with them, please let me know, I am curious to know your specific examples.
  • Various minor enhancements, that ensure WMDP performs well under load
    • Can also be downloaded individually as KB3210293
    • This includes improvements to enable better concurrency in various WMDP scenarios, better error handling on user entry, etc.

Again, install these, try them out, and provide feedback!

There are a lot more enhancements and bug fixes that went into this release, you can read the full list by following the link below:


Thanks!

Wednesday, December 28, 2016

Configuration tip: Warehouse mobile devices portal Native application in Azure Active Directory

Setting up the Warehouse mobile devices portal is a relatively simple process, and is described in detail on the corresponding wiki:
https://ax.help.dynamics.com/en/wiki/warehouse-mobile-devices-portal-for-microsoft-dynamics-ax/

However, now and again I would get complaints around the authorization process not working properly, or asking for interactive login, both of which shouldn't be necessary for the authorization method used by WMDP.

So in this post I would like to give a small configuration tip that prevents the below error message:

Error: "The user or administrator has not consented to use the application with ID ''. Send an interactive authorization request for this user and resource.

The reason this error is shown is because the Native application setup in Azure for WMDP has access to resources that require the Azure admin to consent to that first.

WMDP app is configured to allow access to AAD resources
As you can see, some of the resources WMDP app has access to require prior Admin consent.

Recommendation: 

When configuring the Native application for WMDP in Azure, only give it permissions for the Microsoft Dynamics ERP resources.

This will ensure you don't get unexpected errors when trying to connect to WMDP.



Happy Holidays to all of you!

Stay tuned for more posts next year and subscribe if you haven't already to get updates on the latest tips and tutorials for Dynamics 365 for Operations aka Dynamics AX aka Axapta :)

Thursday, November 24, 2016

Tutorial Link: Handling exceptions the right way in X++

Michael and I have been working the last couple of weeks to uncover some of the difficult to repro bugs in Warehouse management code, and one of the things we discovered is a pattern which can lead to very unpredictable behavior when used incorrectly.

I encourage all of you to read it and make sure all of your code is up to standard.

https://blogs.msdn.microsoft.com/mfp/2016/11/24/x-the-catch/


Thanks!

Sunday, October 02, 2016

Tutorial: Extending the label printing functionality in Microsoft Dynamics AX 7

Today I would like to shed a bit more light onto how to extend the label printing functionality, specifically, show how to add a new field from the work line to be displayed on the label.

This is something we have created as a demo for Tech Conf a while back, and you can still see the recording where Per and Zach from our team showcases the different label printing scenarios.
You can view the different Microsoft conference videos here.

Just as a refresher, here is a guide for how to set up label printing in Dynamics AX 7:
http://kashperuk.blogspot.dk/2016/10/tutorial-label-printing-in-microsoft.html

Technical introduction

The label printing "framework" consists of three main components:

  • WHSLicensePlateLabel table, which contains the information for the label, which is substituted into the label through the variables.
  • WHSLicensePlateLabelBuild class, which is responsible for populating the WHSLicensePlateLabel table with data for a particular work order (line).
  • WHSDocumentRouting class, which is responsible for the actual printing of the label, as well as the substitution of variable values, using the below methods:
    • initMenuFields() method is responsible for building the list of substitute fields based on the WHSLicensePlateLabel table fields
    • printDocument() method finds the specific document routing record that matches the flow criteria (e.g., warehouse, work order type, carrier, etc.), performs the translation of the label and sends it to the selected printer (Note that the label can be printed to multiple printers and you can for each printer decide, which layout to use).
    • translate() method is responsible for actually replacing any variables in the label layout with the corresponding values from the WHSLicensePlateLabel table
Let's take a closer look at the fields available on the WHSLicensePlateLabel table:

WHSLicensePlateLabel table fields
These fields represent the full list of potential variables that can be put into the label in the Document Routing layout. Depending on the item flow, some of these fields are not populated. Note that when setting up the placeholders in the Document Routing Layout form, only visible fields are displayed. That allows for storing some "plumbing" information for each record, like the PrinterSettings.

Adding placeholder variables to a label layout

Fragile Example extension

For some scenarios you might want to display some additional fields on the label, which are not part of the list shown above.

Imagine a scenario where we want to display a "Fragile" message on the label if the items on the work line are accordingly marked. 

Since there is no such field in the label, we will need to extend this functionality. And because we are working in AX 7, we will try to use Extension instead of Overlayering the elements, as we would do in AX 2012 R3.

Step 0 - Create a new model for our changes

First of all, let's create a new model, which will contain all the elements we add through extension.

Create a new model in Visual Studio
We will put this model into a new package, as we do not intent to overlayer existing AOT elements. We will reference the Application Suite package, so that we can access the elements defined in it, such as the ones mentioned above. 
Note that by default the new package will also reference Application Platform.

Select referenced packages for model FragileExample
Confirm the creation of the new model and create a new project for it. Name it FragileExample.

Step 1 - Extend the WHSLicensePlateLabel table and add a new field FragileCode

Since we want to display an extra field in the label, we need to add it to the WHSLicensePlateLabel table. In order to do that, let's create an extension of this table in the new model:

Adding a new table extension from Application Explorer
You need to have selected the right project in your Solution Explorer before you attempt creating an extension. This is to ensure that the extension is actually created in the right model.


We are now going to add a new field of base type String, and call it FragileCode with the corresponding label.

Note I am not going to bother with labels or Extended Data types for sake of simplifying the demo

Table extension for WHSLicensePlateLabel in FragileExample model
New field FragileCode on table extension WHSLicensePlateLabel.Extension
In order for the field to appear in the Document routing layouts form all we need to do is compile the new code and synchronize it against the database. I have decided to do that at build time by configuring it accordingly, as shown below:

Synchronize on build = true for FragileExample project
If we now reopen the Document routing layouts form, we can see that our new placeholder is available in the list and we can add it to the label:

Fragile code placeholder available in Document routing layouts form

Step 2 - Populating the Fragile code field on WHSLicensePlateLabel record

Now that we have the field available on the label, we need to populate it. 
As described in the Technical information section above, the label details are populated in the class WHSLicensePlateLabelBuild. Let's quickly examine how this happens:

Sequence of calls to build a license plate label
As you all know, any and all work creation and execution in Dynamics AX happens through the WHSWorkExecuteDisplay* classes, e.g., purchase order registration can execute WHSWorkExecuteDisplayPOItemReceiving, while general work execution flows can execute WHSWorkExecuteDisplayUserDirected, etc.
Within these classes the WHSLicensePlateLabelBuild class is initialized, and the buildLicensePlateLabels() public method is called, when a label needs to be generated and printed.
Depending on the flow, either the insertSingleLabelPrintLine or the insertSingleLabelMenuItem method will be invoked internally, after which the generated label is printed through the printDocument API of the WHSDocumentRouting class, as described above.

Note. insertSingleLabelPrintLine supports the flow where the Print step is part of the work template lines, while insertSingleLabelMenuItem is for the case, where the Print is configured through the mobile device menu item.

So, in order for us to populate the extra new field we need to look into these insert* methods. With the recent AX 2012 R3 changes these methods have been refactored in a way, where most of the logic for populating the WHSLicensePlateLabel table has been pulled out into a new private initLabel() method.

In Dynamics AX 7 this method has been extended (who could have done that? :)) and now has a delegate which is invoked at the end of the method, which means that event handlers can be created for it. With these minor changes, we can now extend this class by subscribing to the event of the initLabel method being invoked, as shown below:

Copy event handler code for labelInitialized delegate
We can now put this generated event handler signature into a new class in our model, as shown below:

Signature of the event handling method for labelInitialized delegate
This is awesome and is one of the new extensibility language features in Dynamics AX 7 - I have subscribed to the event of this method being called without touching the original class at all.
As you can see, instead I have a SubscribesTo attribute that subscribes me to the corresponding event in a static fashion. 

Now all we need to do is actually populate the Fragile code on the label. Let's do that:

Implementation for the event handling method for labelInitialized delegate
As you see above, the code is super simple, all we do is get the Filter code value from the corresponding item, and populate it into the FragileCode field.

Let's now compile everything and give it a go in AX web client.

You can download the VS project file from my OneDrive here.

AX flow steps and result


  1. Modify item A0001, setting Filter Code 4 to a new value called FRAGILE
  2. Create a new purchase order for 10 pcs of A0001 to WH 24
  3. Modify the Mobile device menu item for Purchase receipt to "Print label"
  4. Ensure you have a Document routing record matching WH 24 for Purchase orders
    1. Ensure you have a document routing layout being sent to a label printer
  5. Receive the above purchase order through the WMDP
As a result, you should get a new label created, which will have the Fragile code populated with the value FRAGILE, as below (I've personalized the form to show the new field):

License plate label with the populated Fragile code

Depending on your label layout you would have this message printed on the label as well.

Conclusion


With this blog post I hoped to show you how to extend the existing set of fields available on the license plate labels.

At the same time we took a look at some of the new language constructs, design paradigms and tooling that allows for a much cleaner approach to extending existing functionality, as compared to overlayering, which many are used to.

Consider extending instead of overlayering next time you need to make a change!