Launch an Automation Script on Error

January 3, 2023

Introduction

While looking up documentation on how to properly obtain the display message for a Maximo exception we came across something quite interesting. In Maximo 7.6.1.2 a hook was added for triggering an automation script every time an error occurs. The intent seems to be to allow developers to add additional information to an exception, but it also opens the door for some interesting use cases for special error handling and reporting.

In this post we will cover how to trigger an automation script when an error occurs, how to add user specific details to the message and then explore other uses for this functionality.

Message Setup

Each message in Maximo can be identified by a unique message group and key combination or by a generated unique identifier. Launching an automation script on an error requires knowing the error message's group and key. When an error message is displayed the generated unique identifier is displayed as a prefix to the message as shown below.

Error Message Id

This unique identifier can be used to identify the message's group and key within the messages dialog, which is available in either the Database Configuration application or the Application Designer application. The dialog is available from the Select Actions menu on the List tab of the Database Configuration application as shown below.

Messages Menu Database Configuration

In the Application Designer application, the dialog is available from the Select Actions menu once an application has been selected as shown below.

Messages Menu Application Designer

From the Messages dialog, use the message identifier from before to locate the error's message group and message key. In the example below we have searched for BMXAA4495E and found the message group workorder and the message key ActualsAppr, which is the error message displayed when a user attempts to record actuals against an unapproved work order.

Message Dialog

Error Script

Once the message group and key have been identified, to create a script that will be called every time the error occurs create a script named MXERR.[MESSAGE_GROUP].[MESSAGE_KEY], where [MESSAGE_GROUP] is the message group and [MESSAGE_KEY] is the message key.

Using the message group and key from the previous example the script name is MXERR.WORKORDER.ACTUALSAPPR. That is all there is to it, the script will now be called every time the error occurs.

Implicit Variables

There are a number of implicit variables available in the script, these are listed in the table below.

VariableDescription
egroupA String object that is the message group name.
ekeyA String object that is the message key name.
eparamsA Object array that contains parameters used for formatting message replacement indexes.
emsgThe resolved error message with variables replaced with the provided parameters.
scriptNameThe name of the script being executed.
serviceAn instance of the the com.ibm.tivoli.maximo.script.ScriptService class.
mxerrormsgAn outbound variable that when assigned will display after the default message

User Specific Message

The mxerrormsg variable can be set within a script and the result will be added to the standard error message. For our example we will add a personalized message to the standard error when a user attempts to add actuals to an unapproved work order.

Create a script named MXERR.WORKORDER.ACTUALSAPPR and use the Javascript or Python code below, whichever you are more comfortable with.

Note that the current userInfo implicit variable is not available in this context so we must use the UIContext to obtain a reference.

Javascript

// import the UIContext class
UIContext = Java.type("psdi.common.context.UIContext");
MXServer = Java.type("psdi.server.MXServer");
SqlFormat = Java.type("psdi.mbo.SqlFormat");
main();
function main() {
// See if we can get a UI current context. This may not be possible for background processes.
if (UIContext.getCurrentContext()) {
// Get a reference to the current web client session
var clientSession = UIContext.getCurrentContext().getWebClientSession();
// If a web client session is available then get the current UserInfo
if (clientSession) {
var userInfo = clientSession.getUserInfo()
var userName = userInfo.getUserName();
// Add to line returns ( \n ) to separate the additional message.
mxerrormsg = "\n\nSorry " + ___getFirstName(userName)
+ ", actuals cannot be added to an unapproved work order.";
}
}
}
// use the three underscores to indicate the function is private.
function ___getFirstName(userName) {
var personSet;
try {
// Typically it is a bad idea to use the SystemUserInfo, but we are accessing
// the person record and the current user may not have access.
personSet = MXServer.getMXServer().getMboSet("PERSON", MXServer.getMXServer().getSystemUserInfo());
var sqlf = new SqlFormat("personid = (select personid from maxuser where userid = :1)");
sqlf.setObject(1, "MAXUSER", "USERID", userName);
personSet.setWhere(sqlf.format());
if (!personSet.isEmpty()) {
return personSet.moveFirst().getString("FIRSTNAME");
} else {
return userName;
}
} finally {
try {
// Always close your sets.
if (personSet) {
personSet.close();
personSet.cleanup();
}
} catch (ignored) {
}
}
}
var scriptConfig = {
"autoscript": "MXERR.WORKORDER.ACTUALSAPPR",
"description": "Custom error handling for work order actuals",
"version": "1.0.0",
"active": true,
"logLevel": "ERROR"
};

Python

# import the UIContext class
from psdi.common.context import UIContext
from psdi.server import MXServer
from psdi.mbo import SqlFormat
def getFirstName(userName):
try:
# Typically it is a bad idea to use the SystemUserInfo, but we are accessing
# the person record and the current user may not have access.
personSet = MXServer.getMXServer().getMboSet("PERSON",MXServer.getMXServer().getSystemUserInfo())
sqlf = SqlFormat("personid = (select personid from maxuser where userid = :1)")
sqlf.setObject(1, "MAXUSER","USERID", userName)
personSet.setWhere(sqlf.format())
if not personSet.isEmpty():
return personSet.moveFirst().getString("FIRSTNAME")
else:
return userName
finally:
# Always close your sets.
if personSet is not None:
personSet.close()
personSet.cleanup()
def main():
# See if we can get a UI current context. This may not be possible for background processes.
if UIContext.getCurrentContext() != None:
# Get a reference to the current web client session
clientSession = UIContext.getCurrentContext().getWebClientSession()
# If a web client session is available then get the current UserInfo
if clientSession != None:
userInfo = clientSession.getUserInfo()
userName = userInfo.getUserName()
# Add to line returns ( \n ) to separate the additional message.
# Declare the outbound variable as global so it will be set.
global mxerrormsg
return "\n\nSorry " + getFirstName(userName) + " actuals cannot be added to an unapproved work order."
# Call the main function
main()
scriptConfig="""{
"autoscript": "MXERR.WORKORDER.ACTUALSAPPR",
"description": "Custom error handling for work order actuals",
"version": "1.0.0",
"active": true,
"logLevel": "ERROR"
}"""

Return to the Work Order Tracking application and select an unapproved work order (WAPPR status). Navigate to the Actuals tab and click the new row button as shown below.

New Actuals Row

An error dialog is now displayed with the additional error message provided by the script.

Custom Error Message Row

Notify Administrator on Error

So far we have looked at using this feature in the way it was intended, but the ability to launch an automation script when an error occurs has many other uses.

There are many scenarios where an administrator may want to be notified when an error occurs such as database connection losses, login failures and a host of other such errors. An administrator may want to collect statistics about how often particular errors are occurring or which users are experiencing a particular error. By being able to run a script when an error occurs, all of these scenarios can be handled.

For a simple demonstration, the following script modifies the previous example and instead of displaying a message to the user, emails the Maximo administrator with the user information so they can follow up, perhaps with additional training.

Javascript

// import the UIContext class
UIContext = Java.type("psdi.common.context.UIContext");
MXServer = Java.type("psdi.server.MXServer");
main();
function main() {
// See if we can get a UI current context. This may not be possible for background processes.
if (UIContext.getCurrentContext()) {
// Get a reference to the current web client session
var clientSession = UIContext.getCurrentContext().getWebClientSession();
// If a web client session is available then get the current UserInfo
if (clientSession) {
var userInfo = clientSession.getUserInfo()
var userName = userInfo.getUserName();
var adminEmail = MXServer.getMXServer().getProperty("mxe.adminEmail");
if (adminEmail) {
MXServer.getMXServer().sendEmail(adminEmail, "[email protected]",
"Unapproved work order actuals error",
userName + " tried to add actuals to an unapproved work order.");
}
}
}
}
var scriptConfig = {
"autoscript": "MXERR.WORKORDER.ACTUALSAPPR",
"description": "Custom error handling for work order actuals",
"version": "",
"active": true,
"logLevel": "ERROR"
};

Python

# import the UIContext class
from psdi.common.context import UIContext
from psdi.server import MXServer
def main():
# See if we can get a UI current context. This may not be possible for background processes.
if UIContext.getCurrentContext() != None:
# Get a reference to the current web client session
clientSession = UIContext.getCurrentContext().getWebClientSession()
# If a web client session is available then get the current UserInfo
if clientSession != None:
userInfo = clientSession.getUserInfo()
userName = userInfo.getUserName()
adminEmail = MXServer.getMXServer().getProperty("mxe.adminEmail")
if adminEmail is not None:
MXServer.getMXServer().sendEmail(adminEmail, "[email protected]", "Unapproved work order actuals error", userName + " tried to add actuals to an unapproved work order.")
# Call the main function
main()
scriptConfig="""{
"autoscript": "MXERR.WORKORDER.ACTUALSAPPR",
"description": "Custom error handling for work order actuals",
"version": "1.0.0",
"active": true,
"logLevel": "ERROR"
}"""

Conclusion

In this post we explored how to launch an automation script when an error occurs. We reviewed how this can be used to add custom details to an error message. Then we expanded on how this can be leveraged for administrative reporting and notification. While the intent of this feature seems to be for adding message details, the ability to launch an automation script on system errors opens many possibilities for smarter error management and reporting.

If you have any questions or comments please reach out to us at [email protected]

In the time it took you to read this blog post...

You could have deployed Opqo, our game-changing mobile solution for Maximo.

Opqo is simple to acquire, simple to deploy and simple to use, with clear transparent monthly pricing that is flexible to your usage.