Creating a Custom Workflow Due Date Provider

Although not often needed within workflow, one sometimes has the requirement to set due dates, escalation dates etc based on some sort of custom criteria E.G Complete by My Birthday or Complete at least one day before the documents requested date. Recently on the Dynamics AX forum this question was raised (https://community.dynamics.com/ax/f/33/t/156937.aspx) so I thought I’d write up a “short” post on how to create a custom WorkflowDueDate provider.

1. Create a new class in the AOT that implements “WorkflowDueDateProvider” e.g. MyCustomDueDateProvider
public class MyCustomDueDateProvider implements WorkflowDueDateProvider
{
}

2. Create method getCalendarTokens

The getCalendarTokens method will return a list of items that will display in the Time Limit’s Calendar option in your workflow configuration.
D2
You can return any list of items here that you would like to allow the user to select for resolution. For example in the standard Calendar Due Date provider a list of all the configured calendars in the system. However you could customise this to return an entirely personal list of options such as “My Birthday” and “My Anniversary” that will set the workitem’s due date to my next birthday (26th of June 2015) or next anniversary (24 of March 2016). You could also provide an option that is document specific such as “1 Day Before Requested Date”. For this example I am going to use these options to illustrate the true arbitrary nature of the tokens.

public WorkflowCalendarTokenList getCalendarTokens()
{
    WorkflowCalendarTokenList tokens = WorkflowCalendarTokenList::construct();
    ;
    tokens.add(“MYBIRTHDAY”, “My Birthday”);
    tokens.add(“MYANNIVERSARY”, “My Anniversary”);
    tokens.add(“1DAYBEFOREREQ”, “1 Day Before Requested Date”);
    return tokens;
}

3. Create the resolve and resolveNonUser methods

After creating the tokens list we need to create a way to resolve the specific option that the user has selected in his configuration. I’ve kept my code very simple (and hardcoded) to illustrate how this works.

public WorkflowDateTime resolve(WorkflowContext _context, WorkflowCalendarToken calendarToken, WorkflowTimeSpanMinutes _timeSpanMinutes, WorkflowUser _userId)
{
    Date tmpDate;
    WorkflowDateTime ret;
    PurchReqTable req;
    ;
    if (!_calendarToken)
        throw error(“@SYS105450″);

    if (_calendarToken == “MYBIRTHDAY”)
    {
        tmpDate = str2DateDMY(“26062010″); //specific date
        ret = DateTimeUtil::newDateTime(tmpDate, 0);
        ret = MyCustomDueDateProvider::nextDate(ret);
    }
    else if (_calendarToken == “MYANNIVERSARY”)
    {
        tmpDate = str2DateDMY(“24032010″); //specific date
        ret = DateTimeUtil::newDateTime(tmpDate, 0);
        //next date is a custom method that simply finds the next occurance of my birthday by adding years to the provided date until it is greater than today.
        ret = MyCustomDueDateProvider::nextDate(ret);
    }
    else if (_calendarToken == “1DAYBEFOREREQ”)
    {
        if (_context.parmTableId() == tableNum(PurchReqTable))
        {
            //retrieve original document form WorkflowContext
            req = PurchReqTable::find(_context.parmRecId());
            ret = DateTimeUtil::newDateTime(req.RequiredDate,0);
            ret = DateTimeUtil::addDays(ret, -1);
        }
       else
        {
            throw error(“Cannot use 1DAYBEFOREREQ with any document except PurchReqTable”);
        }
    }

return ret;
}

For this example we are not going to use user specific resolution, so the resolveNonUser and resolve methods will return the same values

public WorkflowDateTime resolveNonUser(WorkflowContext _context,
WorkflowCalendarToken _calendarToken,
WorkflowTimeSpanMinutes _timeSpanMinutes)
{
return this.resolve(_context, _calendarToken, _timeSpanMinutes, ”);
}

4. Create new and construct methods

protected void new()
{
}

public static MyCustomDueDateProvider construct()
{
return new MyCustomDueDateProvider();
}

5. Create a due Date provider in the AOT.

1. Navigate to Workflow -> Providers -> Due Date Calculation
2. Right click, click “new Due Date Calculation Provider”
3. Right click on your new provider and click properties.
4. Provide an appropriate name e.g. “MyCustomDueDateProvider”
5. Provide a relevant label. This will appear in your workflow configuration under “Calendar Name”
D1
6. Depending on how you have coded your provider you may need to select an Association Type of company and AvailableForAllWorkflowTypes as “no” if you rely on company specific information or on record specific information.
7. Most importantly: Select the the class that you have created under “ProviderClass”

6. Perform CIL Compile and restart your client
7. Configure your workflow:
 Open your workflow configuration and navigate to the place where you would like to make use of your new functionality. E.G. Any Assignment’s “Time Limit” tabYou should now be able to select your provider under the “Calendar Name” option and select the resolution type under the “Calendar” option. Note our code didnt make use of the “_timespanInMinutes” parameter so the Duration option can be set to anything. We could have used this parameter to increase the flexibility on the “Before Requested Date” option if necessary.

I hope this assists someone sometime! Happy Daxing