Showing posts with label Warehouse app. Show all posts
Showing posts with label Warehouse app. Show all posts

D365 SCM warehouse mobile device development approach. Macros or constants.

As you might know there are a lot of controls and related macro commands in the WHS classes. It is not really convenient to search for macro commands in code, since they are not supported by the cross-reference feature.

In D365 Finance and Operations, there is an option that can help simplify the development of warehouse mobile flows and tracking using the existing commands. It is constants.

In my opinion, the best example of the mentioned option is the "ProcessGuideDataTypeNames" class. Inside the class you can find a lot of constants that are used in the mobile device flows. 

As you can see, macros are used at the class declaration level, but with a specific reference to a value in the WHSRF macro. As a result, you can use cross-references to find all the places in the code where the constants are used.

In general, constants have the following advantages over macros:
  • You can add a documentation comment to a constant but not to the value of a macro. Eventually, the language service will pick up this comment and provide a useful information to the user.
  • A constant is known by IntelliSense.
  • A constant is cross-referenced. Therefore, you can find all references for a specific constant but not for a macro.
  • A constant is subject to access modifiers. You can use the private, protected, and public modifiers. The accessibility of macros isn't rigorously defined.
  • Constant variables have scope, whereas macros don't have scope.
  • You can see the value of a constant or a read-only variable in the debugger.
  • Full control of the type for the constant.
  • You can also define constants as variables only. The compiler will maintain the invariant so that the value can't be modified.
  • A significant effect on the performance of the compiler.
Considering all the above, I would recommend you to use constants instead of macros in general, not only in WHS mobile device flow development.

Dynamics 365 Supply Chain Management WHS extending. Adding a new work type for "User directed" mobile device flows.

Introduction

I would like to share my experience with adding a completely new work type. In my case, I have added a new work type for "User directed" mobile device flows. My post is not a complete guide on how to do it. It is more about the main idea and some thoughts. 

Note: There is a post on how to work with the “Custom” work type. It is different.

Overview

WHSWorkType enum extending

First, it is necessary to extend the standard "WHSWorkType" enum in order to add a new work type.

Adding new mobile device step

Then, since it is a new work type it makes sense to add a new step so that the system can process the new work type. The new step should not have one of the existing numbers in the standard macro “WHSWorkExecuteDisplayCases”. 
We can create a new macro or use an existing one for this purpose and add a new step:

#define.NewWorkStep(10000)

Adding a new class handler for the new work 

After that, we need to create a new class handler for the new work type:

/// <summary>
/// The <c>WhsNewWorkTypeHandler</c> class handles new work type.
/// </summary>
[WhsWorkTypeFactory(WhsWorkType::NEWWorkType)]
class WHSNewWorkTypeHandler extends WhsWorkTypeHandler
{}

In this class, we need to implement the methods:

  • findWorkCreateLocationQty – sets the parameters of the processing.
  • determineStep – defines the first step of the flow for the work type. Also, you can add a mobile device screen to be shown for users.
  • executeWorkLine – defines the actions with the work line.

Note: In the system, there are “WhsWorkTypePrintHandler” and “WhsWorkTypeCustomHandler” classes that can be used for a better understanding of the work type handler classes.

Below is a mockup of the possible solution:

public WhsWorkCreateLocationQtyResult

    findWorkCreateLocationQty(WhsWorkCreateLocationQtyParameters _parameters)
{
   WhsWorkCreateLocationQtyResult result; 
   
   result = WhsWorkCreateLocationQtyResult::construct();

   result.locationId       = '';
   result.pickUnitId       = _parameters.unitId;
   result.pickQty          = _parameters.qtyWork;
   result.inventPickQty    = _parameters.inventQtyWork;

   return result;
}

public void determineStep(WhsWorkStepContext _context)

{
    WhsWorkExecuteDisplay   workExecuteDisplay = _context.workExecuteDisplay;
      
    //we can to go to the custom dialog if we would like to
    _context.nextForm   = workExecuteDisplay.DrawNewScreen();
    _context.step       = #NewWorkStep;
}

public WHSWorkLine executeWorkLine(WhsWorkExecute     _workExecute, 

                                   WHSWorkLine        _workLine, 
                                   WHSUserId          _userId)
{
    return _workExecute.processNewWorkType(_workLine.WorkId, 
                                           _workLine.LineNum, 
                                           _userId);
}

When we implement the handler class and the new step in the mobile device flow for the new work type we need to be able to process the new step correctly.


WhsWorkExecuteDisplay class extending

If we take a look at the "processWorkLine" method of the "WHSWorkExecuteDisplay" class we will see that there is a default section for new mobile device steps.

default:

   boolean finishedProcessing = this.processWorkLineForCustomStep(state);
   
   if (finishedProcessing)
   {
       return [state.nextForm, step, state.recall, pass.pack()];
   }
   break;

So, the next step is to create an extension of the WhsWorkExecuteDisplay class and implement the "processWorkLineForCustomStep" method. The "processWorkLineForCustomStep" method has the "Replaceable" attribute so in your extension you can write any business logic

Note: I would recommend using the “next” command in the “processWorkLineForCustomStep”, for instance:

protected boolean 

        processWorkLineForCustomStep(WhsWorkProcessWorkLineState _state)
{
    boolean    ret;
    ……………………………………
    switch (step)
    {
               case #NewWorkStep:
           //do something
           ret = true; //in case the step has been processed correctly
           break;

       default :
           ret = next processWorkLineForCustomStep(_state);
    }
   
    return ret;
}

In this case, if there is more than one extension of this method (for example, from multiple vendors) all of them will be called by the system. 

If you don’t call the “next” command, only your method extension will be called. All other method extensions can be ignored by the system.

If the new step has been processed correctly it is required to return the "True" value. In this case, the system returns the values from your method in the mobile device flow and the standard code after the "processWorkLineForCustomStep" is not executed.

When you jump into your new step you can develop your own mobile device screens and switch between them depending on the buttons and controls in use. When you are done with the new work type you need to "go back" to the standard mobile device steps.


Conclusion

For sure some code adjustments and extensions can be desirable in other objects too. It depends on the business logic that is planned to be implemented with a new work type. In my opinion, the text above can be used as a high-level guide.


D365 Finance and Operations disable the flight feature in a Tier-1 environment.

When we recently were updating one of our Tier-1 environments to 10.0.31 version we faced an issue with WHS mobile app.

The mobile app reverted to the login screen after trying to go to a specific menu. We tried the following options in order to resolve the issue:

  • Delete all user sessions from Warehouse management > Inquiries and reports > Mobile device logs > Work user sessions.
  • Delete and recreate the mobile app user configured/used for your tests (Warehouse management > Setup > Worker)

After an investigation we realized that the issue was rooting in Issue 704649 - Warehouse mobile app gives error "The size of the XML request exceeds the maximum valued allowed". This code changes controls with the flight WHSMobileAppXMLSizeValidationFlight.

So we decided to disable this flight by using the SYSFLIGHTING table. The procedure is nicely described in an old post I found here, I will adjust the procedure to our case.

For this purpose it is needed to add a record with the field Enabled = 1 for the kill switch for the flight, meaning for WHSMobileAppXMLSizeValidationFlight_KillSwitch.

Below specific steps to follow to enable the kill switch for the flight:

1. Add a record with this Insert statement for SYSFLIGHTING table, but please replace the appropriate values:

INSERT INTO SYSFLIGHTING VALUES ('FlightName', 1, 12719367, Partition, RecID, 1)

Note: After replacing 'FlightName' with the actual flight name, the values are/should be:

- 1 stands for Enabled

- 12719367 is the Flight service ID

- Partition = partition ID from your environment which can be obtained by querying (select) for any record. Every record will have a partition id which must be copied and used here.

- RecID = same ID as partition(*) (If there is no other record in SYSFLIGHTING table, then it can be one. Or you can can find one by executing "SELECT max(recid)+1 from SysFlighting")

- 1 is for the RecVersion

- actually, the SQL query could also be much simpler, like this

INSERT INTO SYSFLIGHTING ([FLIGHTNAME],[ENABLED],[FLIGHTSERVICEID]) VALUES ('WHSMobileAppXMLSizeValidationFlight_KillSwitch', 1, 12719367)

2 Verify that C:\AOSService\webroot\web.config has the correct DataAccess.FlightingServiceCatalogID. You should find a line with this key and a value of 12719367. If not, update accordingly the file and save it.

Notes:

Having web.config file in the environment is a clear indication that key DataAccess.FlightingServiceCatalogID should have value 12719367 and this value should be used also in the SQL statement from above for the FLIGHTSERVICEID field value.

If web.config file is not present in the environment, but AXService.config file is present (see next note), it is a clear indication that environment is like an On-Premise deployment (which might be the case also for dev boxes or environments that are not Microsoft managed, but still on Microsoft cloud). In this scenario, see the next note with important differences.

Notes: (not having web.config file in the environment):

Verify that C:\ProgramData\SF\AOS_182\Fabric\work\Applications\AXSFType_App641\AXSF.Code.1.0.20200715180202\AXService.config has the correct DataAccess.FlightingServiceCatalogID. You should find a line with this key and a value of 0. If not, update accordingly the file and save it.

The AXService.config file path might be different (accordingly to your installation).

Having AXService.config file in the environment is a clear indication that key DataAccess.FlightingServiceCatalogID should have value 0 and this value should be used also in the SQL statement from above for the FLIGHTSERVICEID field value.

So, the SQL query should be like this:

INSERT INTO SYSFLIGHTING ([FLIGHTNAME],[ENABLED],[FLIGHTSERVICEID]) VALUES ('WHSMobileAppXMLSizeValidationFlight_KillSwitch', 1, 0)

3. Restart IIS and batch service

P.S. The issue was reported to Microsoft and it can be solved in 10.0.33 version.



Dynamics 365 SCM Warehouse app pop-up windows

Dynamics 365 SCM Warehouse app pop-up windows

We faced an issue with pop-up windows in our current WHS App version. (2.0.11.0)

The issue is: Even if the default field values for the mobile device flow are specified users should confirm default values. 

In our case, we used a warehouse transfer flow with the various default values setups. For instance, one of the setup options is presented on the screenshots below:




However, a pop-up window appears and the user should select the value from the lookup:


But all field values are defined by default based on the default values of the menu item:


From a user perspective, it’s not really convenient to confirm default values after every step since users can make errors because of additional unnecessary confirmation steps. Additionally, it may be quite annoying to have an extra pop-up window where it should not appear. 

It seems there are two options to solve this issue:

1. Upgrading whs app to 2.0.19.0 version. We tested it, there is no such behavior. On the other hand, there is a guarantee that the app will not broke again.
2. It seems possible to change the whs mobile device app behavior via code. This option can be useful if there are some modifications that should be aligned.

Let’s discuss the second option if it is applicable for you.

If we take a look at the user session XML we will see that the Inventory status and To warehouse controls have the DisplayArea tag value - PrimaryInputArea :

<Control InputType="5760" Footer2="" Footer1="" InstructionControl="" AttachedTo="" DataSequence="5" DisplaySubPriority="81" DisplayPriority="90" PreferredInputType="Selection" PreferredInputMode="Manual" DisplayArea="PrimaryInputArea" NumDecimals="-1" Status="1" color="#0076E5" selected="Available" enabled="1" defaultButton="0" error="0" length="-1" type="Undefined" data="||Available||Blocking||Not avail||Rejected" newLine="1" label="Inventory status" name="InventStatusId" controlType="combobox"/>

<Control InputType="9259" Footer2="" Footer1="" InstructionControl="" AttachedTo="" DataSequence="6" DisplaySubPriority="0" DisplayPriority="0" PreferredInputType="Alpha" PreferredInputMode="Scanning" DisplayArea="PrimaryInputArea" NumDecimals="-1" Status="1" color="#0076E5" selected="25" enabled="1" defaultButton="0" error="0" length="-1" type="Undefined" data="15||25" newLine="1" label="To warehouse" name="ToWarehouse" controlType="combobox"/>

The rule seems to be: If the combo box control is in the primary area, a pop-up window will appear.

In order to change the DisplayArea tag we need to create an extension for the WHSMobileAppServiceDecoratorRuleDefaultDisplayArea class. It has some methods and delegates in order to define the control area, for instance:

• isComboboxInPrimaryInputArea and isComboboxInPrimaryInputAreaDelegate for Combobox controls (e.g. units, inventory status and others including developed combobox controls)

• isTextInPrimaryInputArea and isTextInPrimaryInputAreaDelegateisTextInPrimaryInputAreaDelegate for Text controls (e.g. batch number, sales order id and others developed added text controls)

In our case, we need to hide the pop-up windows for the Inventory status and To warehouse controls. In order to do it, the code as below can be written via extension:

protected boolean isComboboxInPrimaryInputArea(boolean             _enabled,

                                               Map                 _controlMap,
                                               str                 _data,
                                               WHSMenuItemName     _menuItemName)
{
    boolean ret;

    ret = next isComboboxInPrimaryInputArea(_enabled, _controlMap, _data, _menuItemName);

    if (_enabled
    &&  _controlMap.lookup(#XMLControlName) == #InventoryStatus)
    {
        return false;
    }

    if (_enabled
    &&  _controlMap.lookup(#XMLControlName) == #ToWarehouse)
    {
        return false;
    }

    return ret;
}

or via delegate:

[SubscribesTo(classStr(WHSMobileAppServiceDecoratorRuleDefaultDisplayArea),
staticDelegateStr(WHSMobileAppServiceDecoratorRuleDefaultDisplayArea,
isComboboxInPrimaryInputAreaDelegate))]
public static void WHSMobileAppServiceDecorator_isComboboxInPrimaryInputAreaDelegate(
                               boolean              _enabled,
                               Map                  _controlMap,
                               str                  _data,
                               WHSMenuItemName      _menuItemName,
                               EventHandlerResult   _result)
{    
    if (_enabled
    &&  _controlMap.lookup(#XMLControlName) == #InventoryStatus)
    {
        _result.result(false);
    }

    if (_enabled
    &&  _controlMap.lookup(#XMLControlName) == #ToWarehouse)
    {
        _result.result(false);
    }
}

NOTE: The code above is an example. The mobile device flow types, and other important conditions are not considered. Please, do not use this code in real implementation projects as it is. It must be adjusted for the real scenario.

After these changes we should not see pop-up window for the Inventory status and To warehouse controls anymore and the user session XML will change as follows:

<Control InputType="5760" Footer2="" Footer1="" InstructionControl="" AttachedTo="" DataSequence="5" DisplaySubPriority="81" DisplayPriority="90" PreferredInputType="Selection" PreferredInputMode="Scanning" DisplayArea="InfoAndSecondaryInputArea" NumDecimals="-1" Status="1" color="#0076E5" selected="Available" enabled="1" defaultButton="0" error="0" length="-1" type="Undefined" data="||Available||Blocking||Not avail||Rejected" newLine="1" label="Inventory status" name="InventStatusId" controlType="combobox"/>

<Control InputType="9259" Footer2="" Footer1="" InstructionControl="" AttachedTo="" DataSequence="6" DisplaySubPriority="0" DisplayPriority="0" PreferredInputType="Alpha" PreferredInputMode="Scanning" DisplayArea="InfoAndSecondaryInputArea" NumDecimals="-1" Status="1" color="#0076E5" selected="25" enabled="1" defaultButton="0" error="0" length="-1" type="Undefined" data="15||25" newLine="1" label="To warehouse" name="ToWarehouse" controlType="combobox"/>

I am glad if this finding can help someone to save their time.

D365 SCM. Extension of promoted fields feature in the Warehouse Management mobile app

Extension of promoted fields feature in the Warehouse Management mobile app

Microsoft has recently introduced a promoted fields feature. It allows to promote and to highlight a specific information of each and any step in the task flows of the Warehouse Management mobile app. The setups are described here and a walkthrough demonstration is hereLet’s take a look at this feature from a technical perspective.

Overview

The key object is the WHSMobileAppFlow class. It is an abstract class that has a number of methods. We will take a look at the most important ones:

initValues              - it is an abstract method. It must be overridden when a new WHSMobileAppFlow derived class is created.

getAvailableFieldsit is used for default data created when the Create default setup button is hit on the Mobile device steps form.

addAvailableField - it is used for defining fields that should be available for promotion.

All other methods of  WHSMobileAppFlow class are either called up by the above-mentioned methods or they are internal and cannot be used in the code.

Promoted fields feature for new mobile device flows

For every mobile device flow, there is a derived class from the WHSMobileAppFlow object.
For example for the “UserDirected” flow:

[WHSWorkExecuteMode(WHSWorkExecuteMode::UserDirected)]
final class WHSMobileAppFlowUserDirected extends WHSMobileAppFlow
{
    protected void initValues()
    {
        this.addStep(WHSMobileAppStepIds::WorkId);
        this.addStep(WHSMobileAppStepIds::WHSWorkLicensePlateId);
        this.addWorkExecutionSteps();
 
        this.addWorkExecutionFields();
    }
}

So if we need to add the promoted fields feature for the custom developed WHS mobile app flow, we do the same – a new derived class from the WHSMobileAppFlow object.

[WHSWorkExecuteMode(WHSWorkExecuteMode::NewWorkExecuteMode)]
final class WHSMobileAppFlowNewWorkExecuteFlow extends WHSMobileAppFlow
{
    protected void initValues()
    {
        //adding necessary fields
        this.addAvailableField(extendedTypeNum(ItemId));
        this.addAvailableField(extendedTypeNum(Qty));
    }
}

After compilation and recreating the setups via the Create default setup button on the Mobile device steps form, the added fields should be available for the promoted fields feature:


Note: Please keep in mind, the addStep method cannot be used with WHSMobileAppStepIds::EnumValue since the WHSMobileAppStepIds class is marked as internal (10.0.24). Probably it can be changed in the future versions.

Promoted fields feature for new mobile device fields

Let's imagine there is a new field that we would like to use with this feature. For example, a new inventory dimension was added as described here.
In this case, we needed to add a new extension for the WHSMobileAppFlowUserDirected class, for instance:

[ExtensionOf(classStr(WHSMobileAppFlowUserDirected))]

final class WHSMobileAppFlowUserDirected_Extension
{
    protected void initValues()
    {
        next initValues();

        this.addAvailableField(extendedTypeNum(InventDimension1));

    }
}

After compilation and recreating the setups via the Create default setup button on the Mobile device steps form the added field should be available for the promoted fields feature:

Important:  For the mentioned extended data types (ItemId, InventDimension1) derived classes from the WHSField class should be developed as described here. Otherwise, it can be not really possible to add new fields.



D365 SCM Warehouse mobile app error: Unexpected difference between request and session data. Warehouse Mobile Devices XML protocol violated.

D365 SCM Warehouse mobile app error: Unexpected difference between request and session data. Warehouse Mobile Devices XML protocol violated.

Recently I was asked to investigate an issue with the WHS mobile application.
My colleagues reported that the application showed the error "Unexpected difference between request and session data. Warehouse Mobile Devices XML protocol violated" when they clicked "OK", "Cancel" or another button, the application screen looked like this :

After investigation, the problem was found. It was because of using buildControl method with the following parameters:

buildControl(#RFText, 'Number', "@Label", 1, data, extendedTypeNum(Dymmy), ' ', 0, false));

After changing the code as below the WHS mobile application works without errors:

buildControl(#RFText, 'Text', "@Label", 1, data, extendedTypeNum(Dymmy), ' ', 0, false));

The interesting thing is that the modification was working without errors when the developer tested modification via mobile emulator web reference. (like: https://YourEnvironment.dynamics.com/?mi=SysClassRunner&cls=WHSWorkExecuteForm)
So if developers do not perform feature tests with WHS mobile app, it may bring the issue as described above.

I would be glad if this information can help someone.


 

Microsoft announced the deprecation of Visual Studio 2022 for X++ development starting with Platform Update 74 (10.0.49)

Microsoft announced the deprecation of Visual Studio 2022 for X++ development. Starting with Platform Update 74 (10.0.49), Visual Studio 20...