Thursday, June 20, 2019

D365FO - Start hierarchy approval with specific worker

There are times when clients want to start hierarchy approval from a specific worker and not from the one who initiated the workflow and then traverse up the hierarchy.


  • Invoices are coming from third-party into FinOps and creating tax invoice registers
  • Setting the Approved by field at tax invoice register line level
  • AP Clerk/Administrator assigns these invoices to correct worker for approval
So, in the above scenario, the AP clerk initiated the workflow but the workflow will not go his/her line manager for approval instead it will be assigned to the owner (approved by) of the invoice.

This is what we want to achieve - add a new Start from

This Start from list get populated through getSupportedDataType() in  class WorkflowHierarchyProviderHelper

Create a new event handler class and subscribe to the delegate as shown below.

P.S. WFOwner is the custom created EDT.

class ECL_WorkflowHierarchyProviderHelperEventHandler
    [SubscribesTo(classstr(WorkflowHierarchyProviderHelper), delegatestr(WorkflowHierarchyProviderHelper, addAdditonalSupportedDataTypesDelegate))]
    static void addAdditonalSupportedDataTypesDelegate(Set _supportedDataTypes)

Add a new field on LedgerJournalTable and assign the WFOwner EDT to it. LedgerJournalTable is for reference as the above change is implemented for vendor invoice approval.

Wednesday, June 19, 2019

D365FO - Add new participant and type of participant to Participant workflow element

There are times when you want to add a new type of participant other than security role participants and user group participants, this post describes the steps to take and achieve this requirement.

This is the final output

Let's find out how did it work.

This is how each type of participant exists in AOT so a new Workflow Participant Assignment Provider needs to be created in order to see it in the Type of participant list as for this example 'Vendor invoice approval provider' is being added.
Created a new Workflow Participant Assignment Provider with the following properties.

Available For All Workflow Templates = No [Just want to have this new Participant type vendor invoice approval workflow]

Added new workflow type and link it with VendInvoiceApprovalJournalTemplate which is the workflow type name for Vendor tax invoice approval journal workflow 

Each provider has a Provider class and here is an example of the class used for above created participant provider

class FF_VendInvoiceWFParticipantProviderExpend  extends WorkflowParticipantProvider_Expend
    const str owner = 'OWNER';

    public WorkflowParticipantExpenDocumentType documentType()
        return WorkflowParticipantExpenDocumentType::VendInvoice;

    public WorkflowParticipantTokenList getParticipantTokens()
        WorkflowParticipantTokenList tokenList = WorkflowParticipantTokenList::construct();

        tokenList = super();
        tokenList.add(owner, '@SYS77709');
        return tokenList;

    /// <summary>
    ///     Resolves the vendor invoice line dimensions to a list of users
    /// </summary>
    /// <param name="_context">
    ///     An instance of the <c>WorkflowContext</c> class
    /// </param>
    /// <param name="_participantTokenName">
    ///     The participant token that is selected for a role-based assignment.
    /// </param>
    /// <returns>
    ///     An instance of the <c>WorkflowUserList</c> class that contains the enabled users from the token
    /// </returns>
    /// <exception cref="M:Exception::Error">
    ///     Participant token does not exist
    /// </exception>
    public WorkflowUserList resolve(WorkflowContext _context, WorkflowParticipantToken _participantTokenName)
        LedgerJournalTable ledgerJournalTable = this.getLedgerJournalTableFromContext(_context);

        WorkflowUserList userList = WorkflowUserList::construct();
        if (_participantTokenName == owner)

        return userList;

    /// <summary>
    /// Gets the <c>LedgerJournalTable</c> record from the workflow context.
    /// </summary>
    /// <param name = "_context">The workflow context.</param>
    /// <returns>A <c>LedgerJournalTable</c> record.</returns>
    private LedgerJournalTable getLedgerJournalTableFromContext(WorkflowContext _context)
        LedgerJournalTable ledgerJournalTable;

        if (_context.parmTableId() == tableNum(LedgerJournalTable))
            ledgerJournalTable = LedgerJournalTable::findRecId(_context.parmRecId());
        else if (_context.parmTableId() == tableNum(LedgerJournalTable))
            ledgerJournalTable = LedgerJournalTrans::findRecId(_context.parmRecId(), false).ledgerJournalTable();

        return ledgerJournalTable;

    /// <summary>
    /// Validates that the <c>WorkFlowContext</c> has the expected tables.
    /// </summary>
    /// <param name = "_context">The workflow context.</param>
    /// <returns>true if the expected tables are found; otherwise, false.</returns>
    private boolean doesContextHaveExpectedTable(WorkflowContext _context)
        return _context.parmTableId() == tableNum(LedgerJournalTable) || _context.parmTableId() == tableNum(LedgerJournalTrans);

    public static FF_VendInvoiceWFParticipantProviderExpend construct()
        return new FF_VendInvoiceWFParticipantProviderExpend();


If your interested to know how it used to work in AX 2012, follow this link

Friday, July 27, 2018

D365FO - How not to select Fleet Management modules in package creation

Want assurance that you never select/include fleet management modules in package creation or build all module together. Just rename the Descriptor folder from all these three locations and refresh models in VS first time to reflect the changes.

<Service volume drive>:\AosService\PackagesLocalDirectory\FleetManagement
<Service volume drive>:\AosService\PackagesLocalDirectory\FleetManagementExtension
<Service volume drive>:\AosService\PackagesLocalDirectory\FleetManagementUnitTests

Friday, July 6, 2018

D365FO - Get list of obsolete data entities

Find which data entity is obsolete after every new update. Here are the steps.

For example; Customers V2 data entity is obsolete with version 8.0

For developers: Type the below in the metadata search in VSTS:
type:dataentityview property:isobsolete=yes

Saturday, January 6, 2018

D365 platform update 12 (7.3): Admin access changes

The Microsoft team did release platform update 12 for Dynamics 365 for Finance and Operations, Enterprise Edition 7.3. There have been few changes concerning accessibility (admin access on VMs).

Starting with platform update 12 users do not have admin access to D365 VMs hosted on the Microsoft subscription.

Which means:

1.    You can only log in with the "builtin\Userxxxxxxxxx" account and not the “builtin\axlocaladmin” account anymore.
Prior to PU12 7.3

With PU12 7.3

2.    IIS Express is used as the web server instead of IIS

3.    IIS Express runs when Visual Studio is running 

4.    Visual Studio cannot be run as Administrator anymore (you are not the local admin anymore on your development VM L ). Just double click Visual Studio shortcut or run it from start.

Admin access to development virtual machines can only be achieved with following options;

1.    Host a development VM on a separate Azure subscription

2.    Deploy VM with an older platform update than PU12 and then upgrade platform update (This option will not work for 7.3)


Monday, December 18, 2017

Newly created data entity is not visible in data management entity list?

If you created a new data entity and it's not visible in your data management entity list. 

Open Data Management workspace -> Framework parameters -> Entity Settings and hit the "Refresh Entity List" button