Code highlighting

Showing posts with label product dimensions. Show all posts
Showing posts with label product dimensions. 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.

Friday, January 16, 2015

Tutorial: InventDimCtrl_Frm classes and the amazing things you can do with their help

Preamble

I was making some adjustments to one of the forms in the application today. Specifically, it was the PdsCustSellableDays form, which is a setup form you can open for a selected customer through the Sell\Setup\Sellable Days action pane button. You can read more about this functionality here:

Working on these changes brought back the memory of what it is that I have always enjoyed most about developing customizations in AX: Making a lot of difference with only a few small targeted code changes.

So I was inspired to use this as an example for describing some of the capabilities of the InventDimCtrl class hierarchy. There are a lot of classes in the hierarchy, targeted to various forms in the application that display Inventory dimensions one way or the other. The main purpose of this class hierarchy is to control the display and behavior of the inventory dimensions as well as the “Dimension display” button that is normally also present on such forms.

Most of you probably know that the way AX developers early on decided to handle inventory dimensions is through a “reference” table InventDim, and a lot of generically written code that would heavily exercise reflection and traversing form controls. This seemed like a good idea at that time, I bet, but over the years, in my opinion, it got completely out of control, and now is a pretty large overhead for almost all inventory related operations in our product. But, at the same time, it provides a nice level of flexibility to how dimensions are displayed on a particular form.

That being said, let’s start from the beginning and briefly explain the existing form behavior and the things I was set to change in it.

Existing behavior and task

Overview of the existing behavior

  • Only product dimensions are displayed in the main grid
  • The relationship to the products is implemented via a “standard” pattern of TableGroupAll. So you can set up Sellable days for a specific item, an item group, or all items.
  • Viewing Inventory\Dimension display shows the standard dialog with all inventory dimensions. However, storage and tracking dimension check-boxes are disabled for editing.
  • Upon adding a grid row and selecting a released product master, all product dimension values are shown, not just those from the released product variants.
  • Only the product dimensions active for the selected product are enabled for editing. If Item code is set to Group or All, all the dimensions are disabled for editing.

Original version of the form

Task

  • Storage and tracking dimensions cannot be selected in Dimensions Display, so should not be shown at all
  • Lookup for configuration and other product dimensions should only show those relevant for the released product master.

 

Explanation

OK, so let’s take a closer look at how such types of forms are built

  • A form-level variable of type InventDimCtrl_Frm is declared. This object is used to control the behavior of the inventory dimension controls on the form.
  • A form method called inventDimSetupObject simply returns the above reference. Through this method other AX forms and classes can access the current state of the form when it comes to the dimensions
    • This includes information about which inventory dimensions are visible in the grid, which of them are enabled for editing, which of them should be marked as mandatory, which of them should be shown when the Dimension Display button is pressed, whether or not the “large” version of the dialog is to be shown (that includes On-hand information like Closed/ClosedQty), whether Item number should be shown on the Dimension Display dialog, etc.You can browse the methods on this class to get a feeling for what else it can do.
    • Since we can only select product dimensions in the form, we want spread that over to the Dimension Display dialog as well.
  • A form method called updateDesign() exists, with a certain pattern for handling various “events” that happen on the form. The main purpose here is to update the inventDimSetupObject with the latest information from the form, and through it refresh the display of the inventory dimension controls.
    • In the PdsCustSellableDays form this happens when the form is opened (Init), whenever the item code or reference is changed (FieldChange), whenever the active record is changed (Active) or whenever the parent customer record is changed in turn refreshing the Sellable Days view (LinkActive).
      • This method is then called from the appropriate event handles or the form, as you can see if you open the form code.
    • In PdsCustSellableDays the intention is to only enable the active product dimensions for the selected item, and disable all of them if we selected all items or an item group instead. But only product dimensions are to be shown ever. This is achieved by using the following methods:
      • parmDimParmEnabled(InventDimParm) controls which dimensions can be edited
      • parmDimParmVisible(InventDimParm) controls which dimensions are shown
      • parmDimParmVisibleGrid(InventDimParm) controls which dimensions are shown in the grid.
      • parmDimParmLockedRightClick(InventDimParm) controls which dimensions can be selected through the Dimension Display button
      • formSetControls(boolean) actually executes the update of the inventory dimension controls based on the above settings. The first parameter controls whether the form is locked for the duration of the update (preventing unnecessary flicker, especially in cases where controls are being made visible/invisible in the grid).
      • formActiveSetup(InventDimGroupSetup), which is not used here, but is frequent in other forms, should be called when the active record is changed, and resets the enabled fields based on the now selected item dimension group information.
      • dimFieldsActive(InventDimParm) that is also used in the form is actually an inquiry-type method, and does not impact the state of the object in any way. Its purpose is to return a container of active dimension field IDs based on an InventDimParm buffer.
  • Lookups for all the product dimensions are based on the form called InventProductDimensionLookup, which is another example of generic handling of inventory dimensions, and has all the above properties as well.
    • It can show up to 3 tab pages, including the selected product dimension values, all relevant product variants and the on-hand information
    • In the current version of the form, all existing product dimension values are shown, regardless of the product. This is one of the things we need to fix.

 

Changes made and result

OK, so in order to accomplish the 2 tasks we set for ourselves above, we only need to change code in 3 places on the form. Let’s walk through each one in turn.

  • Modify the classDeclaration, and replace the type InventDimCtrl_Frm with InventDimCtrl_Frm_ProductDim. If we take a look at this class (it is only available starting from AX 2012 R3 CU8, so I am also including the code for this class below, for reference), we can see a few methods were overridden:
    • mustEnableField() makes sure that only the active product dimensions based on dimension group setup are enabled. This is used by the formActiveSetup method, and is not as interesting for our example.
    • mustShowGridField() makes sure that all product dimensions are shown in the grid, and only product dimensions. This was controlled by explicitly calling parmDimParmVisibleGrid() before. We’ll remove that code, as you’ll see later.
    • setupShowAllProductDimensions() – this method is important for our example. This method, if it returns true, will ensure only product dimensions are shown on the Dimension Display dialog.
  • Modify the updateDesign method as below
    • Remove the lock/unlock method calls, since this is already going to happen within formSetControls().
    • Initialize the inventDimSetupObject using the right class InventDimCtrl_Frm_ProductDim
    • Remove the variables inventDimParmDefault and inventDimParmDisenabled, and all code related to them. This code is now redundant.
    • Remove the call to dimFieldsActive. As I mentioned above, it does not do anything useful for us.
    • We can also add 1 extra line clearing the inventDim values that do not apply – this is important for when changing the item number where we already have product dimensions selected. Just a bug fix, not really related to this tutorial.
  • Add a new method itemId(), which returns the currently selected item number
    • This is necessary for the product dimension lookups to function properly. The lookup tries to find the item information from the calling form through the data source joined to InventDim as a parent, assuming it has an ItemId field. While that is true in most cases, our form uses a TableGroupAll pattern, so the field is a bit different. By creating an itemId() method on the form, we ensure that the lookup can find the right item number to reference when retrieving product dimension group information.
    • In updateDesign, after initializing the object, invoke parmSkipOnHandLookUp(true), which will ensure that the on-hand tab page is not shown on the lookups. Since this is not necessary for this type of setup form, it’s a good idea, since it will improve the lookup loading time. This is also demonstrating how the lookup form uses the inventDimSetupObject of the calling form to get the expected behavior settings.
    • The lookup will now also show the Combinations tab page, if the selected product has more than 1 product dimension active.

That’s it. With very few changes, we were able to drastically change the look and feel of this form. Here’s how it looks now:

Updated form behavior

 

Download the project

You can download the project with the changes I have made from my OneDrive.