SysFlushAOD: Refresh SysExtension cache in D365FO

SysFlushAOD: Refresh SysExtension cache in D365FO

The SysExtension framework is heavily used in warehouse mobile device development within Dynamics 365 for Supply Chain Management (SCM)  (see Process guide framework – Supply Chain Management | Dynamics 365 | Microsoft Learn). You may also find a short, self-contained example in my earlier blog:  X++ Decorator pattern in Dynamics 365.

There is one thing that annoys me every time: newly created classes fail to get invoked. The class factory does not recognize the new class because of the intensive caching of class IDs and attributes. A mobile warehouse solution may return “Process guide is not yet supported for this flow.“, for example. Rebuilding the solution does not clear the cache, and the class factory keeps an outdated list of derived classes, failing to instantiate them. The cache apparently survives even an IISRESET. 

Solution: Execute the following command in the browser, then reload:  https://xxxprod.operations.dynamics.com/?mi=SysClassRunner&cls=SysFlushAOD

This clears the SysExtension factory cache and rescans the list of inherited classes.

D365 Petty cash review

D365 Petty cash review

Today I take a chance to review a development of my younger self: the Petty cash add-on to the Bank and cash module. In central Europe, this “Petty cash” (de: Kasse, fr: caisse) often looks like the box shown above. Inside of it there is… well… some cash. I designed, programmed this add-on and even localized it for Ukraine back in 2002 mostly on my own in something that can be called a study. It has been there in the D365FO application core all these years, and in version 10.0.39 they finally released it worldwide. 

Configuration

To activate this add-on, enable Petty cash in the Feature management first. There is also a license key (what used to be called a configuration key) Country/Regional specific feature / Multiple countries/regions / General ledger – extensions for Eastern European countries / Petty cash, it is normally activated by default. Ultimately, you must activate it in Cash and bank management parameters with a slider Enable petty cash.

The setup is well described here: (1) Petty Cash Accounting – Microsoft Dynamics 365 Finance | LinkedIn. In essence, you have to create a symbolic cash account, in a Cash posting profile attach a general ledger account to it (there is usually a 1:1 relationship), then select both in Cash and bank management parameters:

D365 Petty Cash Setup

Then there is a balance check. In Eastern Europe the amount of cash you accumulate may not exceed a certain threshold. In Western Europe I know no such regulations but just common sense; some companies even used to stash money 5 years ago to escape the negative bank interest. In contrary, there is a EU-wide limit for cash transactions of 10 kEUR. This can be set as an Operations limit.

In addition, you must specify at least 2 number sequences for the cash slips (bons): reimbursement and disbursement. Finally, configure a GL Journal name of the Cash type. You are good to go.

Operation

Navigate to Cash and bank management > Petty cash > Slip journal, create a new journal header, and under Lines you may start registering cash operations.

Cash Slip Journal

For a sale, choose the cash account in debit and a revenue account in credit. Do not forget the VAT. Once you perform Documents approval / Approve of the line, it draws the next Cash reimbursement slipOrder number”. At this step, it is supposed to print this slip at once, but in Eastern Europe there are legal requirements to its form and content, while in Western Europe there are no such requirements and… no printout. 😊Actually we are talking about a “rudimentary invoice” (de: Kleinbetragsrechnung less than €400, fr: facture simplifiée < €150) with some goods/service description, an anonymous recipient and a VAT included. However, in this case a free text invoice is advised, or you may produce it outright at a retail POS, while field servicemen should use their CE mobile terminals.

Post the journal, and it is going to integrate the cash transactions into the GL.

To pay someone out in cash, the cash account is in credit and the expense account is in debit; again, do not forget the VAT. Use Documents approval / Approve first. Interestingly, the cash balance check (see Inquiries / Cash balance) is performed at the same time, and the balance is built of both posted and unposted slips. Again, it issues a new “Order” number for a Cash disbursement slip, and in an Eastern European country it is going to print it. Here it does not make much sense, since a handyman must issue his own slip / bon to testify that he/she has been paid in full, then we take this receipt and preserve it. One case when we need a printout of our own may be a cash advance to an employee.

Conclusion

Even though this add-on remains a monument to my abilities in software design 😉 I am coming to a conclusion that it is pretty useless in Western Europe. The same level of comfort may be achieved with a separate bank account or a simple GL account (see Balance control accounts). In 20 years D365 for Finance has moved upmarket, and with the minimum of 20 licenses it is hard to imagine a company whose main source of liquidity may be cash sales. The module may find some usage in construction industry to pay temporary workers, though.

Dissecting the Warehouse Management app layout

Dissecting the Warehouse Management app layout

The layout of the Dynamics 365 Warehouse Management app is managed by both the App code and the D365 SCM core to ensure a productive workflow. The app receives a state from the Dynamics 365 SCM core encapsulated in a “container,” comprising a list of controls to be presented on the current screen. These hints include the DisplayArea  assignment (the display area where controls that are awaiting input or confirmation are found, see Inspect details of active Warehouse Management mobile app sessions – Supply Chain Management | Dynamics 365 | Microsoft Learn) and the InstructionControl reference for item ID, quantity, location confirmations.

Typically, controls without default values are positioned in the Primary Input Area, awaiting user input through scanning or manual entry. In the above example, the next empty control is LP (license plate) i.e. the licence plate to pick the goods from. These controls which require a user input are presented one after another following the order of controls in the “container” or the explicit Display Priority, if provided by the programmer of the warehouse menu item UI. This is perceived by the user as a series of screens; internally, it remains the same screen.

To determine the DisplayArea, the D365 core employs heuristics. Controls with default values slide down to the Info and Secondary Input Area, except for confirmation fields like Confirm Location, which appear in the Primary Input Area despite seemingly having a default value. The initial value is still empty, but the InstructionControl let the warehouse app present a hint from a different field and display it in italic (here: BULK-010).

Upon assigning values to all controls, the screen is considered complete, triggering the button in the Primary Action Area.

Control placement on the Warehouse Management app screen can be influenced through the WHSMobileAppServiceDecoratorRule class family. For instance, a control with a non-empty default value can still be prompted in the primary input area, as demonstrated in the below code snippet:

				
					[SubscribesTo(classStr(WHSMobileAppServiceDecoratorRuleDefaultDisplayArea), staticDelegateStr(WHSMobileAppServiceDecoratorRuleDefaultDisplayArea, isTextInPrimaryInputAreaDelegate))]
public static void WHSMobileAppServiceDecorator_isTextInPrimaryInputAreaDelegate(boolean _enabled, Map _controlMap, str _data, WHSMenuItemName _menuItemName, EventHandlerResult _result)
{
   if (_enabled && _controlMap.lookup(#XMLControlName) == #MyControl)
   {
      _result.result(true);
   }
}
				
			
It is important to remove (to be exact, not to rebuild after the last user interaction) such a control from the screen once it receives its input, otherwise it will be prompted repeatedly in an infinite loop. The second example showcases a custom control with an InstructionControl reference for requesting confirmations while presenting a hint in italic:
				
					[ExtensionOf(classStr(WHSMobileAppServiceDecoratorRuleInstruction))]
final class WHSMobileAppServiceDecoratorRuleInstruction_Extension
{
    #WHSRF
    protected WHSMobileAppControlName getInstructionControlName(WHSMobileAppControlName _controlName)
    {
        WHSMobileAppControlName confirmationControl = _controlName;
        WHSMobileAppControlName masterControl;
        masterControl = next getInstructionControlName(confirmationControl);
        if (confirmationControl == #MyControl)
        {
            masterControl = #MyMasterControl;
        }
        return masterControl;
    }
}