IBM Maximo is a robust Enterprise Asset Management platform designed to support complex operational processes, but real-world business needs often extend beyond standard out-of-the-box functionality. To address these requirements, Maximo provides powerful customization capabilities that allow developers to enhance both user experience and system behavior. One such capability is the creation of custom dialogs, which enable structured user interactions, data validation, and guided decision-making directly within the application.
When custom dialogs are integrated with automation scripts, they become a key mechanism for executing business logic in a controlled and efficient manner. Automation scripts allow developers to respond dynamically to user inputs, enforce business rules, and automate backend processes without extensive Java customization. This combination not only improves usability for end users but also ensures that custom logic remains scalable, maintainable, and aligned with Maximo best practices as the system evolves.
Step 1: Creating a New Dialog in Maximo
- Log in to the Maximo application and navigate to the Application Designer.
- Select the application in which you want to create the custom dialog. For this example, the People application is used.
- There are two approaches to creating a custom dialog in Maximo:
- Option A: Create the dialog by modifying the application XML
- Option B: Create the dialog directly through the Application Designer interface
- In this scenario, Option A is preferred because it is more efficient and easier to manage. You can export the application XML using the Export XML button and save it to your local machine.
- A pre-built XML dialog configuration is already available for use. You may either reuse the XML provided below or create your own dialog by using it as a reference. If you choose to use the provided XML, ensure that a Non-Persistent Object is created with the attributes referenced in the XML.
<dialog id="addrelloc" label="Add Related Assets and Locations">
<section id="addrelloc_grid1">
<multiparttextbox dataattribute="personid" descdataattribute="displayname" descinputmode="readonly" id="addrelloc_grid1_1" inputmode="readonly"/>
</section>
<tabgroup id="addrelloc_tabgroup_1">
<tab default="true" id="addrelloc_tabgroup_tab1" label="Locations" type="insert" >
<table id="addrelloc_view_personstatus" label="Status History" orderby="changedate desc" relationship="USERCUST">
<tablebody displayrowsperpage="20" filterable="true" id="addrelloc_view_personstatus_tablebody">
<tablecol dataattribute="location" id="addrelloc_view_personstatus_tablebody_2"/>
<tablecol dataattribute="ISPRIMARY" id="addrelloc_view_personstatus_tablebody_5"/>
<tablecol dataattribute="ISCUSTODIAN" id="addrelloc_view_personstatus_tablebody_6"/>
<tablecol dataattribute="ISUSER" id="addrelloc_view_personstatus_tablebody_7"/>
<tablecol dataattribute="personid" id="addrelloc_view_personstatus_tablebody_8"/>
</tablebody>
<tabledetails id="addrelloc_tab2_loc_tabledetails">
<section id="addrelloc_tabledetails_loc">
<sectionrow id="addrelloc_tabledetails_loc_row1">
<sectioncol id="addrelloc_tabledetails_loc_row1_col1">
<section id="addrelloc_tabledetails_loc_row1_col1_1">
<multiparttextbox dataattribute="location" descdataattribute="DESCRIPTION" descinputmode="readonly" id="addrelloc_tabledetails_loc_row1_col1_1_1"/>
<textbox dataattribute="PERSONID" id="1765983543357"/>
<textbox dataattribute="siteid" id="addrelloc_tabledetails_loc_row1_col1_1_2"/>
</section>
</sectioncol>
<sectioncol id="addrelloc_tabledetails_loc_row1_col2">
<section id="addrelloc_tabledetails_loc_row1_col2_sec1">
<checkbox dataattribute="ISPRIMARY" id="addrelloc_tabledetails_loc_row1_col2_sec1_1"/>
<checkbox dataattribute="ISUSER" id="addrelloc_tabledetails_loc_row1_col2_sec1_2"/>
<checkbox dataattribute="ISCUSTODIAN" id="addrelloc_tabledetails_loc_row1_col2_sec1_3"/>
</section>
</sectioncol>
</sectionrow>
</section>
</tabledetails>
<buttongroup id="addrelloc_4">
<pushbutton default="true" id="1764611856539" label="New Row" mxevent="addrow"/>
</buttongroup>
</table>
</tab>
<tab default="true" id="addrelloc_tabgroup_tab2" label="Assets" type="insert">
<table id="addrelloc1_view_personstatus2" label="Status History" orderby="changedate desc" relationship="USERCUST">
<tablebody displayrowsperpage="20" filterable="true" id="addrelloc_view_personstatus_tablebody">
<tablecol dataattribute="assetnum" id="addrelloc1_view_personstatus_tablebody_1"/>
<tablecol dataattribute="ISPRIMARY" id="addrelloc1_view_personstatus_tablebody_5"/>
<tablecol dataattribute="ISCUSTODIAN" id="addrelloc1_view_personstatus_tablebody_6"/>
<tablecol dataattribute="ISUSER" id="addrelloc1_view_personstatus_tablebody_7"/>
<tablecol dataattribute="personid" id="addrelloc1_view_personstatus_tablebody_8"/>
</tablebody>
<tabledetails id="addrelloc1_tab2_loc_tabledetails">
<section id="addrelloc1_tabledetails_loc">
<sectionrow id="addrelloc1_tabledetails_loc_row1">
<sectioncol id="addrelloc1_tabledetails_loc_row1_col1">
<section id="addrelloc1_tabledetails_loc_row1_col1_1">
<multiparttextbox dataattribute="assetnum" descdataattribute="DESCRIPTION" descinputmode="readonly" id="addrelloc1_tabledetails_loc_row1_col1_1_1"/>
<textbox dataattribute="PERSONID" id="1765983543357"/>
<textbox dataattribute="siteid" id="addrelloc1_tabledetails_loc_row1_col1_1_2"/>
</section>
</sectioncol>
<sectioncol id="addrelloc1_tabledetails_loc_row1_col2">
<section id="addrelloc1_tabledetails_loc_row1_col2_sec1">
<checkbox dataattribute="ISPRIMARY" id="addrelloc1_tabledetails_loc_row1_col2_sec1_1"/>
<checkbox dataattribute="ISUSER" id="addrelloc1_tabledetails_loc_row1_col2_sec1_2"/>
<checkbox dataattribute="ISCUSTODIAN" id="addrelloc1_tabledetails_loc_row1_col2_sec1_3"/>
</section>
</sectioncol>
</sectionrow>
</section>
</tabledetails>
<buttongroup id="addrelloc1_4">
<pushbutton default="true" id="1764611856539" label="New Row" mxevent="addrow"/>
</buttongroup>
</table>
</tab>
</tabgroup>
<buttongroup id="addrelloc_3">
<pushbutton default="false" id="addrelloc_3_1" label="Cancel" mxevent="dialogcancel"/>
<pushbutton default="true" id="addrelloc_3_2" label="OK" mxevent="addcust"/>
</buttongroup>
</dialog>
- Once the dialog definition has been merged into the application XML, save the file and import it back into the Maximo application.
- After importing the XML, create a new sigoption for the application. Ensure that the sigoption name exactly matches the ID of the dialog you created.
<dialog id=“addrelloc” label=”Add Related Assets and Locations”> - After creating the sigoption, click Add/Modify Select Action Menu.
- Add a new Select Action menu entry with the following values:
- Element Type: OPTION
- Key Value: ADDRELLOC
- Position: 131 (adjust as needed based on your application layout)
- Subposition: 0 (adjust as needed)
- Visible: Yes (or 1)
Click OK once the configuration is complete.
- Next, navigate to the Security Groups application and grant access to the newly created sigoption. For example, select the MAXADMIN security group, go to the Applications tab, choose the People application, locate the sigoption, and grant access. Save the changes, then log out and log back into Maximo for the updates to take effect.
At this stage, the custom dialog has been successfully created and made accessible within the application. However, the dialog is not yet associated with any business logic. In the next step, we will implement the automation script and link it to the dialog to handle the required functionality.
Step 2: Creating an Automation Script
- Navigate to the Automation Scripts application in Maximo.
- Create a new script using an Action Launch Point by selecting Create → Script with Action Launch Point.
- In the Create Script dialog, provide all the required details, such as the script name, and script type.
- After the script is created, implement the required business logic within the script.
from psdi.server import MXServer
from psdi.mbo import MboConstants, SqlFormat
from psdi.util.logging import MXLoggerFactory
logger = MXLoggerFactory.getLogger("maximo.script.ADDCUST")
logger.debug("Script Started")
logger.debug("Current Mbo: " + mbo.getName())
usercustSet = mbo.getMboSet("USERCUST")
usercust = usercustSet.moveFirst()
while usercust:
location = usercust.getString("LOCATION")
siteid = usercust.getString("SITEID")
assetnum = usercust.getString("ASSETNUM")
personid = usercust.getString("PERSONID")
primary = usercust.getBoolean("ISPRIMARY")
userFlg = usercust.getBoolean("ISUSER")
custodian = usercust.getBoolean("ISCUSTODIAN")
deleteRecords = usercust.getBoolean("DELETERECORDS")
# =========================
# LOCATIONUSERCUST
# =========================
if location:
locSet = MXServer.getMXServer().getMboSet("LOCATIONS", mbo.getUserInfo())
sqlf = SqlFormat(mbo, "LOCATION = :1 AND SITEID = :2")
sqlf.setObject(1, "LOCATIONS", "LOCATION", location)
sqlf.setObject(2, "LOCATIONS", "SITEID", siteid)
locSet.setWhere(sqlf.format())
locSet.reset()
locMbo = locSet.getMbo(0)
if locMbo:
if not deleteRecords:
locUserSet = locMbo.getMboSet("LOCATIONUSERCUST")
locUserSet.setWhere("PERSONID = '%s'" % personid)
locUserSet.reset()
if locUserSet.isEmpty():
locUserMbo = locUserSet.add()
locUserMbo.setValue("PERSONID", personid, MboConstants.NOACCESSCHECK)
locUserMbo.setValue("ISPRIMARY", primary, MboConstants.NOACCESSCHECK)
locUserMbo.setValue("ISUSER", userFlg, MboConstants.NOACCESSCHECK)
locUserMbo.setValue("ISCUSTODIAN", custodian, MboConstants.NOACCESSCHECK)
else:
logger.debug("Record Count:" + locUserMbo.count())
#locUserSet.deleteAll()
locSet.save()
locSet.close()
# =========================
# ASSETUSERCUST
# =========================
if assetnum:
assetSet = MXServer.getMXServer().getMboSet("ASSET", mbo.getUserInfo())
sqlf = SqlFormat(mbo, "ASSETNUM = :1 AND SITEID = :2")
sqlf.setObject(1, "ASSET", "ASSETNUM", assetnum)
sqlf.setObject(2, "ASSET", "SITEID", siteid)
assetSet.setWhere(sqlf.format())
assetSet.reset()
assetMbo = assetSet.getMbo(0)
if assetMbo:
assetUserSet = assetMbo.getMboSet("ASSETUSERCUST")
assetUserSet.setWhere("PERSONID = '%s'" % personid)
assetUserSet.reset()
if assetUserSet.isEmpty():
if not deleteRecords:
assetUserMbo = assetUserSet.add()
assetUserMbo.setValue("PERSONID", personid, MboConstants.NOACCESSCHECK)
assetUserMbo.setValue("ISPRIMARY", primary, MboConstants.NOACCESSCHECK)
assetUserMbo.setValue("ISUSER", userFlg, MboConstants.NOACCESSCHECK)
assetUserMbo.setValue("ISCUSTODIAN", custodian, MboConstants.NOACCESSCHECK)
else:
logger.debug("Record Count:" + assetUserSet.count())
#assetUserSet.deleteAll()
assetSet.save()
assetSet.close()
usercust = usercustSet.moveNext()
- The automation script illustrates how Maximo can be extended programmatically to add (and, if required, remove) user associations for both Locations and Assets by interacting with the LOCATIONUSERCUST and ASSETUSERCUST objects.
- After completing the automation script, the next step is to associate its action with the custom dialog created in Step 1. To do this, navigate back to the Application Designer.
- Search for and open the People application (or the application in which the dialog was created).
- Create a new sigoption and ensure that its name exactly matches the action name defined in the automation script.
- In the Advanced Signature Options, select “This is an action that must be invoked by user in UI.”
- Open the custom dialog, select the OK button, right-click, and choose Properties.
- In the button event configuration, associate the sigoption you created with the OK button.
- Finally, navigate to the Security Groups application and grant access to the newly created sigoption to the appropriate user groups.
About
A3J Group is a leading solutions and consulting firm based in Tampa, Florida, specializing in Enterprise Asset Management (EAM) with a focus on fully developed Computerized Maintenance Management System (CMMS) solutions like IBM Maximo.
In addition to our suite of proprietary products—including MxMobile, our powerful mobile solution for Maximo—we provide traditional consulting services that help organizations plan, implement, optimize, and support their EAM strategies. Whether clients need hands-on configuration, strategic guidance, or ongoing system support, our team delivers the expertise to drive long-term success.
With over 50 years of combined experience, our specialized team is dedicated to our core mission: to serve as excellent stewards of our clients’ trust and investments, while driving measurable results through tailored, high-impact solutions and intelligent consulting.
Visit us at www.a3jgroup.com. Or drop us a line at info@a3jgroup.com.



