Mastering the Maximo Work Order Lifecycle: Status Control, Flow Control, and Conditional Processing

>

Share
Mastering the Maximo Work Order Lifecycle: Status Control, Flow Control, and Conditional Processing

Mastering the Maximo Work Order Lifecycle: Status Control, Flow Control, and Conditional Processing

The work order is the central nervous system of Maximo Manage. Every maintenance activity, every dollar of cost, every hour of labor, and every piece of asset history flows through work orders. Yet most organizations treat the work order lifecycle as a fixed sequence of statuses that came out of the box. They accept the default WAPPR to APPR to INPRG to COMP to CLOSE flow without questioning whether it matches how their maintenance organization actually works.

This article covers how to design, configure, and extend the work order lifecycle to match real-world maintenance processes. It goes beyond the basics of status codes and into the mechanics of flow control, conditional processing, and the automation patterns that make work orders behave intelligently.

The Work Order State Machine

At its core, a Maximo work order is a state machine. It exists in exactly one status at any given time, and it can transition to other statuses based on rules defined in the status control configuration. Understanding this state machine is the foundation for everything that follows.

The Default Status Flow

Maximo ships with a default set of work order statuses and transitions. Here is the standard flow:

┌─────────┐
│ WAPPR │ (Waiting Approval)
└────┬────┘

┌────▼────┐
┌─────│ APPR │ (Approved)
│ └────┬────┘
│ │
│ ┌────▼────┐
│ │ INPRG │ (In Progress)
│ └────┬────┘
│ │
│ ┌────▼────┐
│ │ COMP │ (Complete)
│ └────┬────┘
│ │
│ ┌────▼────┐
└─────▶ CLOSE │ (Closed)
└─────────┘

This linear flow works for simple maintenance operations. It does not work for organizations that need to:

  • Reject work orders and send them back for revision
  • Place work orders on hold waiting for parts or permits
  • Route work orders through multiple approval levels
  • Cancel work orders that are no longer needed
  • Reopen completed work orders for rework

Extended Status Model

A production-grade status model includes additional statuses and transitions:

┌──────────┐
│ DRAFT │
└────┬─────┘

┌────▼─────┐
┌────│ WAPPR │◄──────────┐
│ └────┬─────┘ │
│ │ │
┌─────┤ ┌────▼─────┐ ┌─────┴─────┐
│ │ │ APPR │ │ REJECTED │
│ │ └────┬─────┘ └───────────┘
│ │ │
│ │ ┌────▼─────┐
│ │ │ INPRG │◄──────────┐
│ │ └────┬─────┘ │
│ │ │ │
│ │ ┌────▼─────┐ ┌──────┴──────┐
│ │ │ COMP │ │ ONHOLD │
│ │ └────┬─────┘ └─────────────┘
│ │ │
│ │ ┌────▼─────┐
│ └───▶│ CLOSE │
│ └──────────┘

└──────▶ ┌──────────┐
│ CANCEL │
└──────────┘

This extended model supports real-world maintenance workflows. A work order can be rejected during approval and sent back to WAPPR for revision. It can be placed on hold when parts are unavailable. It can be cancelled if the work is no longer needed. And it can be reopened from CLOSE back to INPRG if rework is required.

Configuring Status Control

Status control in Maximo is configured through the Organizations application, under the Work Order Options action. Each status transition is defined as a row in the status control table, specifying the originating status, the target status, and any conditions that must be met.

Basic Status Control Configuration

The status control table defines which transitions are allowed. Here is a representative configuration:

From Status To Status Flow Control? Condition Memo Required?
DRAFT WAPPR No None No
WAPPR APPR Yes :status != 'REJECTED' No
WAPPR REJECTED No None Yes
WAPPR CANCEL No None Yes
APPR INPRG Yes :personid is not null No
APPR REJECTED No None Yes
INPRG COMP Yes :actlabhrs > 0 No
INPRG ONHOLD No None Yes
ONHOLD INPRG No None No
COMP CLOSE Yes :actlabhrs > 0 and :actmatcost > 0 No
CLOSE INPRG No None Yes
Any CANCEL No None Yes

The "Flow Control" flag determines whether the transition triggers flow control processing. When set to Yes, Maximo evaluates the flow control configuration to determine whether the transition is allowed based on additional conditions.

Flow Control: The Gatekeeper

Flow control is the mechanism that enforces business rules during status transitions. It is more powerful than simple status control because it can evaluate conditions against the work order's current state and prevent transitions that violate business rules.

Flow control is configured in the Flow Control application. Each flow control record specifies:

  • Object: The MBO being controlled (WORKORDER)
  • From Status: The originating status
  • To Status: The target status
  • Sequence: The order in which conditions are evaluated
  • Condition: A SQL condition that must be true
  • Error Message: The message displayed when the condition fails

-- Example flow control conditions for work order transitions

-- WAPPR to APPR: Require a supervisor to approve
-- Condition: The work order must have a supervisor assigned
:supervisor is not null

-- APPR to INPRG: Require a lead craft to be assigned
-- Condition: A lead craft must be assigned before work begins
:lead is not null and :amcrew is not null

-- INPRG to COMP: Require actual labor hours
-- Condition: At least some labor must be reported
:actlabhrs > 0

-- COMP to CLOSE: Require all costs to be captured
-- Condition: Labor, materials, and tools must be reported
:actlabhrs > 0 and :actmatcost > 0 and :acttoolhrs > 0

When a user attempts to change a work order's status, Maximo evaluates all flow control conditions for that transition in sequence. If any condition fails, the transition is blocked and the error message is displayed. If all conditions pass, the transition proceeds.

Conditional Flow Control with Automation Scripts

The built-in flow control conditions are powerful but limited to simple SQL expressions. For complex business logic, you can use automation scripts as flow control conditions. This allows you to evaluate conditions that require multi-table queries, external system calls, or complex calculations.

# Automation Script: Flow Control Condition
# Launch Point: FLOWCONTROL on WORKORDER
# Object: WORKORDER
# Condition evaluates whether a work order can move from INPRG to COMP

from psdi.mbo import MboConstants
from java.util import Date

def evaluate_flow_control():
"""
Custom flow control condition for INPRG to COMP transition.
Returns True if the transition is allowed, False otherwise.
"""

# Check 1: All required safety permits must be closed
permit_set = mbo.getMboSet("SAFETYPERMIT")
if permit_set is not None and not permit_set.isEmpty():
permit = permit_set.moveFirst()
while permit is not None:
if permit.getString("STATUS") != "CLOSED":
# Set error message on the flow control result
flowControl.setErrorMessage(
"Cannot complete work order. Safety permit {} is still open.".format(
permit.getString("PERMITNUM")
)
)
return False
permit = permit_set.moveNext()

# Check 2: Failure report must be completed for emergency work orders
if mbo.getString("WORKTYPE") == "EM":
failure_report = mbo.getMboSet("FAILUREREPORT")
if failure_report is None or failure_report.isEmpty():
flowControl.setErrorMessage(
"Emergency work orders require a completed failure report before completion."
)
return False

# Check 3: Actual finish date must be populated
if mbo.getDate("ACTFINISH") is None:
flowControl.setErrorMessage(
"Actual finish date must be entered before completing the work order."
)
return False

# All checks passed
return True

# Call the evaluation function
result = evaluate_flow_control()

This script evaluates three conditions that cannot be expressed in simple SQL: checking related safety permits, verifying failure reports for emergency work orders, and ensuring the actual finish date is populated. If any condition fails, the script sets an error message and returns False, blocking the transition.

Building a Conditional Work Order Processor

Beyond status transitions, work orders often need conditional processing based on their attributes. For example, a work order for a critical asset might need additional approvals, or a work order exceeding a cost threshold might need financial review.

The Conditional Processing Pattern

The most maintainable approach to conditional processing is a decision table implemented as an automation script. The script evaluates the work order against a set of rules and takes appropriate actions:

# Automation Script: Work Order Conditional Processor
# Launch Point: OBJECT - WORKORDER - Save - After Save
# Evaluates work order conditions and applies business rules

from psdi.mbo import MboConstants
from psdi.util import MXException

def process_work_order():
"""
Evaluate work order conditions and apply business rules.
This runs after every save and applies rules based on the
work order's current state and attributes.
"""

# Rule 1: Critical asset work orders require supervisor approval
asset = mbo.getMboSet("ASSET")
if asset is not None and not asset.isEmpty():
asset_mbo = asset.moveFirst()
criticality = asset_mbo.getInt("CRITICALITY", 0)

if criticality >= 8 and mbo.getString("STATUS") == "WAPPR":
# Auto-route to the asset's responsible supervisor
supervisor = asset_mbo.getString("SUPERVISOR")
if supervisor:
mbo.setValue("SUPERVISOR", supervisor, MboConstants.NOACCESSCHECK)
mbo.setValue("STATUS", "APPR", MboConstants.NOACCESSCHECK)

# Rule 2: High-cost work orders require financial review
estimated_cost = mbo.getDouble("ESTTOTCOST")
if estimated_cost and estimated_cost > 50000:
if mbo.getString("STATUS") == "WAPPR":
# Add a flag for financial review
mbo.setValue("HASFINANCIALREVIEW", True, MboConstants.NOACCESSCHECK)

# Create a follow-up work order for the finance team
follow_up = mbo.getMboSet("FOLLOWUPWO").add()
follow_up.setValue("DESCRIPTION",

"Financial review required: Estimated cost ${:,.2f}".format(estimated_cost))
follow_up.setValue("ASSIGNEDTO", "FINANCE_TEAM")

# Rule 3: PM-generated work orders inherit asset strategy
if mbo.getString("ORIGRECORDCLASS") == "PM":
pm_num = mbo.getString("ORIGRECORDID")
if pm_num:
pm_set = mbo.getMboSet("PM")
pm_set.setWhere("PMNUM = '{}'".format(pm_num))
pm = pm_set.moveFirst()
if pm:
strategy = pm.getString("MAINTSTRATEGY")
if strategy:
mbo.setValue("MAINTSTRATEGY", strategy, MboConstants.NOACCESSCHECK)

# Rule 4: Safety-related work orders require a job plan
if mbo.getBoolean("ISSAFETYRELATED"):
jp_set = mbo.getMboSet("JOBPLAN")
if jp_set is None or jp_set.isEmpty():
raise MXException(
"SAFETY",

"Safety-related work orders require a job plan. Please attach a job plan before saving."
)

# Execute the processor
try:
process_work_order()
except MXException as e:
# Re-raise to prevent the save
raise

Escalation Management

Escalations are Maximo's built-in mechanism for time-based conditional processing. They run on a schedule and evaluate conditions against sets of records, taking actions when conditions are met. For work order lifecycle management, escalations are essential for:

  • Auto-approving work orders that have been waiting too long
  • Escalating overdue work orders to supervisors
  • Auto-closing work orders that have been complete for a configurable period
  • Sending notifications when work orders approach due dates

-- Escalation: Auto-approve work orders waiting more than 24 hours
-- Applies to: WORKORDER where STATUS = 'WAPPR'
-- Condition: STATUSDATE < (SYSDATE - 1)
-- Action: Set STATUS = 'APPR', update STATUS DATE

-- Escalation: Notify supervisor of overdue work orders
-- Applies to: WORKORDER where STATUS = 'INPRG'
-- Condition: TARGCOMPDATE < SYSDATE
-- Action: Send email to SUPERVISOR

-- Escalation: Auto-close completed work orders after 30 days
-- Applies to: WORKORDER where STATUS = 'COMP'
-- Condition: STATUS DATE < (SYSDATE - 30)
-- Action: Set STATUS = 'CLOSE', update STATUS DATE

The key to effective escalation management is restraint. Every escalation consumes database resources. A poorly written escalation that scans the entire WORKORDER table every 5 minutes will degrade system performance. Follow these guidelines:

  1. Use indexed conditions: The WHERE clause in the escalation should use indexed columns (STATUS, STATUS DATE, SITEID).
  2. Limit the result set: Use additional conditions to narrow the scope. For example, add and SITEID = :SITEID to limit to the current site.
  3. Set appropriate schedules: Do not run escalations more frequently than necessary. A 5-minute schedule for auto-approval is excessive. A 1-hour schedule is usually sufficient.
  4. Monitor escalation performance: Use the Escalation Log to identify escalations that take too long to execute.

Custom Status Handlers

For organizations with complex status transition requirements, custom status handlers provide the most flexibility. A status handler is a Java class that implements the StatusHandler interface and is invoked whenever a work order's status changes.

While Java development is outside the scope of this article, automation scripts can achieve similar results through object launch points:

# Automation Script: Custom Status Change Handler
# Launch Point: OBJECT - WORKORDER - Status Change
# This script runs whenever the work order status changes

def handle_status_change():
"""
Handle side effects of work order status changes.
This runs after the status has been changed and the record saved.
"""

old_status = mbo.getString("PREVSTATUS")
new_status = mbo.getString("STATUS")

# Log the status change for audit purposes
audit_set = mbo.getMboSet("WOAUDITLOG")
audit = audit_set.add()
audit.setValue("OLDSTATUS", old_status)
audit.setValue("NEWSTATUS", new_status)
audit.setValue("CHANGEDBY", user)
audit.setValue("CHANGEDATE", MXServer.getMXServer().getDate())

# When moving to INPRG, create a labor transaction for the lead
if new_status == "INPRG" and old_status in ("APPR", "WAPPR"):
lead = mbo.getString("LEAD")
if lead:
labtrans_set = mbo.getMboSet("LABTRANS")
labtrans = labtrans_set.add()
labtrans.setValue("LABORCODE", lead)
labtrans.setValue("STARTDATE", MXServer.getMXServer().getDate())
labtrans.setValue("TRANSTYPE", "WORK")

# When moving to COMP, verify all child work orders are complete
if new_status == "COMP":
child_set = mbo.getMboSet("CHILDWORKORDERS")
if child_set is not None and not child_set.isEmpty():
child = child_set.moveFirst()
incomplete_children = []
while child is not None:
if child.getString("STATUS") not in ("COMP", "CLOSE", "CANCEL"):
incomplete_children.append(child.getString("WONUM"))
child = child_set.moveNext()

if incomplete_children:
# Log a warning but do not block the transition
logger = MXLoggerFactory.getLogger("maximo.workorder")
logger.warning(
"Work order {} completed with incomplete children: {}".format(
mbo.getString("WONUM"),
", ".join(incomplete_children)
)
)

# When moving to CLOSE, update the asset's last maintenance date
if new_status == "CLOSE":
asset = mbo.getMboSet("ASSET")
if asset is not None and not asset.isEmpty():
asset_mbo = asset.moveFirst()
asset_mbo.setValue("LASTMAINTDATE", MXServer.getMXServer().getDate())

# Execute the handler
handle_status_change()

Practical Implications

The work order lifecycle configuration has direct operational consequences:

If your status model is too simple, users will work around it. They will leave work orders in WAPPR indefinitely because there is no REJECTED status. They will create duplicate work orders because there is no way to reopen a closed one. They will use the description field to track information that should be in structured fields.

If your flow control conditions are too strict, users will find ways to bypass them. They will enter dummy data to satisfy required fields. They will change statuses in bulk using database updates. The goal is to enforce business rules without creating unnecessary friction.

If your escalations are too aggressive, you will generate noise. Users will ignore escalation emails because they receive too many. Auto-approval escalations will approve work orders that should have been rejected. The goal is to escalate only when human intervention is genuinely needed.

If your automation scripts are not tested, they will fail in production. A script that works on a single work order may fail when processing 500 work orders simultaneously. Test your scripts with realistic data volumes before deploying to production.

Bottom Line

The work order lifecycle is not a fixed sequence of statuses. It is a configurable state machine that should reflect how your maintenance organization actually operates. Invest the time to design a status model that supports your real-world workflows, configure flow control conditions that enforce business rules without creating friction, and use automation scripts and escalations to handle the edge cases that the built-in configuration cannot address.

A well-designed work order lifecycle reduces data quality issues, improves user adoption, and provides the structured data foundation that predictive maintenance and reliability analysis depend on. The time you spend configuring it correctly pays for itself in reduced administrative overhead and fewer production incidents.

Read more