IBM Maximo Mobile provides controllers that handle the events and business behavior associated with pages, applications, and data sources.
In client-specific implementations, there are often situations where the out-of-the-box (OOB) functionality needs to be enhanced with additional business rules.
Instead of replacing the entire OOB functionality, we can intercept the existing controller method, execute our custom validation, and then allow the original Maximo Mobile logic to continue when the validation succeeds.
This approach provides a useful pattern for implementing custom business logic without unnecessarily duplicating the existing OOB functionality.
For example, a business requirement may state that a technician must complete the Failure Reporting information before a Work Order can be completed.
In this article, we will look at 2 approaches:
Approach 1: Override an existing controller method and execute custom logic before calling the original method.
The custom logic is written in AppCustomizations.js - Override Change status function in woStatusChangeDialog.
The dialogInitialized() function checks whether the dialog being initialized is “woStatusChangeDialog”, and if so it will get the dialog’s controller, save off the changeStatus() function and then set changeStatus to a new function.
The new code calls the original changeStatus() function, but can also do some processing before and after.
/**
* dialogInitialized to validate Failure Code for CM Workorders
* on change status to COMP
* @param {Object} obj
* @param {Dialog} obj.dialog
*/
dialogInitialized(obj) {
if (obj.name === 'woStatusChangeDialog') {
const controller = obj.controllers[0];
if (!controller) return;
const originalChangeStatus = controller.changeStatus.bind(controller);
controller.changeStatus = async (evt) => {
try {
const valid = this.businessLogicBeforeWOComplete(controller);
if (!valid) {
this.app.toast('Please complete failure report before Assignment', 'error');
return;
}
// Continue original logic
return await originalChangeStatus(evt);
}
catch (error) {
this.app.toast({ message: error.message, type: 'error' });
// IMPORTANT: stop further execution
return;
}
};
}
}
/**
* Business Logic Before WOComplete to validate Failure Reporting
* before changing status to COMP
* @param {controller} controller
* @returns {boolean} Returns true if a failure report exists with PCR code
*/
businessLogicBeforeWOComplete(controller) {
const woDetails = controller?.page?.parent?.state?.woItem;
const selectedStatus = controller?.page?.state?.selectedStatus;
// Only validate for COMP WO status
if (selectedStatus !== "COMP") return true;
// Check Work Order work type is corrective or emergency maintenance
if (woDetails.worktype !== "CM" && woDetails.worktype !== "EM") return true;
// check PCR code for the CM WO
if (!this.hasFailureReport(woDetails)) return false;
return true;
}
/**
* Check WO Failure Report
* @returns {boolean} Returns true if a failure report exists with PCR code
*/
hasFailureReport(item) {
const failureReport = item.failurereport || item.failurelist || [];
let hasProblem = false;
let hasCause = false;
let hasRemedy = false;
for (const failure of failureReport) {
if (!hasProblem && failure.type_maxvalue === 'PROBLEM') {
hasProblem = true;
}
if (!hasCause && failure.type_maxvalue === 'CAUSE') {
hasCause = true;
}
if (!hasRemedy && failure.type_maxvalue === 'REMEDY') {
hasRemedy = true;
}
}
if (!failureReport || !Array.isArray(failureReport)) {
return false;
}
return failureReport.length > 0 && hasProblem && hasCause && hasRemedy;
}
Approach 2: Replace a button event handler with a custom method and explicitly invoke the original controller method after validation.
Update the on-click tag value from "completeWorkorder" to "CustomCompleteWorkorder" in the button tag under the Report Work Page in app.xml
<button disabled="{(woDetailsReportWork.item.flowcontrolled && page.state.taskInComplete)
|| !app.checkSigOption('${app.state.woOSName}.COMPWOBUTTON')}"
hidden="{woDetailsReportWork.item.status_maxvalue === 'COMP'||
woDetailsReportWork.item.status_maxvalue === 'CAN' ||
woDetailsReportWork.item.status_maxvalue === 'CLOSE'}"
icon="carbon:checkmark--outline" id="p6aav" kind="primary" label="Complete work"
loading="{page.state.loadingcomp === true}" on-click="CustomCompleteWorkorder"
on-click-arg="{{'item':woDetailsReportWork.item,'datasource':woDetailsReportWork,
'status':app.state.systemProp['maximo.mobile.completestatus']}}" padding="false"
slot="buttons"/>Create a new custom method CustomCompleteWorkorder in AppCustomizations.js
async CustomCompleteWorkorder (evt) {
const woDetailDs = this.app.findDatasource("woDetailds");
const woItem = woDetailDs.item ;
if (woItem.worktype === "CM" && woItem.worktype === "EM") {
if (!this.checkFailureReport(woItem)) {
this.app.toast('Please fill failure report before completing WO', 'error');
return;
}
}
// Call report page oob method after validation
let page = this.app?.currentPage;
let controller = page?.controllers?.find( c => c.completeWorkorder );
controller?.completeWorkorder(evt);
}References:
ibm-maximo-mobile-replace-existing-method
ibm-maximo-mobile-replace-existing-method