by | Oct 12, 2023

    Episode 3: Changing Status in Maximo Mobile

    Introduction

    Welcome to Episode 3 of "Everything You Need to Know About Maximo Mobile". In this episode, we delve into the intricacies of Maximo Mobile customizations, focusing on the use of JavaScript and validations when altering the status of a work order.

     

     

    JavaScript Customisations - Changing Status

    Changing the status of a work order is a common task, and there are several customizations that can enhance this process. Here are some that might resonate with many client scenarios:

    Conditionally Filtering the Status List

    A previous blog post discussed the use of the onAfterLoadData method to filter the status list that appears when initiating the change status dialogue. However, there are instances where clients may want to present technicians with only the subsequent available status, thereby streamlining their choices.

    To address this, I've crafted a function named _filterWOStatusList. This function is designed to conditionally display only the upcoming status, effectively filtering the dataset:

    _filterWOStatusList(dialog) {
       let parentView = dialog.parent;
       // current WO status
       let woStatus = parentView.state.woItem.status;
       let statusList = [];
       switch (woStatus) {  
             case 'APPR':    
                  statusList = ['INPRG'];    
                  break;  
             case 'INPRG':    
                  statusList = ['ONHOLD', 'RESTORED'];    
                  break;  
             case 'ONHOLD':    
                  statusList = ['INPRG'];    
                  break;  
             case 'RESTORED':    
                  statusList = ['COMP']; // no more actions needed from Maximo Mobile    
                  break;  
              default:    
                   statusList = [];    
                   break;
        }
        var statusDS = parentView.findDatasource('dsstatusDomainList');
        if (statusDS && statusDS.dataAdapter.items.length > 0 && statusList.length > 0) {  
            let filteredStatus = statusDS.dataAdapter.items.filter((item) => {    
                return statusList.includes(item.value);  
            });  
            log.d(TAG + ' Filtered Status -->', JSON.stringify(filteredStatus));  
            statusDS.load({ src: filteredStatus, noCache: true });
        }
    }

    While I've employed a switch/case structure for this function, an if/else approach would work just as well. To integrate this function into the dialogue's lifecycle, follow these steps:

    Step 1: Invoke the function upon opening the dialogue.

    dialogOpened({ dialog }) {
        if (dialog.name == 'woStatusChangeDialog') {  
           this._filterWOStatusList(dialog);
        }
    }


    Step 2: Initialise the function during the dialogue setup. It's worth noting that the dialogue won't utilise the dialogOpened function during its inaugural load. To circumvent this, we introduce the filter during the dialogue's creation phase.

    dialogInitialized(dialog) {
       if (dialog.name == 'woStatusChangeDialog') {  
          // Filtering the data for the fist change status dialog loading  
          this._filterWOStatusList(dialog);
        }
    }

     

    Validating the Work Order Prior to Status Change

    While it's entirely acceptable to employ a series of automation scripts to validate a Work Order before modifying its status, the experience isn't consistent across platforms. On the Role Base Application, upon selecting and confirming a new status, users receive feedback identical to what they'd get on the Maximo UI. However, the mobile experience is a different story.

    On mobile devices, all transactions (changes made to one or more records) are queued for background synchronisation. This is where I encountered challenges. When online, validation messages don't pop up as they do in the Role Base Application. Instead, they manifest as transaction errors in the error queue. This discrepancy led to complications for me, especially when I made other record changes before the status update. This left my record in an uncorrectable state, prompting me to shift validation to the mobile platform—a move that proved advantageous, especially in offline mode.

    For guidance, I referred to this blog post and tailored it to my requirements. While the foundational approach remained unchanged, I needed work order details for validation. Here, I'll demonstrate how to obtain these details, assuming a mandatory status change for the Work Order.

    It's essential to recognise that Maximo Mobile operates with an event handler. For a deeper dive into this, please refer to Episode 2: Maximo Mobile Event Emitter.

    Building on the aforementioned blog's concept, I opted to override the changeStatus function, incorporating validation before invoking the out-of-the-box function. I retained the status filter function for concurrent use with validation.

    dialogInitialized(dialog) {
        if (dialog.name == 'woStatusChangeDialog') {  
           // Filtering the data for the fist change status dialog loading  
           this._filterWOStatusList(dialog);      

           // start everriding the changeStatus function  
           let controller = dialog.controllers[0];  
          // Save the OOTB Change status function  
          let coreChangeStatus = controller.changeStatus.bind(controller);  

          controller.changeStatus = (evt) => {    
                // Custom validation on before changing status      
                  coreChangeStatus();  
           };
        }
    }

     

    Next, I signaled the graphite framework of an impending action, allowing another function to intercept it. 

    dialogInitialized(dialog) {  
            if (dialog.name == 'woStatusChangeDialog') {    
              // Filtering the data for the fist change status dialog loading
              this._filterWOStatusList(dialog);          

              // start everriding the changeStatus function    
              let controller = dialog.controllers[0];    
             // Save the OOTB Change status function    
             let coreChangeStatus = controller.changeStatus.bind(controller);     

             controller.changeStatus = (evt) => {      
                   // Custom validation on before changing status      
                   log.t(TAG + '[%s] - before-change-status fired', dialog.name);      
                   this.app.emit('before-change-status', {        
                       newStatus: dialog.state.selectedStatus,        
                       app: this.app,        
                       page: this.page,        
                       dialog      
                    });      
                    log.t(TAG + '[%s] - Can change status: %b', dialog.name,
    dialog.state.canChangeStatus);       

                    coreChangeStatus();    
                 };  
           }
     }

     

    The this.app.emit method accepts a string (in this case, "before-change-status") and an object. This object, passed as a parameter to my "handler" function, contains details like the selected status from the dialogue, application scope, page scope, and the dialogue itself.

    My handler function, named onBeforeChangeStatus, allows for object destructuring in its parameters, streamlining the code and enhancing readability. Thus, we avoid doing something like paramName.newStatus or let newStatus = paramName.newStatus to keep the code clean.

    onBeforeChangeStatus({ newStatus, app, page, dialog }) {
    }

    Conditional checks determine if I'm on the Schedule or Work Order Details pages to retrieve the work order specifics.

    onBeforeChangeStatus({ newStatus, app, page, dialog }) {   
               let workorder = page.name === 'schedule' ? page.state.woItem :
    page.getMainDatasource().currentItem;
    }

    Subsequently, I embarked on constructing the validation. Given that my validations vary based on the chosen new status, I established two variables to determine the feasibility of the status change.

    onBeforeChangeStatus({ newStatus, app, page, dialog }) {  
               let workorder = page.name === 'schedule' ? page.state.woItem :
    page.getMainDatasource().currentItem;  
               let valid = true;  
               let message = '';  
               if (newStatus === 'INPRG') {    
                  valid = !!workorder.schedstart;    
                  message = 'BMXAA4195E - A value is required for the Scheduled Start field on the WORKORDER object.';  
                }    

                if (!valid) {    
                   app.error(message);    
                   dialog.state.canChangeStatus = false;  
                }
         }

    And here is the icing on the cake. After showing the error message on line 11 above, I update my dialogue's state for potential future use. Since the dialogInitialized method is invoked once, I incorporated a dynamic condition to assess the status change viability.

    This state now integrates seamlessly into my override function.

    dialogInitialized(dialog) {  
            if (dialog.name == 'woStatusChangeDialog') {    
               // Filtering the data for the fist change status dialog loading    
               this._filterWOStatusList(dialog);          

              // start everriding the changeStatus function    
              let controller = dialog.controllers[0];    
             // Save the OOTB Change status function    
             let coreChangeStatus = controller.changeStatus.bind(controller);     

             controller.changeStatus = (evt) => {      
                   // Custom validation on before changing status      
                   log.t(TAG + '[%s] - before-change-status fired', dialog.name);      
                   this.app.emit('before-change-status', {        
                       newStatus: dialog.state.selectedStatus,        
                       app: this.app,        
                       page: this.page,        
                       dialog      
                    });      
                    log.t(TAG + '[%s] - Can change status: %b', dialog.name,
    dialog.state.canChangeStatus);              

                    // dynamically test if I can change the status      
                    if (dialog.state.canChangeStatus) {        
                      coreChangeStatus();      
                    } else {        
                      dialog.state.canChangeStatus = true;        
                      dialog.closeDialog();      
                    }    
               };  
          }
    }

    To wrap things up, it's crucial to bind our novel onBeforeChangeStatus function, ensuring its accessibility by the app.

    applicationInitialized(app) {
          this.app = app;
          this.app.on('before-change-status', this.onBeforeChangeStatus);
    }

     

    In conclusion, the intricacies of Maximo Mobile customisation offer developers a rich tapestry of tools to refine and enhance the user experience, particularly when it comes to work order status changes. By harnessing the power of event handlers, conditional filtering, and validation mechanisms, developers can seamlessly align the mobile platform with specific organisational workflows and requirements. This level of adaptability not only ensures that Maximo Mobile remains a robust and responsive tool but also underscores its potential to be a tailored solution, primed to address the nuanced challenges of the modern mobile landscape and guarantee optimal user satisfaction.

    If you'd like to learn more about anything from this blog, CLICK HERE to get in touch with us - we'd love to hear from you! This blog is part of a series aimed at enabling you to customise your Maximo Mobile application to your specific needs. If you're interested in delving deeper into this topic, don't hesitate to subscribe to our newsletter. We're here to help you on your journey towards mastering Maximo Mobile customisation!

     

    Link to Episode 1:
    Episode 1: Maximo Mobile Customisation

    Link to Episode 2:
    Episode 2: Maximo Mobile Event Emitter

     

     

     

    Sign up to our free newsletter to explore emerging technologies, industry events and Maximo best practice.