Tuesday 4 September 2018

Random Examples of Maximo Automation Scripts

So far I have blogged about various capabilities offered by automation scripts in Maximo 7.6, needless to say I love working with Automation Scripts. I would like to share some random examples and usage of automation scripts in this blog. Please put your comments or suggestions.

Calling a Stored Procedure from Automation Script

I have a stored procedure in the database created as below:







This procedure needs to be executed on a scheduled basis. I can create a cron task or an escalation which will trigger the action. And, this action I can create as an automation script with Action launch point. The code snippet in this automation script will be as per the image below:

Throwing an exception in a Message Box using Automation Script

I have created a custom message in Database Configurations application which needs to be displayed to the user when the user selects a date less than the current system date while selecting required date in Create Requisition application. 

I will create an automation script of Attribute Launch point with validate event on MR.REQUIREDDATE attribute as per the images below:


















Taking action from Yes/No button in Message Box using Automation Script

Let us consider we have to throw a warning message with Yes or No button, and the user can select either of them. Based on the choice of the user, we need to take separate actions. The warning message is created in the Database Configurations application as below:

My requirement is when I select the Issue Unit for an item record in Item Master application, if an order unit is available and issue unit and order unit are not same, user needs to be thrown warning message with a choice if he/she wants to proceed. In case the user selects yes, nothing needs to be done but if the user selects no, the value needs to be cleared from the Issue Unit field. I will create an automation script with Attribute Launch point on ITEM.ISSUEUNIT attribute and event Run Action, as per the images below:



















Automation Script for Conditions

We can write automation scripts for custom conditions also which can then be used in workflows, or for achieving conditional UI, or in condition monitoring, etc. This type of automation script will be evaluated to either True or False and the boolean result is returned by the script using an implicit variable "evalresult".

Let us assume while approving a PO record, if the logged in user's PO approval limit is less than the total cost of the PO record, he should not be allowed to approve it. The automation script is created and source code is written as per below images.




























Once the script is written, we need to define the condition expression to refer this script. In Conditional Expression Manager application, create a new condition of type=CLASS and in the expression field, enter the notation as <script-name>:<launchpoint-name> and in the class field, enter the class reference as "com.ibm.tivoli.maximo.script.ScriptCustomCondition". See the image below.


Now, this condition 'CHECKLIMIT' is ready for use in the PO approval workflow process or in conditional UI to restrict the user in approving the PO record.

References:

Wednesday 22 August 2018

Intricacies of Maximo ConfigDB

Few years ago, I had written a blog on errors encountered while applying the configuration changes to one or many database objects in Maximo. One of my acquaintances had asked me to write a blog on the intricacies of configdb. Let us first understand why do we need to configure the database.

When we make some change to an object, say adding a new attribute or changing the length of an attribute, creating or modifying indexes, etc. or,  may be we are adding a new object altogether in Database Configurations application, and when we click on the Save button, the changes are stored in temporary database configuration objects (secondary tables) and these changes do not take effect until you apply the configuration changes. It is important to back up your data before configuring the database. However, if we want to add a new relationship to an object or we want to modify a few relationships, once we save the record in Database Configurations application, they can be used and we do not need to apply the configuration changes. A relationship is a link between two MBOs, which is created by specifying a SQL Join statement.

There are three ways to configure the database: command-line mode, a full live configuration, or a partial live configuration with administration mode turned on. If you want to use the command-line mode, you must shut down the application server. It is easier to restore data from this configuration mode as there are no updates while the database is being configured. While restarting the application server, you need to ensure that you do not encounter internal 500 error. I had also written a blog on internal 500 error. You can refer to that if you like.

Full live configuration has least impact on users as active transactions are not interrupted or lost as administration mode need not be turned on in this case and this can be used only for non-structural changes to Maximo objects. Partial live configuration requires administration mode to be turned on which blocks users from the system applications, disables event listeners, suspends cron tasks, and does not allow remote connectivity. We should know when to use what configuration mode. For this, we need to understand the difference between a structural and a non-structural change. Before that let us also find out what are MBOs and its attributes.

Maximo Business Objects and Attributes

A business object is an object that  has attributes and values, operations, and relationship to other business objects. The business object contains the business data and models the business behavior around it. The Maximo Business Object (MBO) defines a set of fields and business rules and updates one or more Maximo database tables. These can be of two types - Mbo and MboSet. MboSet is a collection of Mbo objects, which has methods to manipulate, iterate and query through the data. This can be considered as a database table. Mbo represents a record in a table which implies that each MBO represents a single database record from a single database table.

Information about a business object, which is referred to as metadata, is stored in the database in database tables. The metadata that is associated with the business objects is used to manage the database objects. This metadata for a business object may include the following:
  1. Definition of the Business Object - Name of the object, database entity, whether the object is persistent or non-persistent, the underlying java class
  2. Attributes  - Name, data type, length or size, field validation class
  3. Associated Relationships - associations between tables that are created using join statements to retrieve data.
The Attributes of business objects contain the data that is associated with a business object. When you create an object, you must specify the attributes that are assigned to the object. These attributes can either be persistent or non-persistent. A persistent attribute represents a database table column or a database view column. A non-persistent attribute exists in memory only, because the data that is associated with the attribute is not stored in the database. The additional metadata that is associated with business object attributes, can include a domain, a custom class, a default value, and to specify whether the attribute is required, etc.

Structural Vs Non-Structural Database Change

The changes made in the Database Configurations application has the ability to change not only the data schema but also the data dictionary tables which store information about the tables, fields, and views used by Maximo. You can check the list of data dictionary tables here.

There is also a set of shadow data dictionary tables which are known as the CFG tables, which store the necessary changes made in the Database Configurations application until you are ready to apply those changes to the database. So, the changes which are made in the Database Configuration application are actually written into the CFG tables and after the DBConfig process is successful, the changes are written into the data dictionary tables which may alter the schema of the database or reconfigure particular attributes. 

A non-structural change to Maximo object does not disrupt the live business object definition. For example, if we change the field validation class for an attribute or we add a domain to an attribute and perform a live update to apply the changes, the business objects that are already instantiated are not re-validated. Modifications to indexes do not use the CFG tables but use two other Maximo objects, MAXSYSINDEXES and MAXSYSKEYS. These changes are also considered as non-structural and hence, do not required admin mode to be turned on before configuring the database.

A change which may alter the data schema, like the ALTER, CREATE, DROP statements in SQL, is termed as as Structural change, like, creating or deleting a Maximo object, changing the data type or length of an attribute, etc. A structural change may alter the transaction table. For certain structural changes, Maximo will automatically rename the original table with an XX prefix during the configuration process and these tables will serve as backed up data. This would be for major modifications, like data type changes which cannot be made on a table with data in it. The configuration process reconstructs the table schema and restores the data from the backup. These backup tables will be retained so as to be used in case you need to do a roll back of the configuration process, and they can be deleted periodically by an administrator. Turning admin mode on allows the structural changes to be applied to the database without stopping the application server.

Changes to the structure should only be done through the Database Configuration application and not directly through the database. This will ensure that all Maximo rules are observed. After doing the changes in the database configuration, the system will then take care to do the changes to the underlying database, if any are needed.

Using Database Configuration Application - WHY?

An object is a self-contained software entity that consists of both data and functions to manipulate data. User-defined objects are always created in the Database Configuration application. All changes should be performed from here, as this will ensure the integrity and upgrade-ability of your configuration. 

When adding a new MBO, there are several settings which one should configure. Just to mention a few, you can set a “Custom class” which will tell Maximo which Java class has the logic to be used with this MBO. You can also set the MBO to be a View or enable Auditing for this MBO. So, it is not as simple as creating a new table in the database using CREATE TABLE statement.

When we are creating a new object in Maximo database, it is not as simple as creating a new table in the database using CREATE TABLE statement in the native database. The changes should be saved in the Data Dictionary tables else we cannot use it from Maximo instance. The object details will be saved in MAXOBJECT table which may be based on MAXTABLE or MAXVIEW. Details of the attributes of this object will be saved into MAXATTRIBUTE table, details of indexes will be saved in MAXSYSINDEXES and MAXSYSKEYS tables, and details of relationships will be saved in MAXRELATIONSHIP table, details of the columns for the view will be saved in MAXVIEWCOLUMN, and MAXSEQUENCE table will store all the sequences used in the system.

When we create the new object in Database Configurations application and save the record, details are saved in the shadow tables, MAXOBJECTCFG, MAXATTRIBUTECFG, MAXTABLECFG, MAXVIEWCFG, etc. During the partial live configuration process, the system runs the CREATE TABLE statement in the native database and also inserts the changes into the data dictionary tables as mentioned above. Once the configuration process is successful we will be able to access this object in the Maximo instance.

We can create a native view directly in Maximo database using CREATE VIEW statement, then we can come into Database Configurations application and click on New Object icon, provide the same  name of the view created above in the Object field, "Imported?"  and "View?" checkboxes will get automatically checked, and "View Select", "View From", and "View Where" fields will be populated with the appropriate portions of the SQL statement.  When you save these changes in the Database Confugurations, the details are written to MAXOBJECTCFG, MAXATTRIBUTECFG, MAXVIEWCFG tables and after the configuration changes are applied with admin mode turned on, these changes are written into MAXOBJECT, MAXVIEW, MAXATTRIBUTE, etc. tables and you can access the view in Maximo UI. You can refer the youtube video for the same.

References:


Tuesday 7 August 2018

Leveraging Automation Scripts for Inbound and Outbound processing of messages

We have used java classes to extend the main java processing classes to customize the processing of integration messages for inbound and outbound transactions. Maximo 7.6 has given us the capability to leverage automation scripts to apply our custom logic to integration components. We can create automation script and associate it to an object structure, enterprise service, publish channel, etc. To create an automation script for integration, in the Automation Scripts application you need to select the action Create > Automation Script for Integration
Next, you will have to select the integration component on which the automation script will run to apply your custom logic. Before that we need to understand what are the different customization points for inbound and outbound transactions that are available with automation scripts.
  1. The automation script for outbound object structure allows an outbound definition to be created which will have the custom processing code to be used during serialization of business object data into an XML message. The automation script for inbound object structure allows an inbound processing of the incoming XML message before it is mapped to the business data. The automation script name will be created by the system as OSIN.<object-structure name> for inbound processing or as OSOUT.<object-structure name> for outbound processing. 
  2. Object structure processing creates the integration message which is then forwarded to the publish channel for outbound transaction. Custom logic can be written in an Automation scripts to process the publish channel further, through either External Exit, user exit before external exit, user exit after external exit or event filter processing. If the publish channel selected for the automation script is MXINVENTORYINTERFACE, then the script name will be as below:
    • PUBLISH.MXINVENTORYINTERFACE.EXTEXIT.OUT (External Exit)
    • PUBLISH.MXINVENTORYINTERFACE.USEREXIT.OUT.BEFORE (User Exit before external exit)
    • PUBLISH.MXINVENTORYINTERFACE.USEREXIT.OUT.AFTER (User Exit after external exit)

    • After successful creation of the automation script for the publish channel, in the Publish Channels application, you can see that predefined class references get auto-populated in Processing class, User Exit Class or Event Filter Class fields. The processing class field will have the value as "com.ibm.tivoli.maximo.script.ScriptExternalExit" if we have used external exit with the automation script or the user exit class field will have the value as "com.ibm.tivoli.maximo.script.ScriptUserExit" if we have used user exit class.

    • For outbound integration messages, Maximo will start an integration transaction. The object structure provides an internal record data (irData) element to a publish channel, which is then processed through a custom logic and an external record data (erData) element is constructed before the message is forwarded to its destination. We have created an automation script (PUBLISH.ES_MXITEMINTERFACE.EXTEXIT.OUT) with a publish channel that is created on MXITEM object structure. In this object structure, we have included a non-persistent attribute "ITEMNAME_NP" which should be combination of item number and description which needs to be sent in outbound transaction. The source code is as below:
  3. Enterprise service provides asynchronous and synchronous processing of inbound integration messages. During asynchronous processing, external service opens a connection and sends a  enterprise service request and does not require a response. However, during synchronous processing, external service opens the connection to send the enterprise service request and will maintain the connection till a response is received. Automation scripts provide the following customization points during the processing of inbound or outbound integration messages to be used with enterprise services:
    • Inbound Request - User Exit before external exit - SYNC.<enterprise-service name>.USEREXIT.IN.BEFORE
    • Inbound Request - User exit after external exit - SYNC.<enterprise-service name>.USEREXIT.IN.AFTER
    • Inbound Request - External Exit - SYNC.<enterprise-service name>.EXTEXIT.IN
    • Outbound Response - User Exit before external exit - SYNC.<enterprise-service name>.USEREXIT.OUT.BEFORE
    • Outbound Response - User exit after external exit - SYNC.<enterprise-service name>.USEREXIT.OUT.AFTER
    • Outbound Response - External Exit - SYNC.<enterprise-service name>.EXTEXIT.OUT

    • After successful creation of the automation script for enterprise service, you can see in the Enterprise Service application, for this enterprise service record predefined class references get populated as "com.ibm.tivoli.maximo.script.ScriptExternalExit" in the processing class field or as "com.ibm.tivoli.maximo.script.ScriptUserExit" in the user exit class field.

    • For inbound integration messages, external system starts the integration transaction and the incoming integration message provides an erData element to an enterprise service. Through a custom code, this element is processed to construct an irData element before the message is forwarded to the associated object structure. Let us assume that we are using out of the box enterprise service, 'MXPOInterface' to processes inbound messages to MXPO object structure. If for any incoming PO record, buyer (PURCHASEAGENT) is null, we need to use the value of the person who has initiated the PO record in this field before saving it to PO object. Automation script is created as per the image below:
After the above automation script is created, you can see in the related enterprise service record, processing class field is auto-populated with the predefined class reference. See the below image:

In case you want to delete the above script, please remember to remove the class reference explicitly from this field in the Enterprise Services Application.

References:

  1. Creating automation scripts for integration
  2. Automation Scripts with Object Structures
  3. Automation Scripts with Publish Channel
  4. Automation Scripts with Enterprise Service
  5. Examples from IBM Knowledge Center

Thursday 26 July 2018

Dynamic values in Lookups - Automation Script Example

Let us consider field level validation of maximo business object attributes. When we are talking about field level validation class, we will directly jump to extend the MboValueAdapter class. Say, in service request records we have to set the value of Phone field of reported by, if it is null, with the value of Primary SMS field in the person record. We will write a java class in a custom package, custom.module.mbo.NewCustomFldClass, in its action method we will write the business logic. After building the ear file and deploying it, we will enter the class path in SR.REPORTEDBY attribute in Database Configurations application and then apply the configuration changes. Let us check the Java source code in the image below:


Whenever a value will be entered in the SR.REPORTEDBY field and tabbed out, above class file will do its action. This can be achieved alternatively by creating an automation script with Attribute launch point with Run Action event on SR.REPORTEDBY attribute, with a simple source code as below:


Now, what if we need some validation and action along with a lookup. We will write the new java custom class which will extend psdi.mbo.MaxTableDomain. We can use the init(), validate() and action() methods as per our requirement and in addition to these, we have one more action getList() for our use. In this custom class we can set the relationship to the object from which we want the values to be fetched and a list criteria with the where clause to filter data from that object. Inside the getList() method we can set additional where clause to filter data.

Conditional lookups for a field can also be achieved in Application Designer, for which I have explained with an example in another blog

Let us consider that when user clicks New Row in Materials sub-tab of Plans tab in Work Order Tracking application, Item field lookup should display all items available if it is a direct issue, else the lookup should display a set of values of items for which Inventory records exist in the default storeroom of the reported by user. To achieve this, following table domain is created as the first step:

Next, we want to create an automation script with Attribute Launch point and event Retrieve List. This is done as per below images:


The source code of this automation script is written as per below image:


References:

Monday 23 July 2018

Fetching Mbo Sets using RelationShip or MXServer - Automation script Examples


I would like to draw your attention towards one important thing which we keep using in our java codes or Jython scripts but we do not use them properly. This is about getMboSet() method. As we are aware there are two ways of fetching an Mbo set, either by using a relationship or MXServer. Improper use of this may lead to performance issues, poor memory management, etc.

For example, I am working with save event of Object launch point on WORKODER object. I need to set a value in all related tasks which are in approved status. There is a relationship between WORKORDER object and WOACTIVITY object which can give me the set of all related tasks of the workorder which are in approved status. It will be easier for me to use this relationship to fetch the WOACTIVITY records. Please keep in mind that when I am accessing the Mbo records using a relationship, it is included in the same transaction as the parent Mbo Set and if I call a save on the parent Mbo Set, all MboSets in the current transaction will be saved. So, the Mbo sets fetched using relationship do not require save to be called explicitly because their save is called when their parent is saved.

In the above code snippet, I can also use a setWhere clause to specifically select some of the records, this new where clause will be appended with the existing where clause of the relationship and you will have to call a reset() method to execute and update the resultset obtained using the relationship. 


Above script will save the WORKORDER records and the related WOACTIVITY records in the current transaction.

Let us consider that the relationship from WORKORDER object to WOACTIVITY does not exist which may satisfy the search criteria we are looking for. In this case, we can create one on the fly as below: 




The parameter “$WOTASK” is a temporary relationship name, “WOACTIVITY” is the child object, and “parent=:wonum and siteid=:siteid and istask=1 and status=’APPR’ and targcompdate is not null” is the relationship where clause. The values of :wonum and :siteid will be taken from the current Mbo record from WORKORDER object.

While fetching MboSets from MXServer, we have to be careful about a few things.
  1. Always use setWhere() and reset() methods with this MboSet. The setWhere() method will reduce the number of Mbo records being fetched and reset() method will ensure fetching of data with the where clause.
  2. If the Mbo set is being fetched only for traversing and not for any addition or update, it is a best practice to set the DISCARDABLE flag as true. If the Mbo set is being fetched for read-only purpose it is a good practice to set the NOSAVE flag as true. These steps will shorten the looping time of the transaction.
  3. If any setValue method is used for some Mbo record of the MboSet, or any add or update is being done on the Mbo set, it is required to call the save() method on the set. Mbo sets fetched from MXServer needs to be saved before the set is closed otherwise the changes will be lost.
  4. Always use clear() and close() methods on the Mbo set fetched using MXServer if it is not required anymore. This will release memory and the database resources

Let us consider one example. Every Saturday, we need to run an escalation to update the actual cost of all issue transactions of active inventory records of all capitalized items that have happened between last Monday and Friday. We have written an escalation to run every Saturday on Inventory Object which calls an Action. Keeping in mind all the above rules, this action logic is written in an automation script with Action launch point, below is the sample source code of the script.


Thursday 5 July 2018

Using Maximo Constants in SetValue methods of Automation Scripts - What, Where, Why

I am blogging again on automation scripts to share my learning with the readers and the contents used in this blog are examples only. Hope this blog helps someone and suggestions/comments are always welcome.  In Maximo 7.6, we have different launch points Object, Attribute and Action to associate to the automation scripts. We already know when to use what. Still, I want to emphasize a few points. 

We have seen in object level java classes order of execution of the methods. The initValue() method is the first method executed after the constructor and is used to initialize attributes on new records and to set default values. The init() method is called after initValue() to set the related attributes as read-only and save() method is executed at the end. Now, coming back to automation scripts, for object launch points we have the events as shown in the image below:

I have a requirement to set the Internal checkbox on PO record creation if the logged in user belongs to some security group X and user should not be able to edit this value. I can use an object launch point on object PO with Object Event Condition as ":&USERNAME& in (select userid from groupuser where groupname='X')" and event as "Initialize Value" and in the script source code I can simply use the below lines:



Let us consider another example where we want to populate the values of PO.SHIPTO and PO.SHIPTOATTN fields based on the PO.PURCHASEAGENT and its related person record. We can use an automation script with object launch point on object PO and event would be Save. On add or update of a PO record, this will be triggered on save. Please see the below images for this example.

Please note that PURCHASEAGENTPSNREC is a relationship name from parent PO object to child PERSON object with where clause "personid=:purchaseagent". Also, please note that while setting the values I have not used any Mbo Constant. I will come back to this later.

Let us now consider field level java classes. The field validation or action gets invoked when tabbing out of a field, or when a field is being set from the back end. The typical order of execution of methods in a field level class is: initValue(), init(), validate(), action(), hasList(), getList(). The initValue() method is used for initializing fields for new records, init() method sets read-only fields, validate() method can be used to verify whether the new value for the attribute is valid, and action() method can be customized to contain the business logic or update any other object or attribute. Similar thing we can keep in mind while using Attribute launch points. Please see the below image.
We can use Initialize Value event for an Attribute launch point to achieve same result as we use initValue() method in a field level java class, Initialize Access Restriction event can be used on the same lines as init() method, Validate event for validate() method, Run action event for action() method, and Retrieve List event will work in similar lines as getList() method. It is easy to correlate the order of execution of these events with the methods of field level java customization. For example, when we add a new line record in PO Lines tab and select an item, we need to make fields X and Y read only, copy a few fields from related item master record if it is a KIT item. We have to do all this when we enter or select the value in ITEMNUM field. We wrote the logic to make fields X and Y read-only in an automation script with Attribute launch point on POLINE.ITEMNUM attribute using event Run Action and used another automation script to copy the values from related item master record to POLINE fields with Attribute launch point on POLINE.ITEMNUM attribute using Validate event. 

Let me come back to MboConstants and draw your attention towards an error we got while we were changing the capitalized status of an item in Item Master application. We got an error as Inventory Object is read-only. When one item is changed to capitalized status, it tries to update all  the related inventory records and save on INVENTORY object is called which in turn calls save method on child objects, INVBALANCES, INVCOST, etc. We have configured some access restriction in the fields of INVENTORY object and one automation script was running to set a few fields of INVENTORY record. This automation script was written on Object launch point with Save event. To resolve this we had to use MboConstants.NOACCESSCHECK in the setValue method used in that script. This was to make sure that those fields can be overwritten without having to rely on whether the fields are accessible on Mbo level.

Similar to the above example, we had not used any Mbo Constant in the setValue methods in our object launch point script with Save event. In this case, however, it is not going to loop through an array of records. It is setting the values of the same PO record on which purchaseagent field is not null. So, even if we do not use MboConstants.NOACCESSCHECK with the setValue method it is not going to throw any error in Purchase Order application. It is recommended to use with the setValue method so as to ensure that the PO record is accessible at any point of time when save on PO object is called from another application or external event. So, the modified script should be as below:
And, it is also a good practice to close a MboSet if it is not to be used anymore.

You can refer the following sites if you want to know about what Maximo constants we need to use while setting values of attributes.
Using field flags to set attribute content
Flags for setValue methods
Mbo Constants in Maximo

Friday 1 June 2018

Maintenance of Metered Assets - PM Counters and Job Plan Sequences


We are aware that we use job plan sequences in Preventive Maintenance to rotate through a series of job plans. For example, you can assign monthly, quarterly, and yearly job plans for work on an asset. The job plan is selected by dividing the PM Counter by the Sequence number. The largest, divisible sequence number will be selected.

This is easier to understand if we take an example of a time-based PM record. Say, you have separate set of tasks for monthly maintenance and semi-annual maintenance. You create two job plans MnthJP and 6MnthJP and you associate these two job plans to a PM record with first job plan with sequence# 1 and second job plan with sequence# 6. Initial PM counter value is 0, so if the frequency is 1 Month, the first work order will be generated with job plan MnthJP and PM counter will be incremented to 1. For the second month also, work order will be generated with job plan MnthJP. Dividing the PM counter value 2 by job plan sequence# 1 results in a whole number, so job plan MnthJP was selected.  Now, if I set the PM counter to 5, and then select the Generate Work Order action for this PM, system will create a work order with job plan 6MnthJP and PM counter will be incremented to 6 (PM counter 6 / Job Plan sequence# 6 = 1, a whole number).

Let us take an example of a metered asset, say, we need to run maintenance schedule for a car servicing every 500 KMs, wheel rotation and oil change with normal car servicing every 1000 KMs, wheels and oil change, wheel alignment with normal car servicing every 4500 KMs and every 10000KMs, the car needs Body painting, Wheel Change and Alignment along with normal car servicing. Let’s also, assume this car runs 50 KMs per day. There are job plan JP500, JP1000, JP4500 and JP10000 with separate tasks. Now the question is how to set the sequences of these job plans so that when work order is generated, it selects the correct job plan.

We have associated a continuous meter with our asset:


Let us create the Preventive Maintenance record associating this Asset. In the Frequency tab, we will use a meter based frequency as below:

Now let us see how we can achieve the job plan sequencing to apply the job plans to work orders.
If we use the action to View the Sequence, we will understand more.
We can go to the asset and record the meter readings. For the first time, we will put meter reading as 500. And, let’s generate the Work Order from the PM record.
Work order 1041 gets created for the first 500 KMs with job plan JP500 as below. 500 meter reading divided by frequency 500, will result in 1. This value is divisible by only job plan sequence# 1.
At this point, we can see that the PM Counter of the PM record has increased to 1 and if we generate the Work Order from the PM record (with Use Frequency Criteria unchecked), this time the work order will be generated with job plan JP1000 because after last meter reading of 500KMs with frequency 500, next meter reading should be 1000KMs, and 1000 divided by 500 (frequency) will result in 2 which is divisible by largest job plan sequence# 2.
Now, if we set the PM Counter to 8, you can see that in the PM record, the job plan value has changed to JP4500.  Let us generate the work order again with “Use Frequency Criteria?” unchecked. This time work order will be generated with job plan JP4500 for 4500KMs. The meter reading 4500, if divided by frequency, 500, will result in number 9 which is easily divisible by largest job plan sequence#9.













After generation of the work order from above step, PM Counter will be 10 and job plan in the PM record will be changed to JP1000, as 5000KMs meter reading if divided by frequency, 500, will result in 10, which is easily divisible by largest job plan sequence# 2.

Similarly, if we set the PM counter value to 19 and generate the work order, with unchecking the “Use Frequency Criteria?” the system will generate a work order with job plan JP10000. 10000KMs meter reading divided by frequency 500, will result in 20 and this value is easily divisible by largest job plan sequence# 20.

References: