Zach Greenvoss, Author at Microsoft Dynamics 365 Blog The future of agentic CRM and ERP Thu, 12 Feb 2026 20:06:54 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.3 http://approjects.co.za/?big=en-us/dynamics-365/blog/wp-content/uploads/2018/08/cropped-cropped-microsoft_logo_element.png Zach Greenvoss, Author at Microsoft Dynamics 365 Blog 32 32 .cloudblogs .cta-box>.link { font-size: 15px; font-weight: 600; display: inline-block; background: #008272; line-height: 1; text-transform: none; padding: 15px 20px; text-decoration: none; color: white; } .cloudblogs img { height: auto; } .cloudblogs img.alignright { float:right; } .cloudblogs img.alignleft { float:right; } .cloudblogs figcaption { padding: 9px; color: #737373; text-align: left; font-size: 13px; font-size: 1.3rem; } .cloudblogs .cta-box.-center { text-align: center; } .cloudblogs .cta-box.-left { padding: 20px 0; } .cloudblogs .cta-box.-right { padding: 20px 0; text-align:right; } .cloudblogs .cta-box { margin-top: 20px; margin-bottom: 20px; padding: 20px; } .cloudblogs .cta-box.-image { position:relative; } .cloudblogs .cta-box.-image>.link { position: absolute; top: auto; left: 50%; -webkit-transform: translate(-50%,0); transform: translate(-50%,0); bottom: 0; } .cloudblogs table { width: 100%; } .cloudblogs table tr { border-bottom: 1px solid #eee; padding: 8px 0; } ]]> Customizing the warehouse mobile app: multi-scan pages http://approjects.co.za/?big=en-us/dynamics-365/blog/it-professional/2018/12/20/customizing-the-warehouse-mobile-app-multi-scan-pages/ Thu, 20 Dec 2018 09:31:58 +0000 Introduction This is another blog post in the series about warehouse mobile devices in Dynamics 365 for Finance and Operations. In the last blog post, the difference between customizing for WMDP and the warehouse mobile app was discussed.

The post Customizing the warehouse mobile app: multi-scan pages appeared first on Microsoft Dynamics 365 Blog.

]]>

Introduction

This is another blog post in the series about warehouse mobile devices in Dynamics 365 for Finance and Operations. In the last blog post, the difference between customizing for WMDP and the warehouse mobile app was discussed. This blog post will be walking you through a new control scheme that was recently released, explaining how it unlocks new potential for partial offline processing in the warehouse mobile app.  This new functionality is called “multi-scan” and it enables a user to perform a series of offline scanning operations and then return them all to the server in one round trip operation. The goal for this control scheme is to allow for very quick scanning operations (many scans per second as an example) in high transactional warehouses where the standard model of a server round trip after each scan will not scale. Especially in sequential operations where the user does not need to look and verify on the device after each scan, but rather just need to register all scans in one go.

Multi-scan Functionality

If you download the latest version of the warehouse mobile app, you will have some new capabilities in the demo-mode which shows how this new control pattern works.  Once you have enabled the demo mode you should see the following menu:

Demo mode Menu Items

Cycle counting is the flow we have enabled in the demo with multi-scanning to demonstrate the new capabilities.  It is designed to simulate a user performing a spot cycle count at a location in a warehouse or retail store where there are many items to scan. Currently this in only available in demo mode of the app, there is no support for this functionality when connected to a Dynamics 365 for Finance and Operations environment.

The first screen that is displayed is a location scanning screen – you can enter (or scan) anything in the demo mode here to move to the next screen.

Scanning screen in Demo Mode

Once you have scanned the location, the app enters the multi-scanning mode.  This is the new control that is being introduced in this release, so let’s go through the different UI elements that have been introduced to support this new flow.

Sample of multi-scanning screen

This is the initial screen – you can tell it is the multi-scanning interface because of the new list icon in the bottom left corner; clicking the list icon will show you the list of items you have scanned so far. The checkbox icon in the bottom right is used to report to the app that you are done scanning and it is the only time the processing returns to Dynamics 365 – everything else will take place within the app locally on the device.

Once a worker starts to scan barcodes (or enter data manually into the app) the UI will change slightly.  Every item scanned will be added to an internal buffer and the number of items scanned will be displayed in the main UI.  For example – after a few scans the UI will now display the scanned count of three:

Screen indicating scanned count: 3

At any time, the user can click the list icon in the lower left, which will then display the list of items that have been scanned (in this example perhaps product barcodes in the location).  The UI for this looks like the following:

Screen showing list of scanned IDs

This lists the barcodes that have been scanned as well as a count of the times they have been scanned by the user.  This is very useful in the counting scenario, as a user can simply scan each product’s barcode to generate a count of items at that location.

You might note that there are two disabled buttons at the bottom of the screen.  These become active when a row is selected by the user in the list – as you can see below:

Two buttons activating upon selecting a scanned ID

The edit icon on the left allows you to manually change the number of scans for the selected row. The icon on the right with the “X” deletes the selected row in case something was scanned accidentally.  

The edit icon will open a new screen with the numeric stepper UI allowing the user to quickly increment or decrement the number of scans or click on the value to open the numeric keyboard:

Screen showing adjusting scan count of a specific Scan ID

When clicking on the value, the numeric keyboard will open. As the number of barcodes cannot be negative, or integers, buttons that aren’t relevant for this use case has been disabled:

Numeric Keyboard screen can be accessed when clicking on value

Returning to the main screen (by clicking the back button in the upper left corner) we are ready to submit the scanned list of items and their counts to the server. We do this by clicking the checkbox button in the bottom right – this is when we finally make the round-trip to the server and communicate with Dynamics 365. Later in the blog post the API will be explained and how to consume the scanned items and their quantities in X++ code.

In the demo flow, the next screen that is displayed is the following list of items which are not present in the location:

Screen with items not present in location

This is the second control pattern that we have introduced as part of this release – it allows a workflow to display a list of items (for example barcodes or product UPCs) and then allow the user to “scan to remove” from the list.  In this demo example we are displaying the items that were found in the cycle count but are not currently registered as on-hand for this location; the intention is that the warehouse worker would double check this list and scan any items that were indeed found as an extra validation check.  Scanning “T0001” in the above screen would then remove this from the list – and remember that this is all done client-side at this point. It is also possible to click on any value in the list and remove it.  Then when the user clicks that checkbox/submit button the new list of items would be submitted to the server for processing through a X++ workflow.

Custom Workflow

Hopefully that walkthrough gives you some idea of the capabilities we have added with these two new client-side control screens.  It is important to know that we have not currently added any multi-scan capabilities to the core product yet – the above cycle counting workflow is just a demo inside the app.  The goal of introducing these new control screens is to enable partners and customers to build new workflow-based solutions in the mobile app that support client-side driven scanning operations.  As such let’s walk through a simple customization example to show how the new control screens can be utilized in a real workflow.

Page Patterns

The way to enable the multi-scan screen is through a Page Pattern.  This might not be something you are aware of in the mobile app, as most of the time this is handled for you by the standard framework.  The Page Pattern is what tells the mobile app what type of UI to display on the device itself.  If you look at the WHSMobileAppPagePattern Enum you can see the different options available:

WHSMobileAppPagePattern showing a list of different options
  • Default
    • This is the page pattern used for 90% of the screens in the app. It displays a primary scanning UI and a set of controls in the secondary tab – of which a few can be promoted to the first screen.  An enter and cancel button and an optional set of additional buttons in the menu are supported.
  • Custom
    • This Page Pattern is not used in many places in the core mobile flows – it is designed to allow partners to convert their old WMDP pages into the new model. Using this pattern will render the controls as it was done in WMDP  – each control simply vertically stacked in a single screen.
  • Login
    • This is used for the initial login page.
  • Menu
    • The Menu screens are rendered with this Page Pattern.
  • Inquiry
    • This Page Pattern support the workflows that allow the user to search for something and then see the results – such as LP or Item lookup screens.
  • InquiryWithNavigation
    • This is the Page Pattern that supports the Worklist view in the app. It is similar to the Inquiry pattern, except that includes some sorting options as well as the tiles are navigable.
  • MultiScan
    • This is the new pattern that has been added which will display the multi-scan UI shown in the demo above.
  • < MultiScanResult>
    • Note that as of the 8.1.1 release there is one missing and will be added in an upcoming release. If you want to enable a workflow to use the second screen described above – the “result list” of items, you would need to add a new Enum and return the value MultiScanResult. 

The actual job of returning the Page Pattern to the app is done through a class which derives from WHSMobileAppServiceXMLDecorator. This abstract class has a “requestedPattern” method that can be overridden to return the specific Page Pattern that is necessary.  This is typically done through a workflow-specific factory class that understands the correct workflow steps and thus can return the correct XMLDecorator class depending on the stage in the state machine.

For example – here is the standard factory class for the Work List functionality.  You can see that it typically will return the WHSMobileAppServiceXMLDecoratorWorkList object – which will render the work list Page Pattern as you would expect, however if the user has switched to the edit filter view then we need to display a different Page Pattern – thus the factory has the context to make this switch.

Standard factory class for the Work List functionality

Multi-Scan API

Now that we know how to enable the Multi-Scan UI through a Page Pattern, we need to understand the basic API for passing the scanned items back and forth.  Once the MultiScan Page Pattern is requested, the first input control registered on the page will be used for the multi-scan input.  Remember that most of the UI interaction is all done client-side – so the only thing the server X++ code needs to do is define this control and the data that it contains.

When the user clicks that “submit” check box and sends the multi-scan data back to the X++ code, this is formatted in a very specific way.  The actual parsing of the data is done using the same interaction patterns as before – it will be stored in the result pass object for the specific control defined as the primary input of this page.  But the data will be passed in this format:

                         <scanned value>, <number of scans>|<scanned value>, <number of scans>|…

Thus, in my demo example above the data that the server would receive would be the following:

                         BC-001,2|BC-002,1|BC-003,1

In the X++ code you would then be responsible for parsing this string and storing the data in the necessary constructs.  We will see a simple example in a moment of how to parse this data.

Asset Scanning

The workflow I will demonstrate is very similar to some of the WHS workflow demos we have described in previous blog posts.  In this flow we will be scanning a container and then capturing all the “assets” that are stored in that container.  Imagine that these assets are very numerous and thus are stored outside of the standard batch tracking mechanisms in AX – they are implemented in the sample as a simple asset table associated with a container.  The assumption here is that scanning assets needs to be extremely quick and thus the offline “multi-scan” mode is the perfect solution.

The state machine for this workflow is similar to our previous examples – we will have an initial scan container screen, which will transition into the multi-scan enabled “Scan Assets” state – and finally when the list is returned we process the assets and return to the initial state. 

Diagram of Workflow

You can see this reflected in the core displayForm method below.  We will not be covering some of the lower-level details of the code – please review the earlier blog posts for details on the enums and control classes necessary to facilitate the new workflow.  All the code necessary for the solution can be downloaded at the end of the post if you want to dig into the details.

Codes for displayform method

The getContainerStep is identical to our previous examples – it simply shows a simple UI and grabs the container ID from the user.  The getAssetStep method validates this container ID and calls the buildGetAssets method – which is where the UI for the multi-scan screen is built.  This is copied below:

Codes for getcontainerstep

As you can see this does not look much different that standard WHS code we have done previously.  The first input control (in this case the Asset ID field) will be used as the multi-scan field, but this code does not need to be modified in any way to support the multi-scan Page Pattern.  Instead what we need to do in ensure the correct Page Pattern is returned to the app during the correct workflow step.  To make this happen I have added a new DecoratorFactory class which will return a WHSMobileAppServiceXMLDecoratorMultiScan object at the appropriate step for my workflow – which in turn is what renders the Page Pattern to the app.

Codes for new DecoratorFactory class

Please note the attribute at the top of this class – it is the same WHSWorkExecuteMode mapping attribute used for the WHSWorkExecuteDisplayAssetScan class in the code sample above.  This is how the framework knows that this specific decorator factory class is used for this work execute mode – the enum-based attribute ties these classes together through the sysExtension framework.  The key point here is that if you need a custom decorator factory to define when exactly to switch to multi-scan mode, the above example is how you will enable this.

In the final workflow step we need to process the incoming multi-scan results. As mentioned before these are returned to the server in the same way as normal data – it will simply look like a specially formatted string in the value of the input control.  Recall the discussion above with the format of the string being <scanned value>, <number of scans>|… In my simple example below, I am parsing this string using X++ and saving the assets to a new table associated with the Container.  In this case I am not making use of the second piece of information in the collection – the number of scans was not necessary in this case.

Additional Codes

Hopefully it is clear how we loop through all the scanned assets and save each one to the new table.  After this is complete, we reset the workflow and move back to the first stage in the state machine.

Example Workflow

Now that you have seen the code to enable this in a custom workflow, let’s walk through this demo.  You can download the complete code for this project in the link at the bottom of this post – you just need to get it up and running on a dev environment and configure the necessary menu items to enable the workflow for your system.

The initial screen shows the Container ID scanning field.  Not that in the sample project I have included the necessary class to default this to the scanning mode – however you will need to set these up in Dynamics as defined here.

Scanning Screen

Scanning a container id (CONT-000000001 works if you are in USMF in the Contoso demo data) will navigate you to the next screen and enable the multi-scan Page Pattern.

multi-scan screen

Here you can enter any number of assets and the app will store them into the local buffer.  As we described above you can view the scanned assets by clicking the icon in the lower left.  After a few scans we would see the UI updated:

Screen showing multiple scanned counts

Clicking the list icon would show us the scans we have performed offline:

List of Scanned IDs

Finally clicking the “submit” button on the main screen will push the items to the server, which will then be saved to the custom table we have and the UI will display the success message.

Screen showing assets were saved

Conclusion

Hopefully this help you understand the new control scheme that was added and how it can enable fast scanning operations.  The code used for this demo is available to download here – please note that this code is demonstration code only and should not be used in a production system without extensive testing.

The post Customizing the warehouse mobile app: multi-scan pages appeared first on Microsoft Dynamics 365 Blog.

]]>
Customizing the Warehousing Mobile App http://approjects.co.za/?big=en-us/dynamics-365/blog/it-professional/2017/07/06/customizing-the-warehousing-mobile-app/ Thu, 06 Jul 2017 20:18:29 +0000 Introduction We last looked at the Warehouse Mobile Devices Portal (WMDP) in detail in a series of blog posts here, here, and here.  The last one covered how to build custom solutions and walked through building a new sample workflow for the WMDP.

The post Customizing the Warehousing Mobile App appeared first on Microsoft Dynamics 365 Blog.

]]>

Introduction

We last looked at the Warehouse Mobile Devices Portal (WMDP) in detail in a series of blog posts here, here, and here.  The last one covered how to build custom solutions and walked through building a new sample workflow for the WMDP.  This post will be updating that sample to cover some of the changes that have occurred with the Advanced Warehousing solution and the Dynamics 365 for Finance and Operations – Enterprise Edition warehousing application.

WMDP vs Dynamics 365 for Warehousing Mobile App

The Warehouse Mobile Devices Portal (WMDP) interface, which is an IIS-based HTML solution (described in detail here), is being deprecated in the July 2017 release of Dynamics 365 for Finance and Operations (see deprecated features list here). Replacing this is a native mobile application shipping on Android and Windows 10 devices.  The mobile app is a complete replacement for the WMDP and contains a superset of capabilities – all existing workflows available in the WMDP will operate in the new mobile app.  You can find more detail on the mobile app here and here.

Customizing the new Dynamics 365 for Warehousing Mobile App

The process for customizing the new mobile app is largely unchanged – you can still utilize the X++ class hierarchy discussed in the previous blog post.  However – I want to walk through some of the differences that enable customizations to exist as purely extensions.  The previous solution required a small set of overlayered code.  Moving forward this practice is being discouraged and we recommend all partners and customers create extensions for any customizations.

As before, we will be focusing on building a new workflow around scanning and weighing a container.  The inherent design concept behind the Advanced Warehousing solution is unchanged – you will still need to think and design these screens in terms of a state machine – with clear transitions between the states.  The definition of what we will build looks like this:

WHSWorkExecuteMode and WHSWorkActivity Enumerations

Just as in the previous blog post – to add a new “indirect work mode” workflow we will need to add values to the two enumerations WHSWorkExecuteMode and WHSWorkActvity.  The new enum names need to match exactly as one will be used to instantiate the other deep inside the framework.  Note that both should be added as enumeration extensions built in a custom model.  Once this has been done it will be possible to create the menu item in the UI – since the WHSWorkActvity enumeration controls the list of available workflows in the UI:

You can see the extension enumeration values in the following screenshots:

  

WHSWorkExecuteDisplay class

The core logic will exist within a new class you will create, which will be derived from the WhsWorkExecuteDisplay base class.  This class is largely defined the same way as the WMDP-based example, however there is now a much easier way to introduce the mapping between the Execute Mode defined in the Menu Item and the actual class which performs the workflow logic – we can use attributes to map the two together.  This also alleviates the need to overlay the base WHSWorkExecuteDisplay class to add support for new derived classes (as the previous WHSWorkExecuteDisplay “factory method” construct forced us to do).

The new class will be defined like this:

[WHSWorkExecuteMode(WHSWorkExecuteMode::WeighContainer)]
class conWhsWorkExecuteDisplayContainerWeight extends WhsWorkExecuteDisplay
{
}

Note that all the new classes I am adding in this example will be prefixed with the “con” prefix (for Contoso).  Since there is still no namespace support it is expected partner code will still leverage this naming scheme to minimize naming conflicts moving forward.

The displayForm method is required – and acts as the primary entry point to the state machine based workflow.  This is completely unchanged from the previous example:

[WHSWorkExecuteMode(WHSWorkExecuteMode::WeighContainer)]
class conWhsWorkExecuteDisplayContainerWeight extends WhsWorkExecuteDisplay
{
    container displayForm(container _con, str _buttonClicked = '')
    {
        container    ret = connull();
        container    con = _con;

        pass = WHSRFPassthrough::create(conPeek(_con, #PassthroughInfo));

        if (this.hasError(_con))
        {
            con = conDel(con, #ControlsStart, 1);
        }

        switch (step)
        {
            case conWeighContainerStep::ScanContainerId:
                ret = this.getContainerStep(ret);
                break;

            case conWeighContainerStep::EnterWeight:
                ret = this.getWeightStep(ret, con);
                break;
       
            case conWeighContainerStep::ProcessWeight:
                ret = this.processWeightStep(ret, con);
                break;

            default:
                break;
        }

        ret = this.updateModeStepPass(ret, WHSWorkExecuteMode::WeighContainer, step, pass);

        return ret;
    }
}

A detailed analysis of this code can be found in the previous blog post – we will skip forward to the definition of the getContainerStep method, which is where the first screen is defined.  The two methods used to define the first screen are below:

private container getContainerStep(container _ret)
{
    _ret = this.buildGetContainerId(_ret);
    step = conWeighContainerStep::EnterWeight;

    return _ret;
}

container buildGetContainerId(container _con)
{
    container ret = _con;

    ret += [this.buildControl(#RFLabel, #Scan, 'Scan a container', 1, '', #WHSRFUndefinedDataType, '', 0)];
    ret += [this.buildControl(#RFText, conWHSControls::ContainerId, "@WAX1422", 1, pass.lookupStr(conWHSControls::ContainerId), extendedTypeNum(WHSContainerId), '', 0)];
    ret += [this.buildControl(#RFButton, #RFOK, "@SYS5473", 1, '', #WHSRFUndefinedDataType, '', 1)];
    ret += [this.buildControl(#RFButton, #RFCancel, "@SYS50163", 1, '', #WHSRFUndefinedDataType, '', 0)];

    return ret;
}

Note that I am using a class to define any custom constants required for the Warehousing logic.  This was typically done with macros in the previous version – but these can cause some issues in extension scenarios.  So instead we are encouraging partners to define a simple class that can group all their constants together – which can then be referenced as you see in the code above.  The only area where this does not work is in attribute definitions – this will still need a Macro or String definition.  Here is mine so far for this project:

class conWHSControls
{
    public static const str ContainerId = "ContainerId";
    public static const str Weight = "Weight";
}

The other important thing to notice in the above code is that I have explicitly defined the data type of the input field (in this case extendedTypeNum(WHSContainerId)).  This is important as it tells the framework exactly what type of input field to construct – which brings us to the new classes you need to add to support the new app functionality.

New Fields

In the previous version of this blog we discussed the fact that since we are adding new fields to the warehousing flows that are not previously handled in the framework we must modify (i.e. overlayer) some code in the WHSRFControlData::processControl method.  This allows the framework to understand how to handle the ContainerId and Weight fields when they are processed by the WMDP framework.

In the new model these features are controlled through two new base classes to customize and manage the properties of fields.  The WHSField class defines the display properties of the field in the mobile app – and it is where the default input mode and display priorities are extracted when the user configures the system using the process described here.  The WhsControl class defines the logic necessary for processing the data into the field values collection.  For my sample, we need to add support for the ContainerId field – so I have added the following two new classes:

[WhsControlFactory('ContainerId')]
class conWhsControlContainerId extends WhsControl
{
    public boolean process()
    {
        if (!super())
        {
            return false;
        }

        fieldValues.insert(conWHSControls::ContainerId, this.data);

        return true;
    }
}

[WHSFieldEDT(extendedTypeStr(WHSContainerId))]
class conWHSFieldContainerId extends WHSField
{
    private const WHSFieldClassName Name = "@WAX1422";
    private const WHSFieldDisplayPriority  Priority    = 65;
    private const WHSFieldDisplayPriority  SubPriority = 10;
    private const WHSFieldInputMode InputMode = WHSFieldInputMode::Scanning;
    private const WHSFieldInputType InputType = WHSFieldInputType::Alpha;

    protected void initValues()
    {
        this.defaultName = Name;
        this.defaultPriority = Priority;
        this.defaultSubPriority = SubPriority;
        this.defaultInputMode = InputMode;
        this.defaultInputType = InputType;
    }
}

Obviously my conWhsControlContainerId class is not doing much – it is just taking the data from the control and placing it into the fieldValues map with the ContainerId name – which is how I will look for the data and utilize it later in the system.  If there was more complex validation or mapping logic I could place that here.  For example, the following is a snapshot of the process logic in the WhsControlQty class – this manages the logic for entering in quantity values from the mobile app:

public boolean process()
    {
        Qty qty = WHSWorkExecuteDisplay::str2numDisplay(data);
        if (qty <= 0)
        {
            return this.fail("@WAX1172");
        }

        if (mode == WHSWorkExecuteMode::Movement && WHSRFMenuItemTable::find(pass.lookup(#MenuItem)).RFDisplayStatus)
        {
            controlData.parmFromInventStatusId(controlData.parmInventoryStatusSelectedOnControl());
        }
        else
        {
            controlData.parmFromInventStatusId(controlData.getInventStatusId());
        }

        if (!super())
        {
            return false;
        }

        if (mode == WHSWorkExecuteMode::Movement && fieldValues.exists(#Qty))
        {
            pass.parmQty(qty ? data : '');
        }
        else
        {
            fieldValues.parmQty(qty ? data : '');
        }

        //When 'Display inventory status' flag is unchecked, need the logic for #FromInventoryStatus and #InventoryStatusId
        this.populateDataForMovementByTemplate();

        return true;
    }

The buildGetWeight method is very similar to the previous UI method – the only real difference is the Weight input data field.  Note that we don’t need to define a custom WHSField class for this field because it already exists in the July Release.

Error Display

There was another minor change that was necessary before I could get the expected behavior, and it points to a slight change in the framework itself.  In the previous version of the code when I reported that the weight was successfully saved I did so with an “addErrorLabel” call and passed in the WHSRFColorText::Error parameter to display the message at the top of the screen.  This same code in the new warehousing app will now cause the previous step to be repeated, meaning I will not get the state machine transition I expect.  Instead I need to use the WHSRFColorText::Success parameter to indicate that I want to display a status message but it should not be construed as an error condition.

container processWeightStep(container _ret, container _con)
…
ttsBegin;
containerTable = WHSContainerTable::findByContainerId(pass.lookupStr(conWHSControls::ContainerId),true);
if(containerTable)
{
    containerTable.Weight = pass.lookupNum(conWHSControls::Weight);
    containerTable.update();
    _ret = conNull();
    _ret = this.addErrorLabel(_ret, 'Weight saved', WHSRFColorText::Success);
    pass.remove(conWHSControls::ContainerId);
    _ret = this.getContainerStep(_ret);
}
else
{
    _ret = conNull();
    _ret = this.addErrorLabel(_ret, 'Invalid ContainerId', WHSRFColorText::Error);
    pass.remove(conWHSControls::ContainerId);
    _ret = this.getContainerStep(_ret);
}
ttsCommit;

 

Caching

The mobile app as well as the AOS perform a significant amount of caching, which can sometimes make it difficult to add new classes into the framework.  This is because the WHS code is heavily leveraging the SysExtension framework.  I find that having a runnable class included in the project which simply calls the  SysExtensionCache::clearAllScopes() method can help resolve some of these issues.

Conclusion

At this point I have a fully functional custom workflow that will display the new fields correctly in the mobile app.  You can see the container input field and weight input below.  Note that if you want to have the weight field display the “scanning” interface you can change the “preferred input mode” for the Weight EDT on the “Warehouse app field names” screen within the Dynamics 365 environment itself.

 

The Dynamics 365 for Operations project for this can be downloaded here.  This code is provided “as-is” and is meant only as a teaching sample and not meant to be used in production environments.  Note that the extension capabilities described in this blog are only available in the July 2017 release of Dynamics 365 for Finance and Operations or later.

The post Customizing the Warehousing Mobile App appeared first on Microsoft Dynamics 365 Blog.

]]>
Displaying a list of open work for warehouse workers http://approjects.co.za/?big=en-us/dynamics-365/blog/no-audience/2015/06/19/displaying-a-list-of-open-work-for-warehouse-workers/ Fri, 19 Jun 2015 01:50:00 +0000 https://blogs.msdn.microsoft.com/dynamicsaxscm/2015/06/19/displaying-a-list-of-open-work-for-warehouse-workers/ We have recently released Cumulative Update 9 (CU9) for Microsoft Dynamics AX 2012 R3. This update packs a ton of great updates and fixes we have released since CU8, and there is one notable new feature that I want to call out and discuss here.

The post Displaying a list of open work for warehouse workers appeared first on Microsoft Dynamics 365 Blog.

]]>

We have recently released Cumulative Update 9 (CU9) for Microsoft Dynamics AX 2012 R3. This update packs a ton of great updates and fixes we have released since CU8, and there is one notable new feature that I want to call out and discuss here. The warehousing team has received feedback from customers that the advanced warehousing functionality needs a way for some users to see a list of available work in the warehouse and to give them the ability to select and operate on this work through a mobile device interface. We are pleased to announce that we have released this functionality as part of CU9 and through KB3062537. This blog post will attempt to describe this functionality and show some of the ways we envision it being useful in your workflows.

Setup

We have implemented this functionality as a new menu item. Like all advanced warehouse menu item configuration, this can be configured by navigating to Warehouse management -> Setup -> Mobile device -> Mobile device menu items. From here create a new menu item, set the Mode to Indirect and select the (new) activity code “Display open work list.”

As you can see, this will display several options available to configure.

  • Records per page: Setting this to non-zero will ensure only a set number of work items are displayed in the grid at one time. This will enable forward/back buttons and paging logic within the work list page itself. Setting this to zero will disable the paging logic and show all work lines within the grid.
  • Allows users to filter by work transaction type: If this is set to true, it will display a filter option on the work list page, allowing users to quickly select the subset of work items matching a specific transaction type.
  • Work classes: This grid allows you to limit the work items displayed to a specific subset of work classes. This will be discussed in more detail later as part of filtering.

In addition to these options, there are two buttons enabled at the top of the window when this activity code is selected: “Edit query” and “Field list.” These allow you to tailor the work selected and the data displayed.

Work selection

By default, the work list will display all Work items in the current warehouse that are available to execute on (WorkStatus = Open or In process, and Frozen = No). By using the query functionality, a more specific list of work items can be selected and displayed in the list. For example, the following query will select the work items that are assigned to the Webshop Work pool and have a specific mode of delivery. This could, for example, be used to give a certain segment of users a specific list of work assigned to them for the day. Note that any sorting applied to this query will also carry over and apply to the generated work list.

Field List

Once you have determined the work query used to select the data, you will need to decide exactly what to display on the work list. This is done through the Field List button; when selected it opens a new window allowing you to configure up to seven columns of data for the work list screen.

We always display the WorkId in the first column (as you will see soon, this is how work is selected to operate upon). Each of the other columns can be configured by selecting one of the available fields in the dropdown. We have exposed all of the fields from the Work table, the Load table, and two display methods we thought would be highly useful. Note that you don’t have to fill in all seven columns – you should test the configuration and final display with the devices you plan to deploy to the warehouse to ensure the functionality works as expected.

The two display methods exposed on the third tab are the “displayFinalPutLocation” and “displayStartLocation.” These are used to provide some overall context to a work line – as sometimes it can be important to understand where the work will start and end before selecting it.

  • displayFinalPutLocation: This will iterate over all the remaining work lines after the specific work line row (which could include multiple pick/put pairs depending on the work template configuration) and display the final put location. This can be helpful to understand when different orders are directed to different loading bays and the user needs to quickly identify all work items belonging in this bundle.
  • displayStartLocation: This will show where this work will direct the user immediately upon selecting it. This can be very useful for a user to see available work that is located physically close to them in the warehouse.

In the screenshot below I have configured the work list based on a typical setup. I selected the Order Number, Work Status, Work Priority, Start/End locations, Created date/time, and the Work Template Code – all from the Work table. I could have added information from the load table as well – you will have to decide if this provides value to your warehouse employees.

Work Filtering

Since we are showing a list of work to the user, it is very important that the right set of work is displayed for that specific user. As such, we have two filtering options in place that you will need to be aware of in case you are not seeing the expected set of work for your users.

Work Class filtering

Like any work mode menu item, it is possible to associate a set of work classes to this menu item through the grid on the menu item setup form. If no work class is specified, then no filtering is performed – however, if one or more work classes are configured here, the final work list will be filtered to only include matching work classes. Note that this is in addition to any query filtering capabilities added as part of the work query process discussed above. The screenshot below shows how we could limit the work list to only show work associated with Sales orders.

Note that it would also be possible to further refine this list, and separate out the Sales picking work from the Sales loading work. In a large warehouse you might not want to show the combined list and instead show the targeted list of work applicable to the separate teams responsible.

Menu Item Filtering

We have another area where we trim results from the final work list displayed to the end user, and I anticipate this could be an area of confusion for some. Since we are displaying a list of work, we need to ensure that the user has access to a valid menu item that can process that work if they click on it to execute. As such, for each work row we do a check to ensure the current user has access to a User-Directed menu item that can process that row. This is very important to remember – if there is no User-Directed menu item for that specific work class then the work will not be displayed to the user. For example, in the base demo data set you will not see any PO Putaway work because the standard menu item is classified as User Grouping, not User Directed. Changing this (or adding a new Menu item) to User Directed will allow this work to be displayed.

Also – the user must have access to the menu item, meaning it must be accessible from their top level menu, as defined in the warehouse user setup. In does not need to be at the top level – we will iterate through the menu structure looking for a match, but it does need to be available for this user somewhere in their menu structure.

These choices were implemented to ensure we don’t show work to users that they are not allowed to process. The choice of only using the User Directed menu items stems from the fact that we are now allowing the user to select the work to execute – so it seemed the best match. Depending on feedback we will likely expand these options and offer more choices in a future release.

Work List Runtime View

Now that we have all the configuration options out of the way, let us take a look at what this screen will look like at runtime. Unlike the previous mobile device screens, this interface is targeting tablet devices and will require more screen space than we typically see in the embedded barcode scanning devices. As such we anticipate this interface being a power user view of the system, or something deployed for forklift drivers who often have a larger mounted display in their cabs.

Based on the configuration defined above, this would be the view we would see running locally in a browser:

Note that we have enabled the Filter work – which allows us to automatically restrict the list of a specific transaction type. This can be enabled/disabled at the menu item configuration screen. We have also set the paging size to 10 – which means we can only see ten records at a time and have access to the Previous/Next buttons.

All of the top level columns are sortable by clicking on them, except the Start Location and Final put location columns.

Finally – clicking one of the Work ID buttons will cause the system to load that work line and start executing it using an available user-directed menu item. In the case of multiple menu items available for processing this work class, we will first show a list of menu items and ask the user to select the specific menu item to use. We will then directly navigate to the screens responsible for processing the work and the user can continue as they typically would.

We did also receive questions whether this work list could be shown on a mobile phone or RF device with a smaller screen. As this is still outputting the same basic HTML structure as discussed in previous blogs the answer is yes, but you will obviously run into screen real-estate issues. Limiting the selected columns to only show 1 or 2 columns would be our recommended way to enable this in these scenarios.

Final Thoughts

I hope this overview of this exciting new feature was useful. The work list feature was driven directly from our interaction with customers and partners and we look forward to hearing more from the AX community.

The post Displaying a list of open work for warehouse workers appeared first on Microsoft Dynamics 365 Blog.

]]>
Barcode Scanning in the Mobile Device http://approjects.co.za/?big=en-us/dynamics-365/blog/business-leader/2015/04/28/barcode-scanning-in-the-mobile-device/ Tue, 28 Apr 2015 21:39:00 +0000 One of the major innovative features we introduced with the R3 release of Microsoft Dynamics AX 2012 was the advanced warehousing system with the warehouse mobile devices portal and the subsequent support for using embedded devices for efficient warehouse workflows.

The post Barcode Scanning in the Mobile Device appeared first on Microsoft Dynamics 365 Blog.

]]>

One of the major innovative features we introduced with the R3 release of Microsoft Dynamics AX 2012 was the advanced warehousing system with the warehouse mobile devices portal and the subsequent support for using embedded devices for efficient warehouse workflows. The key assumption with this technology was that warehouse workers would be scanning barcodes for various tasks, including, but not limited to, item identification, license plate selection, location verification, etc.

Specifically for item identification, whenever an ItemID field is presented in the mobile device screen, we allow the user to scan (or manually enter if necessary) a barcode. That barcode is then used to lookup several different values to try to identify which product has been scanned. However – this simple functionality did not support product variants and was not very extensible for other product identifiers or barcode types. As such, in the CU8 release we re-imagined this barcode scanning framework and came up with a solution that supports product variants and partner/customer customizations in a more robust way. This blog post will discuss this framework and show how it can be extended.

Purchase Order Receiving with Barcodes

First let’s walk through two common scenarios. In the first you have a Purchase Order with multiple items you want to receive, such as the following:

Purchase order with multiple items you want to receive.

When you receive this Purchase Order in the warehouse using the mobile device interface you will be asked which item you are receiving. To ensure productivity we want the warehouse worker to scan a barcode and not key in data on the device.

Purchase order receipt.

So how can we ensure that the warehouse worker can scan a barcode and have the system recognize the appropriate item? As you will see shortly, there are multiple identifiers that can be used here, but let us first examine how the actual barcode functionality within AX would be used. Within the Product information management module we can configure barcodes for our items. In the image below you can see that I have setup a barcode for each of the items we are concerned with.

Product information management module.

With this configuration I can now scan (or manually enter) the barcodes and the system will know which item I am receiving.

Purchase order receipts.

Note that this process would also work with a product variant, and the barcode can be used to identify exactly which product variant I am receiving.

Item barcode overview tab.

Product Confirmation with Barcodes

Another scenario that we have enabled is the ability to perform product confirmation through the mobile device interface. This is detailed in a blog post here. The basic idea is that you want the warehouse worker to be forced to scan something to ensure they have picked the correct product and/or from the correct location. This can help reduce errors in the warehouse – but we still want to ensure productivity is as high as possible. In this vein we have enabled the same barcode scanning framework discussed above into this process – allowing the warehouse worker to scan a barcode which is then used to lookup the product in a variety of contexts.

For example, if we have product confirmation enabled and we have some Sales Order picking work to complete on the mobile device, we would see the following screen:

Sales orders pick.

In that second Item field, we could scan the barcode we defined above (even if this was a variant), to proceed with the pick. However – we are not just limited to the barcodes defined with AX, we actually have other identifiers which might make more sense to uniquely identify this product.

Item Scanning Framework

To enable the above scenarios, and others like it, we released a set of classes as part of CU8 that manage our item identification search process. This is designed as a flexible and extensible framework – with individual search processors chained together, each one looking for data in a particular area. Once one of them finds matching data, a “SearchResult” object is returned to the caller.

On a CU8 box, if you look at all the classes that start with InventInventItemSearch* you will find this small framework:

  • InventInventItemSearch
    • Main entry point to the search functionality – also creates the child search processors and iterates through the chain
  • InventInventItemSearchProcessor
    • Base class for creating new search processor functionality
  • InventInventItemSearchBarcode, InventInventItemSearchExternal, InventInventItemSearchGTIN, InventInventItemSearchItemAlias, InventInventItemSearchItemId
    • Search processors we ship in CU8 for looking up item identifiers in various locations in the application
  • InventInventItemSearchResult
    • Rich object used to return the data found

When the search method is invoked on the InventInventItemSearch class, the following sequence of SearchProcessors is used to look for a matching item (I have also included the field used to lookup the data):

  1. InventInventItemSearchItemId
    • InventTable.ItemId
  2. InventInventItemSearchItemAlias
    • InventTable.NameAlias
  3. InventInventItemSearchBarcode
    • InventItemBarcode.ItemBarCode
  4. InventInventItemSearchExternal
    • CustVendExternalItem.ExternalItemId
  5. InventInventItemSearchGTIN
    • InventItemGTIN.GlobalTradeItemNumber

When a warehouse user scans a barcode to lookup a product, we don’t simply look in the barcode table. Instead we iterate over the set of defined search processors and look for a matching record in the various defined tables. Practically speaking, this means the warehouse worker could scan/enter identifiers such as the Item Alias or External identifier – which may be more appropriate for certain items.

This is utilized on the mobile device within the WHSRFControlData::processControl method:

case #ItemId:
        if (_data != "@WAX402")
        {
            localInventItemSearch = InventInventItemSearch::construct();
            localInventItemSearchResult = localInventItemSearch.search(_data);
            if (localInventItemSearchResult)
            {
                itemId = localInventItemSearchResult.parmItemId();
                itemInventDim = InventDim::find(localInventItemSearchResult.parmInventDimId());
            }
            else
            {
                errorMessage = "@SYP5070015";
                hasError = true;
                break;
            }

Note that if a barcode has been scanned that supports identifying the product dimensions the InventDim will also be returned – and thus can be used to determine the exact variant being scanned.

Extension and Customization

While this is interesting in itself, what I really want to discuss is the ability for our partners and customers to extend this framework to suit their specific business needs. We will cover two areas of customization that are available to you: 1. adding a new search processor to handle a specific barcode format, and 2. Extending the search result object to enable more information to be retrieved from barcode formats.

Creating a New Search Processor

A common request we see is the ability to read out product identifiers from within the GSI-128 barcode format. In these cases the barcode could be encoding a lot of other information related to the product, such as batch, expiration dates, etc – and we may only want to extract the product identifier out of a fixed location within the barcode format. This is a perfect example of something that is easy to add to AX via a custom search processor.

Let’s say that our products have long barcodes such as the following example: 02050450004144213736922724210090801. Perhaps the 13-character product identifier is embedded within this barcode format starting at the 4th character (5045000414421). How would we build a processor to parse this data correctly?

We would first add a new class to AX extending the InventInventItemSearchProcessor base class. We would then need to implement the search method, which is what is invoked by the search framework as it iterates over the available SearchProcessors. The actual code for performing the string slicing is very simple – and the entire SearchProcessor is below:

public class InventInventItemSearchBarcodeEAN128 extends InventInventItemSearchProcessor 
{
    public InventInventItemSearchResult search(InventInventItemSearchItem _searchValue) 
    {
        InventItemBarcode inventItemBarcode;
        if (strLen(_searchValue) > 16) 
        {
            inventItemBarcode = InventItemBarcode::findBarcode(subStr(_searchValue, 4, 13), false, true);
        }
 
        return inventItemBarcode.RecId == 0 ?
            null : 
            InventInventItemSearchResult::newFromParams(inventItemBarcode.ItemId,
                InventDim::find(inventItemBarcode.InventDimId),
                inventItemBarcode.UnitID);
    }
}

The other change that is required is to add our new SearchProcessor to the list of available SearchProcessors. This is done in the InventInventItemSearch::createSearchProcessors method. Note that when you customize this list you can choose where in the sequence your new SearchProcessor should process the data – and if you want to remove SearchProcessors that might not be relevant to your specific scenario. In this case I am adding our new SearcgProcessor to the head of the list:

protected void createSearchProcessors()
{
    searchProcessors = new List(Types::Class);  
    
    searchProcessors.addEnd(new InventInventItemSearchBarcodeEAN128()); 
    searchProcessors.addEnd(new InventInventItemSearchItemId()); 
    searchProcessors.addEnd(new InventInventItemSearchItemAlias()); 
    searchProcessors.addEnd(new InventInventItemSearchBarcode()); 
    searchProcessors.addEnd(new InventInventItemSearchExternal()); 
    searchProcessors.addEnd(new InventInventItemSearchGTIN());
    return;
}

Extending the Result Data

Another common scenario customers ask for is the ability to extract more information from a barcode than what we currently support. Barcode formats such as GS1-128/EAN128 can encode a cavalcade of data, such as batch number, expiration dates, physical dimensions, etc. We have some support in the system for these format in our BarcodeEAN128 class – which includes a decode method to parse this barcode format. We will use this functionality to perform the parsing of the barcode.

It all starts with the InventInventItemSearchResult class. This is a small class that is returned from the search framework when matching data is found. Currently this class contains the following fields:

  • ItemId
    • Always filled in by the SearchProcessors when a matching item is found within AX
  • InventDimId
    • Filled in when a matching variant is found for a GTIN/Barcode lookup
  • UnitOfMeasureSymbol
    • Filled in when a matching variant is found for a GTIN lookup

In our simple example we will have a barcode that encodes the batch information after the product identifier. The product identifier will be a fixed 14-character field followed by the batch identifier. For example, product 0000000161_202, batch number B123 would have a barcode such as the following:

0000000161_202B123

The human-readable format for this barcode would be the following (in the GS-128 format):

(01) 0000000161_202 (10) B123

And the actual scanned text of this barcode would look something like this:

]C1010000000161_20210B123]C1

In the AX BarcodeEAN128 implementation the character string “]C1” is designated as the Function Code 1 or FNC1. This is used in the GS-128 spec to indicate application identifiers and variable length fields (such as the batch id). There is much more to GS-128 parsing than can be covered in this blog post – for more information start here.

To get the batch information extracted, first we will add the new data to the InventInventItemSearchResult result object. Using the same pattern as the existing parameter fields gives us the following code:

///  
/// Class used to return data from the InventInventItemSearch search functionality. 
///  
public class InventInventItemSearchResult 
{
    ItemId               itemId;
    InventDimId          inventDimId;
    UnitOfMeasureSymbol  unitOfMeasureSymbol;
    InventBatchId        batchId;
}
public InventBatchId parmBatchId(InventBatchId _batchId = batchId)
{
    batchId = _batchId;
    return batchId;
}

 

Now I can make a new SearchProcessor to extract the embedded Batch and ItemId information. This might look something like this:

public class InventInventItemSearchEmbeddedBatch extends InventInventItemSearchProcessor
{
    public InventInventItemSearchResult search(InventInventItemSearchItem _searchValue)
    {
        InventTable                    inventTable;
        InventInventItemSearchResult   result = null;
        BarcodeEAN128                  barcode = BarcodeEAN128::construct();
        barcode.decode(_searchValue);
        inventTable = inventTable::find(barcode.itemId());
        if (inventTable.RecId != 0)
        {  
            result = InventInventItemSearchResult::newFromItemId(barcode.itemId());
            result.parmBatchId(barcode.batch());
        }
        return result;
    }
}

Consuming the returned batch information is done by checking for the batch parameter data and processing the data as if the user has entered it directly into the batch text control. This can be done by simply modifying the code we saw earlier in the WHSRFControlData::processControl method:

case #ItemId:
    if (_data != "@WAX402")
    {
        localInventItemSearch = InventInventItemSearch::construct();
        localInventItemSearchResult = localInventItemSearch.search(_data);
        if (localInventItemSearchResult)
        {
            itemId = localInventItemSearchResult.parmItemId();
            itemInventDim = InventDim::find(localInventItemSearchResult.parmInventDimId());
            if (localInventItemSearchResult.parmBatchId() != '')
             {
                 this.processControl(#BatchId, localInventItemSearchResult.parmBatchId()); 
             }
        }
        else
        {
            errorMessage = "@SYP5070015";
            hasError = true;
            break;
        }

 

To make this work I also had to modify the processData method to not overwrite the Batch information.

case #BatchId:
    if (inventBatchId == '')
    {
        if (mode == WHSWorkExecuteMode::AdjustmentIn)
        {
            if (licensePlateId)
            {
                if (WHSLicensePlate::exist(#LicensePlateId))
                {
                    inventBatchId = this.getBatchId();
                }
            }
        }
        elseif(workLine.WorkType != WHSWorkType::Count)
        {
            inventBatchId = this.getBatchId();
        }
    }
    fieldValues.insert(#BatchId, inventBatchId);
    break;

This will now allow our users to automatically select the batch by scanning one of our specially formatted barcodes. As an example, suppose we have a location containing a number of batch-controlled items and we want to move some items from the location using the mobile device. Using the standard functionality, we would need to scan or enter the location, then scan or enter the product identifier, and then enter the batch number. Using the embedded batch barcode we defined we can skip one of these steps.

Batch controlled items.
Batch controlled items with batch number, quantity, unit, and inventory status.

Note that I ran into a slight implementation problem with this example due to the ItemId EDT length definition. When we build the mobile device UI we use the EDT definitions as the maximum length of allowable input. Since the ItemId is only allowed to be 20 characters long, I was not able to scan these barcodes that could end up much longer than 20 characters. Instead of modifying every page in the mobile interface, I updated the WHSWorkExecuteDisplay::buildControl method to extend the maximum allowed length when building an ItemId-related field.

container buildControl(str             _controlType,
                       str             _name,
                       str             _label,
                       int             _newLine,
                       str             _data,
                       ExtendedTypeId  _inputType,
                       str             _error,
                       int             _defaultButton,
                       boolean         _enabled = true,
                       str             _selected = '',
                       WHSRFColorText  _color = WHSRFColorText::Default)
{
    container      ret         = conNull();
    int            length      = -1;
    str            typeStr     = #TypeUndefined;
    SysDictType    sysTypeDict = new SysDictType(_inputType);
    Types          type;
    if (_inputType == extendedTypeNum(ItemId)) 
     { 
         length = 100;
     }
    else if (_inputType != #WHSRFUndefinedDataType && sysTypeDict)
    {
        type = sysTypeDict.isTime() ? Types::Time : sysTypeDict.baseType();
        typeStr = enum2Symbol(enumNum(Types), type);
        if (type == Types::String)
        {
            length = sysTypeDict.stringLen();
        }
    }

Conclusion

Hopefully this gives you an idea of some of the things that are possible with our new item search functionality framework in the mobile device. Using this effectively will be key for enabling truly modern and effective workflow processes in your warehouse.

The post Barcode Scanning in the Mobile Device appeared first on Microsoft Dynamics 365 Blog.

]]>
Creating Custom Solutions with the Warehouse Mobile Device Portal http://approjects.co.za/?big=en-us/dynamics-365/blog/no-audience/2015/03/13/creating-custom-solutions-with-the-warehouse-mobile-device-portal/ Fri, 13 Mar 2015 01:24:00 +0000 https://blogs.msdn.microsoft.com/dynamicsaxscm/2015/03/13/creating-custom-solutions-with-the-warehouse-mobile-device-portal/ This is the third in the series of blog posts focusing on the warehouse mobile device portal (WMDP).

The post Creating Custom Solutions with the Warehouse Mobile Device Portal appeared first on Microsoft Dynamics 365 Blog.

]]>

This is the third in the series of blog posts focusing on the warehouse mobile device portal (WMDP). This portal was released as part of the advanced warehousing solution in Microsoft Dynamics AX 2012 R3 – and we have been trying to explore the powerful ways you have to customize the warehouse workflow for your business. In this post we will dive deep into customizing and extending the mobile device functionality in order to build new mobile workflows for your users.

Example Workflow Design

To give a better understanding of the design of mobile portal workflows, I thought it would be interesting to create a new workflow and walk through the various changes required to get it up and running in Microsoft Dynamics AX. I have tried to select an example that is simple enough to work through in a blog post, but interesting enough that it will provide some value when you are trying to build your own workflows.

The new process we will enable is a “re-weigh” container mobile device workflow. Currently in AX there is no way to weigh a container via the mobile device – but I could imagine a warehouse having a scale at a final inspection point staffed with a mobile device user and capturing the final packed weight. We will create that customization now.

State Machine

We will first create a state machine model that represents the workflow we want to enable for our users. Like any good state machine, this should have clear states and transitions between them. My workflow will be very simple – I will present a screen asking for the ContainerID (assuming the user can scan or enter the ContainerID from a barcode). If this ContainerID is successfully validated we move to the next screen – in which we ask for the weight. If an invalid ContainerID was entered we remain on the same initial screen. When the user enters a valid weight we store the weight in the Container structure and move back to the initial screen. Visually this workflow is depicted below:

State machine model that represents the workflow we want to enable for our users.

WHSWorkExecuteDisplay Code

Since this workflow does not directly relate to a Workline, we will be adding it as an “Indirect Mode” MenuItem. Having this as an Indirect mode item means we will need to add an option to the Activity Code list – which is what is displayed when you select Indirect mode:

Mobile device menu items.

This list is populated from the WHSWorkActivity enumeration. So our first step will be to add a new enumeration value to this list. We will call the activity “WeighContainer,” with an appropriate label that describes the workflow.

WHS work activity enumeration list.

Another enumeration is required to be updated when you are adding any new workflow into the mobile device framework. The WHSWorkExecuteMode enumeration is a superset of the WHSWorkActivity enumeration, as it contains all the Indirect work mode classes as well as all the work creation workflows and work processing workflows. This is essentially the master list of all mobile device work processing workflows. We will need to add a matching enumeration value to this – please ensure the names and labels match, as this is used to convert from one to the other deep within the mobile device framework (I found this out the hard way after debugging for far too long).

WHS work execute mode enumeration list 1.
WHS work execute mode enumeration list 1.

I will also add a new enumeration to the system that will represent the states of my state machine diagram. This is not absolutely necessary – but will make reading the code easier.

Weigh container step list.

Once we have these building blocks in place we can add the core processing class. This is the class that will implement the state machine logic and be responsible for constructing the user interface (or coordinating other classes to do it). It must extend the WHSWorkExecuteDisplay base class. We will call ours WHSWorkExecuteDisplayContainerWeight.

WHS work execute display container weight.

The key method to implement is displayForm – as discussed in the previous post this is what is invoked by the framework when requests are mapped to this workflow class. There are many examples in R3 and CU8 of displayForm methods – I have tried to simplify the method and show basic patterns I see as common across many of the classes in the example below:

Container display form method.

The basic structure of this method is that it accepts a container with the data passed in from the incoming request, processes this data, and returns a new container with the response to the user. The pass object (which is a member variable of the base WHSWorkExecuteDisplay class) is constructed based on the incoming container. This will be used to test for values that have been stored in previous steps in the workflow.

The test for an error condition is a common pattern – we are checking to see if the user has already been presented with an error message and if so removing the first control from the control collection. This is because when an error is displayed (for example telling the user that they have entered an invalid ContainerId) – it is added to the top of the controls collection. If we are seeing it again then the user is most likely trying to correct the error and if we don’t remove it the error label will persist through to the next screen.

The next section – where I switch based on the current step (which is also a member variable of the base class) is the realization of the state model concept. Depending on exactly what step the user is in determines the UI that is built and/or the processing that needs to occur. This is where we use the new enumeration defined for our state steps. Note the last call is to updateModeStepPass – this is a base class method that will persist any changes to the mode, step, or pass variables which may have changed through the processing of the user request.

Let’s dig into the first step of the process. We have the following methods to support us. Note that I probably could have combined these into a single method, but I wanted to have a separate method for building a “GetContainerId” screen for re-use in the future. If you look at the WHSWorkExecuteDisplay base class you can see many of these helper build* methods (for example buildPick, buildPut, buildGetWorkId, etc).

Private container get container step method.

The buildControl method is used to construct the returned container, populating it with the correct Control container structure. Since this method is so important, let’s talk about each of the parameters.

NameData typeDescription
_controlTypestrThis tells the framework what type of HTML control to build for the provided data. This must be one of the following macro definitions (defined in WHSRF):

#define.RFButton(‘button‘)
#define.RFLabel(‘label‘)
#define.RFText(‘text‘)
#define.RFPassword(‘password‘)
#define.RFListbox(‘listbox‘)
#define.RFCombobox(‘combobox‘)
#define.RFError(‘error‘)

 

_namestrName used for the control in the rendered HTML. Also used as the key to store data persisted in the control within the WHSRFPassthrough Map object.
_labelstrText to display to the user in the UI for this control.
_newLineintField that specifies how this control should be rendered in the UI. If a 1 is passed it means this control should be situated on a new line in the HTML table. If a 0 is passed this control will remain on the same line as the previous control(s).

Note this only applied to the default display settings view page used to render the HTML pages. If you have customized the display settings view it is possible this no longer renders in the same way.

_datastrData to display within the control (for example the data to include in a textbox control). Does not apply to label or button controls.
_inputTypeExtendedTypeIdDataType of the field – important for data entry fields so the correct validation rules can be applied by the framework.
For controls that do not require validation the macro
#WHSRFUndefinedDataType can be used.
_errorstrIndicates if this control contains validation errors – used to help the user understand which controls contain validation or input errors information.
_defaultButtonintIndicates the specified button should be executed as the default form submit – for example when the user presses the enter key in the UI. This is typically applied to the “OK” button in the forms.
_enabledbooleanIndicates if the control should be editable in the UI or if it should be displayed in a read-only mode.
Optional – defaults to true.
_selectedintIf set to 1 this will be the currently active control when the user comes to this page.
Optional – defaults to empty string.
_colorWHSRFColorTextColor to set the control textual data.
Optional – defaults to WHSRFColorTest::Default.

In my simple UI I create a label instructing the user what to do, an input field for the ContainerId, and an OK/Cancel button pair. Note that I set the ContainerId data based on what I find in the WHSRFPassthrough object (in case it was set previously but we are back in this step because of a validation error, for example).

Note also that I use the macro #ContainerId for the name of the control. The included #WHSRF macro contains a long list of available names for all of the control types used in the shipped code – however ContainerId is not one of these options. This will cause us some problems later on when we are trying to process the data from the user. We will need to add #ContainerId and #Weight as available control names to the list of control names in the macro #WHSRF. Here is just a snippet with my additions in the bottom of the list:

Code snippet.

Let’s assume the user enters a valid ContainerId and clicks the OK button. This will go through the processing steps discussed above and eventually call our displayForm method with the step value set to 1/WeighContainerStep::EnterWeight (because that is what we set it to after constructing the “GetContainerId” UI). So the getWeightStep method will now need to determine if the ContainerId is valid and keep the user on this step if it is not or display the “GetWeight” UI if it is valid.

Private container get weight step method.

The first few lines of this code are a pattern you will see quite often in the codebase for the mobile device. The goal is to take the incoming data from the user and combine it with the existing state data – as well as provide an automatic way of processing the controls on a form and indicate any validation errors. If all goes well the pass Map object will be updated with the data provided by the user and the _ret container will be set to the regenerated container with both the standard controls as well as the user input.

The central if statement checks to ensure we have data entered by the user and does the validation against the WHSContainerTable. Note that we pull out the ContainerId from the pass object – this is another common pattern used to find data used throughout the framework. If the validation is successful the “GetWeight” UI is built and the step variable is advanced to WeighContainerStep::ProcessWeight (2). If the validation fails we display an error to the user, after which we rebuild the “GetContainerId” UI screen.

There is one additional framework change we will need in order to make this code work. Within the WHSRFControlData::processData method the code calls WHSRFControlData::processControl for each of the controls on a form. This method contains specific processing logic for each of the different fields defined in the system. This enables common and consistent processing of fields by the framework each time they are used – but it does mean that when you want to add new field types to the framework this method needs to be expanded. In our case we have added the ContainerId and Weight types – so we need to add the following code to the end of the processControl method:

Code added to the end of the process control method.

The final method, processWeightStep, is very similar to the previous – except now when we get the Weight value we update the WHSContainerTable row with the new value. This code can be found in the attached project.

Weigh Container Usage

We now have everything in place for us to utilize the new workflow we created. After creating/importing the code above we will need to ensure to build the IL so the mobile portal can reference the new code. Once this is done we can add the new logic as a Menu Item and add it to the Menu.

Mobile device menu items.

Menu Item Definition

Mobile device menu name and inventory.

Adding the new Menu Item to a Menu.

Now we can execute this workflow from the mobile device portal.

Executing workflow from the mobile device portal.

Initial screen.

Initial screen.

Entering an invalid container ID – remain on the same state with an error message.

Enter the weight.

Entering a valid ContainerId will move us to the next state – displaying the Weight entry page. Entering a weight on this form and clicking OK will cause us to store the weight in the WHSContainer record and move back to the first state.

Customizing Existing Workflows

While the above discussion is useful for creating entirely new workflows, many customers and partners simply want to augment the existing workflows with new data and/or processes. Microsoft Dynamics AX 2012 R3 ships with all of the code for the WHS workflow processes, and this can be used to decide where exactly to add custom logic and code into the system. This means if there is an existing workflow that implements most of the desired functionality, adding the missing functionality is simply a matter of augmenting the existing code – much like adding customizations into “core” AX logic.

For example, you might have a requirement that certain items display a “Fragile” label on the mobile device when directing users to pick them. This could be a special class of items that are deemed especially fragile, which you have added to the production configuration through some sort of customization. Adding this logic to the standard Pick screen is simply a matter of finding the common code that builds the Pick screen and adding new X++ logic to enable this new feature.

Fragile Pick

I have defined the fragile attribute of an item using filter codes within the Warehouse fast tab of the Product information screen. This might not be the best way to define this – I simply wanted an easy way to show the WMDP displaying different UI elements based on the product. My configuration is below:

Release product details.

Once this is in place we can look at the WHSWorkExecuteDisplay base class. This class contains many generic builder methods that are used throughout the framework when creating the workflow UI. Fortunately for us there is a buildPick method – which is used by the framework whenever a picking screen is displayed to the user. We will add our code into this method at the very end – to ensure we are not changing any of the code that is used to build the pick screens currently.

Code that is used to build the pick screens currently.

In the code above you can see we are checking for the Fragile code – and displaying a new label element in the UI if it is found. Obviously in a production code you would want to use labels for any display strings. If we load this into the browser and perform a pick on a “fragile” item we will see the following UI:

Performing a pick on a fragile item.

Obviously this is not very attention-grabbing. Fortunately, if you have been following these blog posts about the WMDP you know we can customize the UI through CSS. Let’s modify the default CSS file so as to make this label much more visible. Since we know the name we assigned the new label (FragileLabel) – we can build the css to target this.

CSS to target the new label named fragile label.

This will now display the following – which is much more visible.

Sales order pick.

Client-Side Notification

It is also be possible to inject code that detects if the fragile label is being displayed and perform additional client-side operations. One common request we hear is to play a beep or perform some sort of haptic feedback to the user to ensure they pay attention to the screen in this sort of situation. While these sorts of customizations are very device-specific and outside the scope of this article, adding the following code to the “mobile device display settings view” page will allow you to write code that would respond to the fragile label being present on the page:

Code that would respond to the fragile label being present on the page.

In the default configuration the above code would be added to the DisplayIEOS.aspx file, located in <AX Installation directory>\6.3\Warehouse Mobile Devices Portal\<WMDP instance folder>\Views\Execute.

This software is provided “as is”, without warranty of any kind, express or implied.

Conclusion

I hope this was a useful overview of the Warehouse Mobile Device portal architecture and how to extend the workflows. As partners and customers utilize the new advanced warehousing functionality it will become more important to extend and enhance what is included in Microsoft Dynamics AX 2012 R3. Please let us know of any enhancements or issues you experience with this functionality – we are always interested in making it more useful for our partners and customers.

The post Creating Custom Solutions with the Warehouse Mobile Device Portal appeared first on Microsoft Dynamics 365 Blog.

]]>
Warehouse Mobile Device Portal Architecture http://approjects.co.za/?big=en-us/dynamics-365/blog/business-leader/2015/03/03/warehouse-mobile-device-portal-architecture/ Tue, 03 Mar 2015 01:36:00 +0000 https://blogs.msdn.microsoft.com/dynamicsaxscm/2015/03/03/warehouse-mobile-device-portal-architecture/ This is the second part of a blog series on the Warehouse mobile device portal (WMDP) introduced in Microsoft Dynamics AX 2013 R3. The first part can be found here.

The post Warehouse Mobile Device Portal Architecture appeared first on Microsoft Dynamics 365 Blog.

]]>

This is the second part of a blog series on the Warehouse mobile device portal (WMDP) introduced in Microsoft Dynamics AX 2013 R3. The first part can be found here. The mobile device portal is designed to provide warehouse workers with an interface into the advanced warehousing system of Microsoft Dynamics AX and is intended to be used on a wide variety of devices within the warehouse. This post is designed to help you understand the overall architecture of the mobile device portal and how the existing code operates to generate the mobile device pages.

WMDP – Architecture

To understand how the mobile portal ultimately renders the warehouse work on the mobile device, it is important to take a step back and see how the overall data flow operates and all of the major components in the solution. The following picture shows the high level objects that constitute the warehouse mobile portal architecture.

High level objects that constitute the warehouse mobile portal architecture.

The far left represents the end user device, which displays the final HTML in a browser or emulator. As mentioned in the previous blog post, the mobile portal is designed to render across a wide variety of devices and form-factors, and we have tried to ensure the generated HTML is widely compatible across browsers and devices.

IIS, or Internet Information Services, executes on the server and acts as the Web server for the mobile device portal. Within IIS the warehouse mobile device portal executes as an ASP.NET web application. This application accepts the HTTP communications from end-user browsers and translates these into web service calls to the AOS endpoint – ultimately resulting in new webpages being generated for the end-user, based on their current workflow state and data entered and/or returned from the Application object server (AOS).

The AOS hosts the WHSMobileDeviceService endpoint as an Application Integration Service endpoint. This is the entrypoint into AX for all advanced warehouse functionality exposed by the mobile portal. You can see the details of the WHSMobileDeviceService in the AOT under the Services node, and you can configure the exposed endpoint within AX by navigating to System administration -> Setup -> Services and Application Integration Framework -> Inbound ports. The configuration for this endpoint on my machine can be seen below:

Inbound ports.

WMDP – Data Flow

Let’s walk through a typical data exchange from the client-side device to the AOS and back. This will illustrate how each of these components operate within the framework and what they contribute to the overall solution.

Step 1 – Client-side HTTP Form Post

How each of these components operate within the framework and what they contribute to the overall solution.

All communication is initiated from the client-side via standard HTTP operations. The initial webpage is retrieved via an HTTP GET operation – providing the starting point for the mobile device. After this all interactions with the server-side portal are conducted with HTTP Form POST commands. Remember that one of the design goals for this portal was to ensure we could support low-power and low-capability devices. As such the portal is not designed as a fancy JavaScript single-page app – instead we rely on standards-based, tried-and-true HTML4/HTTP functionality that should be available to most devices with an Internet browser.

The following are two examples of this form data being posted from the client-side browser. Note that the username/password fields are not encrypted in transit – which is why we recommend the mobile portal be exposed only on a trusted private network or to ensure secure transport protocols are implemented between the client-side device and the server (i.e. HTTPS). You will also note the various data fields are passed to the server as form/url-encoded data as well as the session token used to determine the user authentication and authorization details.

ClickedButton=&IsMenu=False&SessionGuid=ZZZ&__RequestVerificationToken=
XXX&UserId=42&Password=1

ClickedButton=&IsMenu=False&SessionGuid=ZZZ&__RequestVerificationToken=
XXX&PONum=123&Qty=1&UOM=

Step 2 – WMDP Website Processing

Inside the WMDP website several validations occur on the incoming data, including determining if the mobile user is valid and currently still logged in. The incoming data is validated and the data is combined with an XML structure of the current workflow UI to create a Control XML structure. This XML is used to communicate with the WHSMobileDevicesService AIF endpoint. A sample of this, containing the controls constructed from a login submission request, would look like the following:

A sample containing the controls constructed from a login submission request.

Step 3 – WHSMobileDevicesService Integration

The XML created by the mobile portal is now submitted to the endpoint exposed in the AOS.

The XML created by the mobile portal is now submitted to the endpoint exposed in the AOS. The address of this endpoint is defined in the web.config file of the mobile portal website; by default this is assumed to be on the same machine as the mobile portal – but this can be reconfigured for a multi-box deployment.

Step 4 – WHSMobileDevicesService Processing

The final step in the inbound chain, this is where the incoming request is processed by the AX Work framework and the next step in the workflow is generated and returned to the caller. This is the set of X++ classes we will dive into later in this post – and this is where it is possible for you to inject your own code into the system to represent custom workflows and operations you want to enable in your warehouse. It is also possible to customize the workflows shipped as part of AX R3/CU8 – as you will see later.

The final step in the inbound chain, where the incoming request is processed by the AX Work framework.

Step 5 – Control XML Returned

Ultimately all of the processing that occurs within the AOS will result in a package of XML being returned to the caller. This will contain the structure and content of the controls to ultimately display in the generated HTML – including any error or validation error messages that need to be displayed to the user.

The structure and content of the controls to ultimately display in the generated HTML.

The following XML is what might be returned from the AOS when the user is conducting a PO Receiving workflow but has entered an incorrect PO number. You can see the error label with the information to inform the user, and you can see all of the other controls that make up the structure of the user interface. You will also note that now that we have authenticated this user we have an additional node in the XML containing the session GUID to track the user authentication information.

XML that might be returned from the AOS when the user is conducting a PO Receiving workflow but has entered an incorrect PO number.

Step 6 – WMDP Processing

The WMDP website uses the Control XML returned from the WHSMobileDevicesService endpoint to construct the final HTML that will be returned to the client device. This HTML is constructed based on the controls defined in the XML, as well as the mobile settings view page discussed in the previous blog post. The goal is ultimately to have the correct HTML generated for the client device/user for the specific workflow step they are currently executing.

Step 7 – HTML Returned

Control XML returned from the WHSMobileDevicesService endpoint to construct the final HTML.

The final step in the process is returning the constructed HTML back to the client device. As discussed above, this HTML is designed to be widely compatible and standard-based back to HTML4, such that any device with a browser should be able to operate within the warehouse portal.

The basic format of the constructed HTML is created by the display settings view, which controls the layout and construction of the HTML structure. The default view creates an HTML table and populates the rows of the table with the returned controls.

Default view creating an HTML table and populating the rows of the table with the returned controls.

WMDP – AOT Classes

The above walkthrough gives us a better idea of the overall data flow into and out of the mobile portal. If we go back and expand “Step 4” a bit – we will now cover what exactly happens within the AOS when a request comes in from a mobile device and how that is translated into a result to the user.

Recall that the endpoint the WMDP uses to communicate with the AOS is the WHSMobileDevicesService. This exposes five operations, but the primary one we will deal with in detail in the getNextFormHandheld. This is the operation invoked by the WMDP to determine the next step in the current workflow for the user.

WHS mobile devices service.

The high-level flow of classes involved in constructing the response to the user can be seen below. We will walk through this tree and discuss what each of the various components are doing along the way. All of these classes can be found in a standard Microsoft Dynamics AX 2012 R3 deployment if you want to follow along.

High-level flow of classes involved in constructing the response to the user.

At the highest level – the WHSMobileDevicesService service is responsible for exposing the operation endpoints to external processes. As we described above, the getNextFormHandHeld operation consumes and returns XML data. This service is backed by the WHSMobileDevicesServiceFacade class which implements the operation methods. In turn, this class utilizes the WHSWorkExecuteDisplay:: getNextFormHandheld method to start the actual logic of generating the return XML.

I consider the WHSWorkExecuteDisplay::getNextFormHandheld method as the true entrypoint to the WMDP Work Framework. This is where I put a breakpoint when debugging and want to see exactly what is entering the system from the client and what we are returning from the various Work X++ classes. The method itself is very straightforward:

public static str getNextFormHandHeld(str _xml)

{

container con;

con = WHSWorkExecuteDisplay::readXML(_xml);

return WHSWorkExecuteDisplay::getNextFormXML(con);

}

The logic is very simple – the incoming XML is first read and a container is constructed. This is then used when building the return XML.

The WHSWorkExecuteDisplay::readXML method converts the incoming Control XML into a semi-structured container format. This container is composed of 3+ containers – each of which are used throughout the processing and rendering process. I have tried to capture a high-level overview of the container below.

WHS container (con)
Index 1
#StateInfo
State Info container 
 Index 1WHSWorkExecuteMode enumeration
 Index 2State Step
Index 2
#PassthroughInfo
PassthroughInfo container<WHSRFPassthrough Map object>
 Index 1Map identifier
 Index 2Type of Keys stored in this map (String)
 Index 3Type of Values stored in this map (String)
 Index 4Number of values in the Map
 Index nKey Name
 Index n+1Value
Index 3+
#ControlsStart
Control Container 
 Index 1Control Type
 Index 2Control Name
 Index 3Control Label
 Index 4Newline Indicator
 Index 5Control Data
 Index 6Control Data Type
 Index 7Control Data Length
 Index 8Error Indicator
 Index 9Default Button Indicator
 Index 10Selected Indicator
 Index 11Control Color

In the WHSWorkExecuteDisplay::getNextFormState we have code that consumes this container, primarily the StateInfo container, in order to figure out the correct class to load in order to process the user request.    

Private static server container.

You will note the mode and step variables are extracted out of the container structure using the various macros defined either in the base class WHSWorkExecuteDisplay or in the global #WHSRF macro definition.

After the validation of the user session information, the critical step in this code is the call to the WHSWorkExecuteDisplay::construct method. This is a factory method that accepts the current mode we are operating under and creates the appropriate WHSWorkExecuteDisplay derived class to handle the rest of user interface creation and workflow processing. Here is a snippet of this code:

Code snippet of factory method that accepts the current mode we are operating under and creates the appropriate WHS Work Execute Display derived class to handle the rest of user interface creation and workflow processing.

If you were to define your own processing class you would need to hook some code into this method to ensure the new class is created when the framework requests that new WHSWorkExecuteMode class.

Once the correct WHSWorkExecuteDisplay* class has been constructed the framework will invoke the displayForm method on this class – passing in the container and the specific button clicked in the UI (if any). This method is the central location to define the state machine of the various workflows. The current state the user is executing is located in the step variable, and this can be updated to reflect movement in the state machine model. In addition, the WHSRFPassthrough Map object discussed above is used to pass data between the various classes/methods involved in creating the final output.

Here is an example of the displayForm method. It is a very common pattern to have the central switch statement on the step member variable – with each case representing a different state in the state machine this class is representing.

Example of the display form method.

Next Time

I hope this was a useful overview of the Mobile Device Portal and how the various components work together to provide workflow solutions to warehouse users. There is a lot more to discuss – and we will have another blog post that will dive into building customized workflows within this framework shortly. Stay tuned!

The post Warehouse Mobile Device Portal Architecture appeared first on Microsoft Dynamics 365 Blog.

]]>
Serial Number Tracking for Service and Warranty in Microsoft Dynamics AX R3 http://approjects.co.za/?big=en-us/dynamics-365/blog/no-audience/2014/07/02/serial-number-tracking-for-service-and-warranty-in-microsoft-dynamics-ax-r3/ Wed, 02 Jul 2014 06:52:00 +0000 https://blogs.msdn.microsoft.com/dynamicsaxscm/2014/07/02/serial-number-tracking-for-service-and-warranty-in-microsoft-dynamics-ax-r3/ Serial Number Tracking for Service and Warranty in Microsoft Dynamics AX R3 In Microsoft Dynamics AX 2012 R3 we added new serial number capabilities.

The post Serial Number Tracking for Service and Warranty in Microsoft Dynamics AX R3 appeared first on Microsoft Dynamics 365 Blog.

]]>

Serial Number Tracking for Service and Warranty in Microsoft Dynamics AX R3

In Microsoft Dynamics AX 2012 R3 we added new serial number capabilities. The intention was to help companies who are struggling to manage serialized products in inventory, when they really just want to capture serial numbers for service and warranty purposes when items are sold. For many companies this is the only reason to track serial numbers, but because serial numbers are stored as an inventory dimension, companies were forced to manage them at the individual product level in warehousing and inventory processes. This required an extra task of registering serial numbers, and added performance overhead to the system. The new capabilities added in Microsoft Dynamics AX 2012 R3 allow a serial number to be tracked, but defers the actual registration until the product is sold.

Setup

Configuring a product to use this new feature is a straightforward process. The serial number tracking feature is configured for the tracking dimension group setup. You can create a tracking dimension group by clicking Inventory management -> Product information management -> Tracking dimension groups. You can create a new tracking dimension group and select the “Active in sales process” check box for Serial number. The following image shows an example of this configuration.

 

Note that when this is option selected, the Capture serial option defaults to None and cannot be modified. This might seem a little confusing, but it is the correct behavior. The Capture serial box is only applicable for advanced warehousing scenarios. We also set the Serial number control as checked, because this is required for the new serial number functionality.

Because this functionality is enabled by creating a new tracking dimension group, products that were already serial number tracked will continue to work as they did previously, assuming that the tracking dimension group remains the same. You can enable some products with the new serial number tracking feature and some with the existing functionality by simply using different tracking dimension groups.

Benefits to Inventory

After an item is configured to use the new serial number configuration, you can have on-hand quantities of products without having to specify individual serial numbers. In the On hand form below, you can see a large quantity of Item T0006 in warehouse 11. Item T0006 is a serial number controlled item, but I do not have to record each individual serial number located in Warehouse 11.

Sales Orders

Often we find that our customers only need to track serial numbers when a product is sold. A consumer may have warranty issues or just want to return the product; in both cases it is important to understand exactly what product they are trying to return.

The enhanced serial number functionality allows a serial number to be registered for products when they are picked or packed to fulfill a sales order, or when the sales order is invoiced. The item must be configured as described above. After a sales order is created, in the Packing slip form you can register serial numbers by clicking the Lines tab and clicking the Update line -> Register serial numbers.

The Serial numbers form is displayed, where you can register serial numbers, as shown in the following image.

This form is new for Microsoft Dynamics 2012 R3, and has been designed to work with a barcode scanner so that you can quickly assign serial numbers with outgoing products. Of course, if you do not have a scanner the form also allows you to manually enter the data. The form validates the number of serial numbers required, and you can create a “not readable” entry in cases where a serial number cannot be read.

After these steps have been completed and the sales order is sent to the customer, you can view the shipped serial numbers on the printed packing slip. You can also view the serial numbers by clicking Update line -> Register serial numbers from the forms for posting packing slips and invoices.

Item Tracing

It’s important to keep customers happy by supporting warranty and service scenarios. To this end, the new serial number feature allows you to use serial numbers during the return process.

For example, suppose a customer reports a defective item but does not have their invoice. They have only the serial number on the product. In this case, you can use the tracing functionality in Microsoft Dynamics AX to retrieve the order history for the product. The item tracing functionality works with the new serial number features described above.

Click Inventory management > Inquiries > Tracing > Item tracing. In the Item tracing form, enter the Item number and the Serial number.

Click Trace. The Trace result pane will show the sales orders that contain items with this serial number, as shown in the image below.

All of the functionality for tracing works for serial numbers, such as the ability to navigate to the specific details page – in this case the sales order page.

Product Returns

Returning a product from a customer is done in much the same way as before. When a return order is created and the new serial number configuration is enabled, you will need to register the serial numbers for the items that are being returned when you generate the packing slip.

In the Packing slip posting form, on the Lines tab, click Update line -> Register serial numbers.

The Serial numbers form is displayed, where you can scan or enter the barcode for the incoming item. These are validated against the serial numbers that were registered on the original invoice.

Conclusion

The Inventory team is constantly working to improve the experience for our customers. With the release of Microsoft Dynamics 2012 R3, we made an important step in improving serial number tracking and registration. We look forward to your feedback about this feature, and suggestions for how we can make Dynamics AX even better.

The post Serial Number Tracking for Service and Warranty in Microsoft Dynamics AX R3 appeared first on Microsoft Dynamics 365 Blog.

]]>