January 3, 2023
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.
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.
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.
In the Application Designer application, the dialog is available from the Select Actions menu once an application has been selected as shown below.
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.
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.
There are a number of implicit variables available in the script, these are listed in the table below.
Variable | Description |
---|---|
egroup | A String object that is the message group name. |
ekey | A String object that is the message key name. |
eparams | A Object array that contains parameters used for formatting message replacement indexes. |
emsg | The resolved error message with variables replaced with the provided parameters. |
scriptName | The name of the script being executed. |
service | An instance of the the com.ibm.tivoli.maximo.script.ScriptService class. |
mxerrormsg | An outbound variable that when assigned will display after the default 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 theUIContext
to obtain a reference.
// import the UIContext classUIContext = 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 sessionvar clientSession = UIContext.getCurrentContext().getWebClientSession();// If a web client session is available then get the current UserInfoif (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"};
# import the UIContext classfrom psdi.common.context import UIContextfrom psdi.server import MXServerfrom psdi.mbo import SqlFormatdef 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 userNamefinally:# 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 sessionclientSession = UIContext.getCurrentContext().getWebClientSession()# If a web client session is available then get the current UserInfoif 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 mxerrormsgreturn "\n\nSorry " + getFirstName(userName) + " actuals cannot be added to an unapproved work order."# Call the main functionmain()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.
An error dialog is now displayed with the additional error message provided by the script.
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.
// import the UIContext classUIContext = 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 sessionvar clientSession = UIContext.getCurrentContext().getWebClientSession();// If a web client session is available then get the current UserInfoif (clientSession) {var userInfo = clientSession.getUserInfo()var userName = userInfo.getUserName();var adminEmail = MXServer.getMXServer().getProperty("mxe.adminEmail");if (adminEmail) {"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"};
# import the UIContext classfrom psdi.common.context import UIContextfrom psdi.server import MXServerdef 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 sessionclientSession = UIContext.getCurrentContext().getWebClientSession()# If a web client session is available then get the current UserInfoif 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 functionmain()scriptConfig="""{"autoscript": "MXERR.WORKORDER.ACTUALSAPPR","description": "Custom error handling for work order actuals","version": "1.0.0","active": true,"logLevel": "ERROR"}"""
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]