April 5, 2016

Restricting status changes in Maximo Anywhere

A common requirement in Maximo projects is to restrict work order status changes based on some internal business rules. This can be achieved on Maximo with the technique described in this article.
Unfortunately the rules set in the WOSTATUS domain on the server are not applied automatically to the Anywhere mobile applications so we need to customize the mobile apps to follow the same rules.

Lets first analyze how the status changes are managed in the Work Execution app.
The application.business.WorkOrderStatusHandler script implements a state machine where the matrix of allowed status changes are defined (state machine).


init: function(modelDataSet){
var settings = {};
settings.resourceName = "workOrder";
settings.stateToAlias = {};
settings.configuration = {
"WAPPR": ["WAPPR", "APPR", "INPRG",         "WMATL", "COMP",         "CAN"],
"APPR" : ["WAPPR", "APPR", "INPRG",         "WMATL", "COMP",         "CAN"],
"INPRG": ["WAPPR",         "INPRG",         "WMATL", "COMP"               ],
"WSCH":  ["WAPPR", "APPR", "INPRG", "WSCH", "WMATL", "COMP"               ],
"WMATL": ["WAPPR",         "INPRG",         "WMATL", "COMP",         "CAN"],
"COMP":  [                                           "COMP"               ],
"CLOSE": [                                                   "CLOSE"      ],
"CAN":   [                                                           "CAN"]
};

Unfortunately this script is referenced in many other scripts so the simplest may of overriding it is modifying it. This is not a best practice since this file may be overridden in an Anywhere fixpack but is a quick and dirty solution.
Another limitation of this solution is that it works only based on the domain internal values (SYNONYMDOMAIN.MAXVALUE).

Now imagine the following scenario. I have two aliases of the INPRG status: INPRG1 and INPRG2. I want to avoid a direct transition to INPRG2. Only INPRG1 to INPRG2 must be possible.

Another place where status changes are handled is the filtering rule in the WorkExecution.statusLookup lookup.

<lookup id="WorkExecution.statusLookup" label="Work Order Status" resource="domainwostatus"
  filterClass="application.handlers.StatusChangeHandler"
  filterMethod="filterWOStatus">

If you look at the application.handlers.StatusChangeHandler.filterWOStatus(evenHandler) method you will notice it handles some logic and filters the visible status in the lookup. We can now override this method to implement our logic.

First of all create a new script custom.handlers.MyStatusChangeHandler.

define("custom/handlers/MyStatusChangeHandler", 
[ "dojo/_base/declare",
  "platform/handlers/_ApplicationHandlerBase",
  "application/handlers/StatusChangeHandler",
  "application/business/WorkOrderStatusHandler" ],
function(declare, ApplicationHandlerBase, StatusChangeHandler, WorkOrderStatusHandler) {
return declare( [ApplicationHandlerBase, StatusChangeHandler], {

  // dummy method required only to ensure script loading
  dummyMethod: function(eventContext) {
  },
  
  // Filter WO statuses to those available for selection
  filterWOStatus: function(eventContext) {
    // call the original filterWOStatus method
    this.inherited(arguments);

    // retrieve current status
    var currWO = eventContext.application.getResource("workOrder").getCurrentRecord();
    var currStatus = currWO.get("status");

    // retrieve wodomain resource
    var woStatusDomain = this.application.getResource('domainwostatus');

    // sets the additional filter if necessary
    if(woStatusDomain.isFiltered() && currStatus!="INPRG1"){
      woStatusDomain.filter("value!=$1", "INPRG2");
    }
  },

});
});


There are two important things to note here.
  1. How the original StatusChangeHandler script is extended using the (see Dojo declare tutorial for details)
  2. How the additional filter value!='INPRG2" is applied to the existing filter already set in the woStatusDomain resource.
  3. The filter is specified using JavaScript syntax not SQL (JavaScript conditions syntax).
Now you need to modify the app.xml to include your customized transition rule.
Modify the WorkExecution.statusLookup filterClass from application.handlers.StatusChangeHandler to custom.handlers.MyStatusChangeHandler.

It seems also this is not enough because the custom script is not loaded by just referencing it in the filterClass.To circumvent this problem you can add a dummy eventhandler like this.

<eventHandler event="render" 
class="custom.handlers.MyStatusChangeHandler" method="dummyMethod" />


No comments:

Post a Comment