Preventing fields from Editing Once Record is in Workflow

Preventing fields from Editing Once Record is in Workflow

I like this problem because it involves a few components to make it work.

The business problem that is being solved here is if the user would like a field or fields to not be editable once the work order, in this case, enters workflow.  This example focuses on the WORKTYPE field, but this script could easily be expanded to include other fields.

The components you will need for a successful script are:

  • A list of fields that will be made read only once record is in workflow.
  • A list of viable statuses for the workflow to know when the records should be evaluated.
  • A SQL query to determine if record is on workflow.
  • Setting fields to be read only if evaluation is true.

Creating a list of fields to be made read only

You can create a list of fields to be read only by using an array.  Here I only have one field but using an array gives you the flexibility to quickly add additional fields.

#List of fields that will be read only
readOnlyFields = ['WORKTYPE']
#Example with additional fields
readOnlyFields = ['WORKTYPE', 'DESCRIPTION']

Obtain list of viable workflow statuses

In this scenario we care about records that are actively in workflow.  So we get a list of statuses using the workflow status domain.

# Get a list of valid workflow assignment statuses
statusList = mbo.getTranslator().toExternalList("WFASGNSTATUS", "ACTIVE")

Query to determine if record Is actively in workflow

Construct a query to determine if the record is in workflow.

# Construct a where clause to find the existing workflow assignment 
# for this work order. Ensure that one exists before proceeding. 
whereClause = SqlFormat(mbo.getUserInfo(), "ownertable = :1 and ownerid = " + woId + " and assignstatus in (" + statusList + ")")
whereClause.setObject(1, "WFASSIGNMENT", "OWNERTABLE", "WORKORDER")

Setting field(s) flag to read only

If it is determined that the record is in workflow then we set the fields listed in the array, readOnlyFields to read only.

if not wfAssignmentSet.isEmpty():
    logger.error("WF Assignments assignments for this work order")
    # Make fields read only if the work order is in workflow
 	# There will be more read only fields.  Fields can also be made
    # required using the same principle.
 	mbo.setFieldFlag(readOnlyFields, MboConstants.READONLY, True)

Steps to create automation script

Create a new automation script with Object Launch Point. We called it WOPREVEDIT in this example.

Create a launch point with Initialize Value selected.

Here is the full automation script.

#Make fields read only if record is in workflow
#Launch Point Type: OBJECT
#Launch Point Object: WORKORDER
#Language: Python
#Author: A3J Group
from psdi.mbo import SqlFormat
from psdi.server import MXServer
from psdi.util.logging import MXLoggerFactory
from psdi.mbo import MboConstants
logger = MXLoggerFactory.getLogger("maximo.script.woinit")
# Get the associated work order
wo = mbo.getString("WONUM")
woId = mbo.getLong("WORKORDERID")
#woId = str(woId)
#woId = woId.replace(',','')
#Logging"Value for woId is " + str(woId))
#List of fields that will be read only. Add additional fields with a comma.
readOnlyFields = ['WORKTYPE']
# Get a list of valid workflow assignment statuses
statusList = mbo.getTranslator().toExternalList("WFASGNSTATUS", "ACTIVE")
# Construct a where clause to find the existing workflow assignment 
# for this work order. Ensure that one exists before proceeding. 
whereClause = SqlFormat(mbo.getUserInfo(), "ownertable = :1 and ownerid = " + str(woId) + " and assignstatus in (" + statusList + ")")
whereClause.setObject(1, "WFASSIGNMENT", "OWNERTABLE", "WORKORDER")
# Get record set and filter it by the where clause
wfAssignmentSet = mbo.getMboSet("$WOAPPR", "WFASSIGNMENT", whereClause.format())
if not wfAssignmentSet.isEmpty():"Found WF Assignments for this WO – settings fields readonly")
 	# Make fields read only if the work order is in workflow
 	# There will be more read only fields.  Fields can also be made
    # required using the same principle.
 	mbo.setFieldFlag(readOnlyFields, MboConstants.READONLY, True)
if mbo.getThisMboSet().getParentApp() == "WOTRACK":
 	woOwner = mbo.getOwner()


One of our missions A3J Group is to share knowledge whenever we can. We hope this helps you in your day!

Customizing Ad Hoc Reports

We all want to make our Maximo reports as informative and readable as possible, but sometimes the available attributes for an Ad Hoc report don’t provide the information we want to see. For example, let’s look at a Work Order record. If I wanted to pull this Work Order into a report, I would have a hard time knowing what company is being used as the Vendor and which “Ed” is supervising the Work Order. So instead of using these attributes on our Work Order reports, why not use the display name of the Supervisor or the name of the Vendor company? In the steps below, I’ll use the “company name” example to demonstrate creating an Ad Hoc report with an attribute from a separate application.

First things first, let’s see what it looks like if I try to create a report that includes the name of the Vendor company. There isn’t anything related to the Companies object on the left side panel, so I can’t access the attribute I need yet. However, we can see the description of our reporting Object Structure at the top. (We’ll save that piece for later!)

For now, let’s grab the information we need to create a relationship between the Work Order object and the Companies object. I’ll have to use my trusty ALT+i shortcut to get the value of two different attributes: the attribute representing the record I want to access and the attribute on that record which is being displayed. In my case, the Work Order “VENDOR” attribute represents the record I want to reach and the “COMPANY” attribute stores that same value in the Companies object.




Now we can go into the Database Configuration and see if there is a relationship from the Work Order object to the Companies objects which uses these fields. Looks like there are none, so let’s create a new row and make it ourselves!

I’ve filled in my details as shown below. Remember when creating a new relationship between objects, the Relationship should have the same name as the Child Object to avoid creating duplicates in the future. In your Where Clause, the value of the Child attribute is listed first and attributes on the Parent are retrieved using a binding ‘:’ symbol.

Now that the Work Order knows how to access the Companies application, let’s go to the Object Structures application and use this relationship to alter the reporting structure we saw earlier.

Scroll to the “Source Objects” section and create a new using the COMPANIES Object, the WORKORDER Parent Object, and the brand-new COMPANIES Relationship. Make sure to enter a Reporting Description so anyone creating an Ad Hoc report knows what this object represents.

Finally, let’s go back to Work Order Tracking and create a new report. We can now see the new Vendor Information object in the structure and select it. This is where I can access any of the attributes that the Companies object has to offer.

Once I’ve added the company Description to my report, I can go ahead and run a preview to see it in action. This version of my report is much easier to understand, and it saves me time digging around in Company records for more information. So, try creating new object relationships and adding to object structures to make your Ad Hoc reports the best they can be!

MxMobile Update June 2023 Release

ibm_mxmobile_maximo mobile_app_application_suite_report_maintenance_reliability_industry_4_work_order_enterprise_asset_management_inventory_perform_count_log_time_create_meter_reading_shipping_and_recieving_mobility_admin_service_request_issue_parts_material_approve_task_job_plan_software_upgrade

A3J Group is happy to announce the latest MxMobile releases below. As an IBM Maximo mobile solution provider, A3J Group consistently improves the functionality and features of MxMobile. Enriching the experience of MxMobile users is an important part of our user mission. Our uers enjoy the freedom of Maximo mobility and are happy request interface features, functionality needs and our team actively delivers on those requests. You can download MxMobile apps from the Apple App or Google Play store.

The releases will be available on Monday, June 12, 2023.

June Release Updates


    • Ability to organize and group saved queries on the home screen
    • Ability to make work orders read-only based on status and labor timer status
    • Prompt user to save if certain screens have been edited but not committed
    • General bug fixes and performance improvements

What do you need to do?

  • Updates are available to current clients automatically by updating your apps via the appropriate app store.
  • If you would like to request a new feature or report a bug, please follow our new support ticket guidelines submitting a video and a support form describing the request.

If your like to learn more, please fillin the form below and we’ll be in contact!

Workflow Delegates

Pretend you are going to take a real vacation, two weeks in Spain with no work laptop. You have planned and prepared for your trip but, what about all the work that is going to keep going while you are away? Work orders still need to be reviewed, assigned, and approved by someone. Purchase Orders and Invoices need to be approved so vendors can get paid. You know that giving your username and password to your co-workers so they can log in and do your work is against company policy (and no one wants to get on IT’s bad side). Lucky for you Maximo has a way to help you out so you can eat tapas in peace knowing work is being handled, it is called Workflow Delegates.

Workflow delegates allow you to select a single person to receive all records that are sent to you via workflow in Maximo. Maximo allows you to set a start and end date for your delegate to receive the records or you can just enter a start date and never select an end date.

There are some things to think about when selecting a workflow delegate.

  • Any records that were sent to them while they are acting as a delegate will stay with them even after the delegation ends.
  • For financial records if the delegate does not have sufficient limits and tolerances they will not be able to approve the record. Depending on how Maximo is configured this may result in an error message or the record may be routed to an approver with higher limits and tolerances.
  • If the delegate does not have security access to the application the record was created in then the delegate will not be able to view the record. Selecting a delegate with the equal or greater security privileges is advised.

Once you return from your trip to Spain you can log into Maximo knowing that work has continued without you.

How to set a workflow delegate:

  1. Navigate People application from Administration > Resources > People and open a Person record.maximo_workflow
  2. Populate the Workflow Delegate field and at least the Delegate From field.maximo_workflow

Maximo Bug with Start Center Result Set and Custom Application

I created a query and then added a result set to the Start Center for our custom application.   In the Result Set portlet the query was chosen but no fields were displaying in the Available List or objects in the Object List.

The reason for the empty fields was ultimately due to a database length field issue on two objects: RESULTSETCOLS and RSCONFIGSELECT.  The APP attribute field length is 10 but our custom application name length was 11.


Increasing the attribute length for APP in RESULTSETCOLS and RSCONFIGSELECT followed by a database configuration corrected the problem which resulted in the Object List and Available Fields list displaying the appropriate information.


This was in Maximo so the problem may already be corrected in a patch.




Enable Logging to Capture Report Data Set Queries in Maximo 7.6

You upload your awesome new report in Maximo, click the Preview button or run the report and…. you get no results.  Is the problem in the Maximo Where clause, the report query or …?  Naturally you turn to the Maximo Logging application, crank up the SQL and Report loggers to DEBUG then sit back and comb through all those juicy log statements that pinpoint exactly where the problem resides.  Sound familiar?  

Of course not!  You crank up all that logging and comb through a whole bunch of nothing.   

This article will detail one way to coax Maximo into giving up all the information you need to properly diagnose your report running in Maximo 7.6.  You may not need to perform all these steps; however, I was not able to see exactly what I needed until I performed the last step.  

The report I was developing was based on the ASSET application and was rather complicated.  Consequently I wanted a lot of information ouof Maximo.  You may not need or want all these loggers running to diagnose your report so feel free to adjust these steps to suit your specific requirements. Keep in mind that if you do not see what you want in the log execute all these steps and get it working.  Then you can pare it down to be more efficient. 

Set appropriate loggers to DEBUG using the Maximo Logging application. 


As I mentioned, the report I was working on was based on ASSET. I wanted to see both ASSET object queries and report queries.  Navigate to the Logging application Maximo and filter the Logger list to show sql. 



Change the log level to Debug anApply Settings so the changes take effect. 

If you execute the report now all you will see is some SQL statements as you navigate around the ASSET object filtering the records for your eventual report.  While potentially useful in providing a complete picture of the data being requested it is most likely not what we need to figure out why our report is not displaying any records.  In order to see Birt and report related log statements we need to adjust the log level of the report logger. 

Filter the Logging application by report and adjust the log level to DEBUG for the report logger as well as the birt and directprint loggers.  Do not forget to Apply Settings. 


Setting additional Report loggers to DEBUG. 


If you, like me, run your report you still will not see what you want in the log.   

In order to see the report parameters, where clauseactual DataSet query being used and a whole bunch of other report information I had to execute the following sql statement against my Maximo database. 

update maxlogger set loglevel = ‘DEBUG’ where logkey like ‘; 

Be sure to commit the update if not using SQL Server.   

You will need to restart the Maximo application server after this update.  The logger update will not take effect until the Maximo application is restarted.   

Now if you run the report you will see the actual queries being executed from within Maximo.       

Save time by creating Command Aliases

Hello, everyone! Let’s skip the formal introduction about myself since it kind of fits the theme of the topic. Let’s talk about a hack to cut out extra steps when writing commands. To me it doesn’t matter whether the hack takes out a few or a lot of steps. Everyone can enjoy making and discovering new ways to work more efficiently. I promise an exact example of hack efficiency is coming up and it won’t affect the quality of the final product or goal.

Now let’s talk about the highlights of being lazy. I selected this topic because I felt this perspective was greatly imprinted on me after watching Bill Gates praise lazy people for being ingenious at finding faster and more efficient ways to resolve problems. (Side note – he is a living legend.) I am no master at being lazy, but there is an art to laziness that doesn’t have minor or outrageous consequences. This example of using aliases on Windows and Mac operating systems says it all.

Use of terminal commands are essential for Ionic development. You need them to install libraries, plugins, build folders, and even just moving in between files. By creating aliases you can define customized shortcuts that can save you considerable time. Let’s look at an example. This example is for Mac but there is a Windows tutorial at the end and the concept is completely identical.

To be specific, you need to be setting this inside a file in your configuration somewhere described in the videos. The line below will now make mxr the same as if you typed out all of cd ~desktop/work/a3jgroup/mxreserve. It’s a very easy step to turning the act of having to type out half a sentence into practically a word.

alias mxr = 'cd ~desktop/work/a3jgroup/mxreserve'

At the end of the day it’s just some extra typing but there is such usefulness when it comes to more complicated steps. There are a lot of unique commands specific to Cordova, Ionic and other cases where this will save you time looking up things that you don’t need to remember for real development. So let’s do some math to back this up and just nerd out a little.

This is a link for a quick typing test if you want to see your own score: My score was 43 words a minute. I think it could be better if I take another test. However, that might be a complete waste of time to cover up a slightly self-conscious moment. I have about 60 shortcuts, each averaging about 3 words. It would be more than safe to say that I end up using a shortcut about 10 times on a work day, so:

Total seconds saved per command (TS) = (60/43) * (3-1) = 2.7906 seconds
Seconds saved from typing in a day (SPD) = 10 * TS = 27.9 seconds
Total work days in a year (WDPY) = 52 * 5 – 20 (Vacation and Holiday) = 240
Annual time savings = 240 * 27.9 = 6,696 seconds = 111.6 minutes per year.

There are 525,600 minutes in a year so it’s a small saving. However, it’s almost 2 hours that I get to skip out on remembering something way too specific and doesn’t require my creative side.

Anyway that is really all of it. The math could better account all the variables in a work year but I kept it simple. I’m really happy to have the chance to share with you all something that is in my eyes a hidden beauty in the development process.

Link to tutorial on creating aliases:



A3J – A Blog Life

One of our goals at A3J is to share, specifically information.  We’ve never found it very useful to keep the cards close to our chests, and we’ve always had a great admiration for those who aren’t afraid to put it all out there without regard to profit or fame.  The simple good will of getting information out that could help someone else is very uplifting.  With each blog article, we are paying it forward as a result of benefiting from other’s good will in the past.

We wrote our first blog piece in December of 2016, more than two years ago.  Hard to believe.  Like any new company with all of the players wearing too many hats, blog pieces were a scarcity, only happening sporadically and without planning.

Then one day we wrote the article that would go down in A3J lore as the lightbulb moment.  It was a little article on SSL and how to create a secure connection thereby protecting your Maximo environment.  It was an issue we had struggled with.  We knew many others who had as well.  So we wrote something on how we went about this task.  Needless to say it took off.

From then on we got serious about writing and recently we’ve created an internal initiative to make the writing more consistent.  As with any company filled with techies, the elation was vast, and their pens began to scrawl poetic words to rival Fitzgerald.  We jest.  Some came more willingly than others to the writing table, but everyone could appreciate putting out helpful content that made someone’s job somewhere a little easier.

So look for these blogs to post on the first Thursday of the month with the first one starting in April.  Many will be technically oriented but it’s all hands on deck and everyone will be writing an article.  Along with the technical articles, some will have a marketing focus or a professional services/management focus or brand new to EAM/Maximo deer in headlight focus.  Either way we hope they are helpful, insightful and maybe even occasionally entertaining.  In the meantime, check out all of our blog articles at