Wednesday, November 10, 2021

Repoint References from Original to New Cloned Application

In Maximo projects, we always need to have a custom application that used to be a minimal version of original base application. 

If it is developed at the beginning of the Implementation, then it will be straight forward method for providing access, referring it in Start center, creating reports etc., In case, it was requested after the Original application is used for sometime, then we need to repoint the references from Original to newly cloned application. 

For example, if we clone an Original Application (like WOTRACK) to New Application (C_WOTRACK), there will be a few references like below are need to be updated. 

  •  The User created queries need to be copied to new application

insert into query (app,clausename,owner,description,clause, ispublic,queryid, langcode,intobjectname, priority, isuserlist, notes)  (select  'WOTRACK' as app , clausename, owner , description, clause, ispublic, queryseq.nextval as queryid, langcode, null as intobjectname, null  as priority,  isuserlist, null as notes from maximo.query  where app = 'C_WOTRACK' ) ;

  • Reports need to be migrated to New application
  • The Start center references need to be updated to new application

update layout set queryapp = 'C_WOTRACK' where queryapp = 'WOTRACK' ;

-- layout will repoint the link in the query result set

update faconfig set app = 'C_WOTRACK' where app = 'WOTRACK' ;

-- it will update the favorite application in the layout

update ACTIONSCFG set app = 'YHNKWOTRACK' where app = 'WOTRACK' ;

-- it will update the quick insert links in start center layout

  • Delete the authorization of original application for Users and copy the same access to new application in Security Group

insert into applicationauth (groupname, app, optionname, applicationauthid , conditionnum ) (select groupname , 'C_WOTRACK' as app, optionname, APPLICATIONAUTHSEQ.nextval as applicationauthid, conditionnum  from  maximo.applicationauth where app = 'WOTRACK' and groupname not in  ('MAXADMIN' , 'MAXEVERYONE' , 'MAXDEFLTREG' ,'ANYWHERE_TECHNICIAN', 'ANYWHERE_APPROVER' ,'ANYWHERE_INSPECTOR' ) ) ;

delete from applicationauth where groupname not in  ('MAXADMIN' , 'MAXEVERYONE' , 'MAXDEFLTREG' ,'ANYWHERE_TECHNICIAN', 'ANYWHERE_APPROVER' ,'ANYWHERE_INSPECTOR') and app = 'WOTRACK' ; 

We don't need to modify the maxadmin and other Out of box groups which might affect Integration or other basic functions. 

  • Create a new Object Structure for reporting (similar to REP_WORKORDER) for newly created application. It is needed for creating adhoc report by users
  • Hide the original application from the Users view and position the cloned application in same place as original application. We need to restart the application servers for reflecting this change in Maximo

 update MAXMENU set position = XXXXX , image = 'appimg_wotrack.gif'  where menutype = 'MODULE' and elementtype = 'APP' and moduleapp = 'WO' and keyvalue = 'C_WOTRACK' ;

 -- XXXXX value should be lower than original application position. for example, if WOTRACK position is 11180, then C_WOTRACK is 11175

 update MAXMENU set visible = 0 where menutype = 'MODULE' and elementtype = 'APP' and moduleapp = 'WO' and keyvalue = 'WOTRACK' ;

-- visibility of original application is set 0, so that it wont be displayed in menu lookups and Work order module.

  


Friday, October 22, 2021

Maximo Automation Scripting Best Practices for Performance

Automation Scripting is a feature in Maximo used to implement business logic using any JSR 223 specification compliant Scripting language

The automation script code get compiled to Java bytecode, gets cached as part of Maximo runtime. When the script is invoked, it is cached bytecode that is executed by JVM in the same thread as other Maximo business logic written in Java. A poorly written code can cause performance issue, so we need to follow a few guidelines similar to Java customization.       

Cautious of having Multiple Scripts for Single Launch Point Event

Maximo allows to include multiple scripts for the same launch point triggering event. Maximo event topic is un-ordered map, where the events gets fired without any sequence. 
 
If you write script that need to be executed in specific order or need any pre-requisite actions on the same launch point, then it cause issues on the expected output.
 
Possible solution: Ensure that there is no dependency between scripts or combine them into a single script

Use of Single script for Multiple Launch points

We should try to create a single script where we need a generic business logic and attach it in multiple launch points. 

One such business case is to restrict description to 50 characters between Maximo and other external systems.

------------------------------------------------------------------------

strLen = len(mbo.getString("description")) ;

if(strLen > 50):

   service.error("system","DescriptionFieldLimit");

--------------------------------------------------------------------------

Above script can be attached to any MBO where description need to be restricted.

Choice of Launch point and Event

Launch points decide when the script need to be triggered. Choosing a right launch point can help avoid certain performance issue. 

Case 1: skipping an outbound integration message can be done using 2 launch points: User Exit Scripting or Publish Channel Event Filter. The best launch point to use is Event Filter because the skip action happens before the serialization of MBOs. Sample script for Event Filter to skip records based on status is below:

---------------------------------------------------------------------

If service.getMbo().getString("status")== "APPR":

evalresult = False

evalresult = True

--------------------------------------------------------------------

Case 2: Initialization of Attribute value can be set using Object Launch Point or Attribute Launch Point with Event - Initialize Value. We must use Attribute Launch Point, because Object Launch point can lead to performance issues when selecting a lot of MBOs in List tab, escalations or API actions. 

Naming Convention for Automation Script

As we know the launch points play an important role on the Scripting Performance. We need to have a way to identify the launch point of the script without navigating to the launch point tab & dialog in Scripting application.

The Name can be written in 

TABLE_SCRIPTTYPE_ATTRIBUTE_EVENT_DESCRIPTION

TABLE is WORKORDER, ASSET, PO, PR etc.,
SCRIPTTYPE can be Object, Library, Action, Attribute level, Integration and Custom Condition. 
ATTRIBUTE - Attribute name; It is used only for attribute launch point scripts 
EVENT - It's predefined triggering point. Before Save, After Save, After Commit, Attribute Initialize Value, etc.,
DESCRIPTION - can be any free text. You can ignore it based on your field length.
for example: WORKORDER_OBJECT_BEFORESAVE
WORKORDER_FLD_PRIORITY_MANDATE_INITVAL
COMMON_LIB_LIMITDESC

Avoid initialization Events from List tab

You can perform heavy initialization logic once the MBO is opened in Maximo Main tab. Doing the same action when it is loaded in List tab would cause poor response time on loading a lot of records. 

-----------------------------------------------------------------------------------------------------------------------

from psdi.common.context import UIContext

if UIContext.getCurrentContext() is not None and UIContext.isFromListTab() == False:

print ("the logic goes here")

-------------------------------------------------------------------------------------------------------------------------

Use MboSet.count() only once or isEmpty() instead

MboSet.count() calls sql script to Database every time it is executed in the script. 

In order to improve the performance, write the script once and store it in a variable. 

--------------------------------------------------------------------

cnt = mboset.count()

if cnt <= 1:

        service.log("skipping this as count is " + cnt)

-------------------------------------------------------------------

or use mboset..isEmpty() to check if the count is zero. isEmpty() will be called once if mboset is not initialized, any more calls to this function will be accessed from memory without hitting the database.

Close the MboSet opened from MXServer.getMXServer.getMboSet("")

Maximo framework will always release the mboset that are created by launch point mbo or related objects mbo.getMboSet().
 
But, for Mbosets opened using the server MXServer.getMXServer.getMboSet("") api, the programmer is responsible to close the mbosets. If it is not handled, it may lead to OutOfMemory Error. 

------------------------

try:

    xxxxxx

finally:

    mboset.cleanup()

-------------------------

Check if logging is enabled before writing log statements

As a thumb rule, write the print or log statements only after checking whether the logging is enabled or not. The file write operations would take reasonable amount of time to complete the execution of code. 

-----------------------------------------------------------------------------

from psdi.util.logging import MXLoggerFactory

logger = MXLoggerFactory.getLogger("maximo.script”);

debugEnabled = logger.isDebugEnabled()


if debugEnabled:

 service.log("MBOs saved in DB"+mboset.count())

-------------------------------------------------------------------------------

Avoid calling SAVE in middle of transaction

MBOs created or updated by a launch point script or by its related mboset are always part of the single transaction .i.e., committed into database by a single SAVE. 

If you create or update a MBO by MXServer.getMXServer().getMboSet("objectname"), those changes would be outside of the script execution. You need to add it by this code: 

------------------------------------------------------------------------------------------

newMboSet = MXServer.getMXServer.getMboSet("WORKORDER")

mbo.getMXTransaction.add(newMboSet)

------------------------------------------------------------------------------------------

In real time scenario, the chances of using this code is very rare and tricky too. 

Reference: Scripting_Best_Practices_For_Performance.pdf

service-methods-automation-scripts.html 

Wednesday, June 16, 2021

Maximo 7.6.x Barcode Generation in BIRT reports

What is Barcode ? 

A barcode, consists of bars and shapes of varying width, is a machine-readable form of alphanumeric characters that can be read with an optical barcode scanner. Barcodes are used for many applications across many Industries such as Manufacturing, Distribution, Retail, Food, Pharmaceutical, Transportation, Entertainment etc.,

Why Barcodes are needed in Maximo ?

Maximo is designed for managing assets in many industries where barcodes are used. One such use case is Spare parts management in Inventory. Stocks are scanned in front of the shelves (or bin) to enter actual balance of Inventory - it increases Inventory accuracy and Work efficiency. 

Maximo Product team don't support for any issues barcode in BIRT. So, we need to know the methods of generating barcodes for Maximo application.

Barcode Generation in BIRT Report

As Maximo uses BIRT for reporting, we will see on how barcodes can be displayed in a report. We have following methods of creating barcodes in BIRT report. 

  •         Barcodes using plugins
  •         Barcodes using ZXing API

Barcode by plugins

Plugins are provided by different vendors, available in BIRT marketplace. 

We need to place the barcode plugin jar files in this path <folder>\birt_431\eclipse\plugins to display an extension item for barcode in Report Item palette in Eclipse Report Designer. 

 



Preview Barcode in Eclipse
                    


For running the barcode report from Maximo application, we need to upload the plugin jar file in this installed path 

\IBM\SMP\maximo\applications\maximo\maximouiweb\webmodule\WEB-INF\birt\platform\plugins,

then build and deploy the EAR for making this report runtime generate barcode in browser. 


For development purpose, we used the trial version of the plugin, which will display the barcode with trial trademark.  Plugins for production are priced based on number of users.

Barcodes by ZXing API

Zxing (Zebra Crossing) - It’s open source API barcode image processing library implemented in Java. It supports one and two dimensional barcodes.

Download the zxing jars and add them to the Windows -> Preferences -> Report Design -> Classpath of report design.


Add a normal Image in the report design, right click on the Image -> click on Properties -> Edit. Choose the dynamic Image and Select Image Data from Container Data Set.



On the Data Binding of imgbar (BLOB), we write our code in Expression section for generating barcode in Image object.


You can modify the writer object to any format like Code39, QRCode etc., In this method of creating barcode, we dont need write any custom java code for deployment. It will be embedded in the report file and runs by the jars files in the Maximo libraries path. 

In order to make this report run from maximo application, we need to add the jars files in this Maximo installed path -
IBM\SMP\maximo\applications\maximo\maximouiweb\webmodule\WEB-INF\lib and proceed with deployment of EAR process.

Preview of report from Maximo application


References:

Fundamentals and Applications of Barcode Create Barcode Images Dynamically by Java Code in BIRT

Javadocs for ZXing

Sample Javascript to display barcode using ZXing

Download ZXing Jar files

Thursday, April 8, 2021

Fuel Consumption Import in Maximo Transportation

Maximo Transportation Solution has an application Fuel Transaction Import (Tr) which is used to import Inventory transactions plus meter readings from Maximo.

Steps to be followed to import Fuel Transactions.

  • Create a template
  • Import file
  • Edit records for corrections (optional)
  • Reconcile and create Inventory record

Create a template

We need to create a template for loading fuel consumption data.  It need to be defined in Organization (Tr) application, Select Action -> Transportation Options -> Fuel Transactions Import Setup.





Sample template file can be found in https://gitlab.com/bysurendar/maximo/-/blob/master/templates/fuelconsumption.csv

Import file
After we define the template, we can import the data file from Data Import (Tr) -> Fuel Transactions Import (Tr) application. Click on Import File option under More Actions Section. 

In the Import File dialog, choose Template ,defined in Organization (Tr) application. 
Select whether the imported file has Inventory Transactions & Meter Readings. 
Choose the Site for Imported Readings. 

Once you upload the file, you will get a couple of system messages. The loaded transaction will be created in PENDING status.


Edit records for corrections
We can edit the records before committing the Meter reading and fuel transactions. It can be done by Imported Transactions --> Edit Records.



Reconcile and create Inventory record

In order to commit the transaction, we need to use option Imported transactions -> Create Inventory Transactions.

First Stage of committing to database is to reconcile the transactions. You can do it by choosing the Site, selecting the records and click on Reconcile button.

 
The Status of the transaction goes to "RECONCILED" Status.

Second stage is to Create Inventory transactions for reconciled records from the same dialog. It will create the Inventory transaction for item in a storeroom. 


The loaded fuel transaction of item DIESEL is recorded as ISSUE in Inventory application. 

Since we have loaded meter readings along with fuel transactions in the same file, we can create Meter readings from Fuel transactions Import (Tr) application. The detailed explanation is given in this website  Bulk Meter reading Load


Advantage: Ease of use. We don’t need to configure MIF related object structure, enterprise service or external system to import data. It is very helpful for end users to collect fuel consumption readings from external system, validate and upload them.

Thursday, February 4, 2021

Maximo DBC - Database Configuration Scripts

What is DBC ?   
Database Configuration Scripts (DBCs) are xml-formatted instructions for making changes to Maximo Database using updatedb command. 

What can we do using DBC ?
We can perform Maximo changes related to Database configuration application, security options, application or UI, domains, menus, system properties, MAXVARS and loading .sql files using DBC. It is one way of deploying our changes to a Maximo Environment.

How to create DBCs for your project ? 
i) Create a new product xml file in <MaximoInstalledFolder>/applications/maximo/properties/product/ to store information about your enhancement
ii) Create a scripts directory in <MaximoInstalledFolder>/tools/maximo/en to place dbc files
iii) Each dbc script should be numbered sequentially. DBC file extensions - .mxs (application screen changes), .msg (maxmessages), .sql (file with sql scripts) & .dbc
iv) DBCs can be created manually by referring to existing dbcs in folders (tools/maximo/en), or, by ScriptBuilder.bat (tools/maximo/internal) or mxdiff.bat for .mxs file or geninsertdbc.bat
v) During the development phase, update product xml with information about your script
vi) This information is used by the “updatedb” command to determine from which dbc to run

Where to add DBCs ? 

  • Scripts are sequential. They start with name V followed by values in major,minor. modlevel & patch fields in product XML followed by underscore ( _ ), a sequential number and ending with extension (dbc/sql/mxs/msg)
  • First script in every new version is numbered as 01. for example, V7611_01.dbc
  • After the DBCs are added in scripts folder and product.xml is updated with latest script number in <dbmaxvarname> tag, run updatedb command
  • The dbcs for our customization should be placed in the folder   <MaximoInstalledFolder>/tools/maximo/en/<folder in dbscripts tag>/ , for example, C:/IBM/SMP/maximo/tools/maximo/en/myproject


Product XML
  • Uniquely named XML file in "applications/maximo/properties/product" directory
  • <dbmaxvarname> is MAXVAR id that will be created to store last script number for our development
  • <dbscripts> is the folder name located in tools\maximo\en
  • <dbversion> - specifies the most recent script in the scripts folder
  • <lastdbversion> - specifies the last committed dbc
  • Script version in product.xml file has dash (-), but file system has  ( _ ) underscore (V7611_00.dbc) with an extension  



updatedb process
  • Updatedb tool is present in tools\maximo folder
  • Maximo servers should be stopped when you run updatedb
  • updatedb command will fail, if there is a gap in sequential numbering of scripts. To fix it, we can add empty script files to fill the gap
  • Addition of new scripts to product directory need to be followed by update of dbversion element in product XML file to match the most recent script number
  • After running updatedb, last processed script will be shown in Maximo System Information. We need to build ear to include custom product.xml to view them in Maximo System Information.


Testing DBCs
runscriptfile command is present in "tools\maximo\internal" folder
runscriptfile.bat –c<foldername> –f<filename>
runscriptfile.bat –cmyproject –fV7611_01
   <foldername> is where the scripts are stored in. It is optional parameter. if -c is not specified, Maximo will look for dbc file in this default folder tools\maximo\en\script
   <filename> – dbc file name without any extension



Pros and Cons
  • Database independent way of making changes to Maximo irrespective of type of database (Oracle, DB2 & Microsoft SQL Server)
  • Lesser Development time
  • Need system downtime for deployment
Best Practices
  • Group structural changes together in the same script
  • Update the version and build date with each release
  • Don’t modify a script after it is released to a customer

References: 

Thursday, January 21, 2021

Maximo Service Provider - Internal & External

Internal Service Provider & External Service provider - There is no difference in functionality or feature between them. These are just 2 different license models for the Maximo Service Provider add-on.

Internal Service Provider would be for customers that are managing services for their own organization. For example maybe Client has IT or Facility services departments which provide services to other departments like Sales within their organization.

In this case IT department internally charges sales for IT services using a chargeback. If this is how you want to use Maximo for Service Provider then you would purchase an Internal license.

External Service Provider would be for customers that manage assets and services for other 3rd parties outside of their organization.

For example CompanyA providing IT services to Client and other third parties. In this case, CompanyA is the Service Provider which uses Maximo for Service Provider to deliver services to client.

These customers pay CompanyA for those services. If this is how you want to use Maximo for Service Provider then you would purchase an External license.