<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2002636098451095610</id><updated>2026-04-06T08:14:38.886+02:00</updated><category term="intermediate"/><category term="beginner"/><category term="advanced"/><category term="java"/><category term="application"/><category term="integration"/><category term="mbo"/><category term="performance"/><category term="maximo"/><category term="mif"/><category term="database"/><category term="sql"/><category term="trick"/><category term="installation"/><category term="conditional expression"/><category term="market"/><category term="tpae"/><category term="documentation"/><category term="scripting"/><category term="report"/><category term="websphere"/><category term="everyplace"/><category term="doclinks"/><category term="education"/><category term="http"/><category term="security"/><category term="tips"/><category term="birt"/><category term="mobile"/><category term="tutorial"/><category term="workflow"/><category term="anywhere"/><category term="configuration"/><category term="custom"/><category term="android"/><category term="best practice"/><category term="domain"/><category term="email"/><category term="howto"/><category term="ibm"/><category term="iot"/><category term="mxloader"/><category term="upgrade"/><category term="excel"/><category term="inventory"/><category term="logging"/><category term="lookup"/><category term="preventive maintenance"/><category term="security groups"/><category term="ccmdb"/><category term="crontask"/><category term="eclipse"/><category term="extensions"/><category term="fun"/><category term="functional"/><category term="industry solutions"/><category term="jdbc"/><category term="kpi"/><category term="license"/><category term="news"/><category term="personal"/><category term="raspberrypi"/><category term="rest"/><category term="schedule"/><category term="sigoption"/><category term="stats"/><category term="tamit"/><category term="top"/><category term="trsrm"/><category term="usability"/><category term="utilities"/><category term="audit"/><category term="barcode"/><category term="cognos"/><category term="connection"/><category term="demo"/><category term="eam"/><category term="finance"/><category term="ie"/><category term="iiot"/><category term="job"/><category term="kura"/><category term="menu"/><category term="metrics"/><category term="microsoft explorer"/><category term="mqtt"/><category term="pm"/><category term="procedure"/><category term="training"/><category term="tuning"/><category term="video"/><title type='text'>IBM Maximo Customization and Development</title><subtitle type='html'>All you ever wanted to know about Maximo</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>248</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-1694715516458185223</id><published>2019-08-22T21:43:00.002+02:00</published><updated>2019-08-24T01:05:21.494+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="configuration"/><category scheme="http://www.blogger.com/atom/ns#" term="mxloader"/><title type='text'>Migrate Maximo configurations with MxLoader</title><content type='html'>Have you ever struggled migrating configurations from Development to Test environment and then to Production?&lt;br /&gt;
If the answer is yes, you are not alone. I think this is the one of the most common issues when managing multiple environments in medium-large Maximo projects.&lt;br /&gt;
&lt;br /&gt;
Keeping several Maximo environments in synch while ensuring a fast release cycle required in today&#39;s projects is challenging and typically involves two flows.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;The first flow of configuration changes is the classical release flow. You have to release configurations&amp;nbsp;&lt;b&gt;from Development to Production&lt;/b&gt; through all the intermediate environments and entails the build of some sort of &#39;configuration package&#39; that is deployed on each environment.&lt;/li&gt;
&lt;li&gt;However, in the real world, all those environment will loose sync after some time so we need to realign back through the chain using a &lt;b&gt;database cloning&lt;/b&gt; procedure (backup and restore). This is a well known practice to rebuild a development environment ensuring all&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcYCpKs5KDMrBZMXvOvd9T-Aa0vk4gc5jI32vT1NeQqZTXLm0-XThCWPCqxc4QRebDg0Wx-t7p6ciE4WozymfrdKUFfwKepDo2F3j3gb00KyVAA7VF8IM0t3N3r9BgiMW5NFfo_AeOHKo/s1600/Migrating+Configurations.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;761&quot; data-original-width=&quot;1356&quot; height=&quot;222&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcYCpKs5KDMrBZMXvOvd9T-Aa0vk4gc5jI32vT1NeQqZTXLm0-XThCWPCqxc4QRebDg0Wx-t7p6ciE4WozymfrdKUFfwKepDo2F3j3gb00KyVAA7VF8IM0t3N3r9BgiMW5NFfo_AeOHKo/s400/Migrating+Configurations.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
In my experience I have seen a lot of different approaches to build &#39;configuration packages&#39;.&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;The simplest form of package is&amp;nbsp;&lt;b&gt;brain memory&lt;/b&gt;. This is the simplest form of package. It is applicable only when there is only one Maximo administrator/developer but is very unreliable and there is no change log of what has been released.&lt;/li&gt;
&lt;li&gt;The second type of package is a &lt;b&gt;text file with precise instructions&lt;/b&gt; of what configuration must be applied. This is the minimum level that I personally adopt on small projects involving up to 2-3 environments and 1-3 administrators/developers. The file can be prepared by the developer and passed to the system administrator (together with automation scripts, application XMLs and other configuration files) to be deployed. Such packages can be stored on a shared folder for tracking purposes or versioned on a CVS/SVN repo.&lt;/li&gt;
&lt;li&gt;Instead of having unstructured text files, some teams tries to define a standard template for documenting configurations. These are typically &lt;b&gt;Excel spreadsheets&lt;/b&gt;. I do not personally use this approach because it is quite compelling to find a set of templates to cover all possible kind of configurations and there is no great advantage over the text-file approach.&lt;/li&gt;
&lt;li&gt;The official approach is to use the &lt;b&gt;&lt;a href=&quot;https://www.ibm.com/support/knowledgecenter/SSLKT6_7.6.1/com.ibm.mbs.doc/gp_migmgr/c_ctr_mig_mgr_over.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;IBM Migration Manager&lt;/a&gt;&lt;/b&gt;. I have seldom used this approach and is perfect for large environments and big teams. The biggest problem of this tool is that it is not really easy to understand what configurations are stored in the package since it actually is a zip file containing large XML files.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
I have recently developed my own approach based on MxLoader to overcome limitations of the approach 4 thus providing a more reliable process than approach 2.&lt;/div&gt;
&lt;div&gt;
In &lt;b&gt;MxLoader 6.1&lt;/b&gt; I have released a set of Object Structures and templates specifically developed for migrating configurations: Conditional Expressions, Reports, Object Data Restriction, Attribute Data Restriction, Domains, Database Objects/Attributes/Relationships/Indexes, Automation Scripts, Application Signature Options, Security&amp;nbsp;Group Authorizations, Actions, Roles, Escalations, Workflows, Communication Templates,etc.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I typically use the templates with the &#39;Query&#39; action to extract the configuration from the development environment. I incrementally build the appropriate where clause in cell D1 to extract the minimum set of records. When I have finished building the package, I switch to the integration environment in the Config sheet and use the &#39;Sync-AddChange&#39; action to apply the configurations.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The main advantage of this approach is that it is really easy to see what configurations are in the package and what changes are actually applied to the production environment.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I encourage you to &lt;a href=&quot;https://www.ibm.com/developerworks/community/groups/community/MxLoader&quot; target=&quot;_blank&quot;&gt;download MxLoader&lt;/a&gt; and give it a try. I will do my best to publish some tutorials in the next future about migrating configurations using such great tool.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/1694715516458185223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2019/08/migrate-maximo-configurations-mxloader.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1694715516458185223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1694715516458185223'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2019/08/migrate-maximo-configurations-mxloader.html' title='Migrate Maximo configurations with MxLoader'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcYCpKs5KDMrBZMXvOvd9T-Aa0vk4gc5jI32vT1NeQqZTXLm0-XThCWPCqxc4QRebDg0Wx-t7p6ciE4WozymfrdKUFfwKepDo2F3j3gb00KyVAA7VF8IM0t3N3r9BgiMW5NFfo_AeOHKo/s72-c/Migrating+Configurations.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-3494594107221733935</id><published>2019-08-09T19:09:00.000+02:00</published><updated>2019-08-10T19:12:09.648+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="configuration"/><category scheme="http://www.blogger.com/atom/ns#" term="intermediate"/><title type='text'>The hidden features of Work Logs</title><content type='html'>Work Logs are a very useful feature in Maximo and Control Desk products to allow users to keep notes of the progress of work.&lt;br /&gt;
&lt;br /&gt;
A very nice feature of work logs is that Maximo displays all work logs for the current record an related ones. Lets make an example. If there is a work log on a work order originated from a Service Request, Maximo will display both SR logs and Work Order logs in the Work Order Tracking application.&lt;br /&gt;
In the example below we are in the Work Order Tracking application displaying work logs on work order 1019. The first work log has been added to the work order but the second one is attached to the originating service request 1214.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixC2_QjhN4wj1sk-5ODWym2mQTjipNRV0WO3PQa8NXFo1rrw7r6LtXtezjxdyph8LJZLxhYII2Q9jb9q-301lT2HtgyCTOzQqXRsnvsf_z9umqLTTbM4XnnBho_0OBsc8TOQn23VKthoU/s1600/worklogs.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;498&quot; data-original-width=&quot;1426&quot; height=&quot;138&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixC2_QjhN4wj1sk-5ODWym2mQTjipNRV0WO3PQa8NXFo1rrw7r6LtXtezjxdyph8LJZLxhYII2Q9jb9q-301lT2HtgyCTOzQqXRsnvsf_z9umqLTTbM4XnnBho_0OBsc8TOQn23VKthoU/s400/worklogs.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
To go in details, Maximo will display records on the Work Logs tab with the following logic:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Work logs attached to the current record&lt;/li&gt;
&lt;li&gt;Work logs for the originating and follow up records&lt;/li&gt;
&lt;li&gt;If the ticket is global, all work logs in related to this global&lt;/li&gt;
&lt;li&gt;If it is &#39;View SR App&#39; (VIEWSR) or cloned by it, display only work logs which are marked as &#39;Client Viewable&#39;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
These rules seem pretty reasonable but in some cases we may prefer to adopt different rules. In such cases we can use a well hidden feature.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;The system property &lt;b&gt;&lt;i&gt;psdi.worklog.workorder.useWOrelationship&lt;/i&gt;&lt;/b&gt; allows to specify a custom rule in the CUSTOMWOWORKLOG relationship of the WORKORDER object.&lt;/li&gt;
&lt;li&gt;The system property &lt;b&gt;&lt;i&gt;psdi.worklog.ticket.useTKrelationship&lt;/i&gt;&lt;/b&gt;&amp;nbsp;allows to specify a custom rule in the CUSTOMTKWORKLOG relationship of the TICKET object.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
For example if we want to display only work logs related to the currently displayed work order we can configure Maximo as follows.&lt;br /&gt;
Open the System Properties application and set&amp;nbsp;&lt;i&gt;psdi.worklog.workorder.useWOrelationship&lt;/i&gt; to 1. Then apply configuration changes by selecting the record and clicking on &#39;Live Refresh&#39; action.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY-fWU-DMuhhL4ACrtmn0F8qb8oYZ_PVzks6h4hJY9q582ncEgbn0EIhM9MEOvJKTbiPnm8mkj0VVdHBgyd4-T5Yd5CPWdx5UNDCxUi5e5OG_rvhuP2ZISJk3J3zSyxlKo7mgcReKkhBE/s1600/useWOrelationship.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;660&quot; data-original-width=&quot;1403&quot; height=&quot;187&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY-fWU-DMuhhL4ACrtmn0F8qb8oYZ_PVzks6h4hJY9q582ncEgbn0EIhM9MEOvJKTbiPnm8mkj0VVdHBgyd4-T5Yd5CPWdx5UNDCxUi5e5OG_rvhuP2ZISJk3J3zSyxlKo7mgcReKkhBE/s400/useWOrelationship.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Now open Database Configuration application, open WORKORDER object and go to the Relationships tab. Search for CUSTOMWOWORKLOG relationship and set it to:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;recordkey=:wonum and class=:woclass and siteid=:siteid&lt;/pre&gt;
&lt;br /&gt;
This is how the configuration should look.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIJ9lEgkHylh7OT4HfpQwNdBD7dPgSSLkrR-QaG6IEiX9vmULUex3OEX2NO7nTjnzEIk-B2JtgRJvVft4-O_XVGFsr5oepExYL50B_51OU5M_E1-1NcXU6GGzRzeSqdH5c5a7khY45bGU/s1600/CUSTOMWOWORKLOG.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;554&quot; data-original-width=&quot;1284&quot; height=&quot;172&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIJ9lEgkHylh7OT4HfpQwNdBD7dPgSSLkrR-QaG6IEiX9vmULUex3OEX2NO7nTjnzEIk-B2JtgRJvVft4-O_XVGFsr5oepExYL50B_51OU5M_E1-1NcXU6GGzRzeSqdH5c5a7khY45bGU/s400/CUSTOMWOWORKLOG.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
If we now open work order we will not see the work log on the service request.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxpjgEvMFWm3IH8WorqXAfL4NMczfhKUsjBc_Zoi2DSqRgU66bYMpm98j70Qjryv2GYOAi8JKBOPAOMTf6UIH_tsNuo_lAjAMR_ODVZzt7F9YT73dHc-Wy2ODnwLTQTZ5nDdqiHkpIKTo/s1600/worklogs2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;381&quot; data-original-width=&quot;1142&quot; height=&quot;132&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxpjgEvMFWm3IH8WorqXAfL4NMczfhKUsjBc_Zoi2DSqRgU66bYMpm98j70Qjryv2GYOAi8JKBOPAOMTf6UIH_tsNuo_lAjAMR_ODVZzt7F9YT73dHc-Wy2ODnwLTQTZ5nDdqiHkpIKTo/s400/worklogs2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/3494594107221733935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2019/08/the-hidden-features-of-work-logs.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/3494594107221733935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/3494594107221733935'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2019/08/the-hidden-features-of-work-logs.html' title='The hidden features of Work Logs'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixC2_QjhN4wj1sk-5ODWym2mQTjipNRV0WO3PQa8NXFo1rrw7r6LtXtezjxdyph8LJZLxhYII2Q9jb9q-301lT2HtgyCTOzQqXRsnvsf_z9umqLTTbM4XnnBho_0OBsc8TOQn23VKthoU/s72-c/worklogs.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-5113283839289128131</id><published>2019-08-04T18:31:00.001+02:00</published><updated>2019-08-04T18:31:46.877+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><title type='text'>Tracking elapsed time in work order status history</title><content type='html'>A common requirement from my clients is to track how much time work orders have been in each status.&lt;br /&gt;
IBM Maximo already has the Work Order History dialog that displays the date and time of each status change. Unfortunately it may be not straightforward for a user to calculate the time spent in each step of the process or to develop a KPI to set processing time goals in your work management flow.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGpYFvjQqNc91i0a52miqjTOvkWlmrXmVlMDRXdrppwHVzLPjPCRXhFmJ31kLr9xFUVeXSGYlFovPD2ZgTUgzb-dplP66BGbSd5oqbDQEAGPLh0GblZ_ys-70di2UDvAkotqph9IMvRi0/s1600/workorder-status-history.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;226&quot; data-original-width=&quot;754&quot; height=&quot;118&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGpYFvjQqNc91i0a52miqjTOvkWlmrXmVlMDRXdrppwHVzLPjPCRXhFmJ31kLr9xFUVeXSGYlFovPD2ZgTUgzb-dplP66BGbSd5oqbDQEAGPLh0GblZ_ys-70di2UDvAkotqph9IMvRi0/s400/workorder-status-history.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
What I usually implement is a very simple time-tracking feature that just displays the elapsed time (time spent) attribute for each row. Note how the new history dialog is much more readable now.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgy8hZii9EGywCuRK92JIQyun9AHIb8u77iTzq346KrW5TIcgKXjF-ywEdt2Crp_07j8WXX3BIWJV75O8O1-6kqYqDIxFbkLTMr5IyArdQshCniiOAKumU8gFmlk-pb6x4ULj-HC9FBnic/s1600/workorder-status-history-new.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;219&quot; data-original-width=&quot;755&quot; height=&quot;115&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgy8hZii9EGywCuRK92JIQyun9AHIb8u77iTzq346KrW5TIcgKXjF-ywEdt2Crp_07j8WXX3BIWJV75O8O1-6kqYqDIxFbkLTMr5IyArdQshCniiOAKumU8gFmlk-pb6x4ULj-HC9FBnic/s400/workorder-status-history-new.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
To achieve this result we just need three configurations:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;A new attribute to store the &#39;elapsed time&#39; value in the&amp;nbsp;&lt;span class=&quot;text fhd&quot;&gt;WOSTATUS table&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;An automation script to calculate and set the value in the custom attribute.&lt;/li&gt;
&lt;li&gt;Modify the Work Order history dialog to display the new attribute.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
Note that he same technique can be implemented for tickets (service requests) with very few modifications.&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Elapsed Time attribute&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Open Database Configuration application and create a new field like this:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Object: WOSTATUS&lt;/li&gt;
&lt;li&gt;Attribute: XXXELAPSEDTIME (replace XXX with your own custom prefix)&lt;/li&gt;
&lt;li&gt;Title: Time spent (or Elapsed Time)&lt;/li&gt;
&lt;li&gt;Type:&amp;nbsp;DURATION&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Apply database configuration changes to create the new field in the database.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Automation Script&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Open Automation Scripts Applications and create the following script.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;# Script: WOSTATUS_TIMETRACKING
# Launch Point: Object (Save - Add - After Save)
# Object: WOSTATUS
# Calculate the time spent in previous status and update XXXELAPSEDTIME

from psdi.mbo import Mbo
from psdi.mbo import MboConstants

# Perform calculation only on interactive sessions to avoid the following error when generating PMs in the background.
# BMXAA3212E - Error while generating work order for PM. BMXAA8229W - Record WOSTATUS has been updated by another user.
if interactive:
  # get latest status history records
  shSet = mbo.getMboSet(&quot;$WOSTATUS$&quot;, &quot;WOSTATUS&quot;, &quot;wonum=:wonum and siteid=:siteid&quot;)
  shSet.setOrderBy(&quot;changedate desc&quot;)

  # calculate elapsed time
  if shSet is not None:
    lastSh = shSet.getMbo(1)
    thisSh = shSet.getMbo(0)
    if lastSh is not None and thisSh is not None:
      diff = (thisSh.getDate(&#39;CHANGEDATE&#39;).getTime() - lastSh.getDate(&#39;CHANGEDATE&#39;).getTime()) / float(3600000)
      lastSh.setValue(&quot;XXXELAPSEDTIME&quot;, diff, MboConstants.NOACCESSCHECK+MboConstants.NOVALIDATION)&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Application dialog&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The new WOSTATUS.XXXELAPSEDTIME attribute is now automatically updated by the script so we just have to display it in the application dialog.&lt;br /&gt;
Open Application Designer and search for WOTRACK application.&lt;br /&gt;
Edit the&amp;nbsp;&lt;i&gt;viewhist &lt;/i&gt;dialog and add the XXXELAPSEDTIME attribute in the first table.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/5113283839289128131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2019/08/tracking-elapsed-time-in-work-order.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/5113283839289128131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/5113283839289128131'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2019/08/tracking-elapsed-time-in-work-order.html' title='Tracking elapsed time in work order status history'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGpYFvjQqNc91i0a52miqjTOvkWlmrXmVlMDRXdrppwHVzLPjPCRXhFmJ31kLr9xFUVeXSGYlFovPD2ZgTUgzb-dplP66BGbSd5oqbDQEAGPLh0GblZ_ys-70di2UDvAkotqph9IMvRi0/s72-c/workorder-status-history.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-2691830860969699018</id><published>2019-08-03T17:31:00.000+02:00</published><updated>2019-08-04T18:32:00.795+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="doclinks"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><title type='text'>Disable default attachment folder</title><content type='html'>One of the fist lessons I have learned through all these years as Maximo consultant is that &lt;b&gt;&lt;i&gt;every time there is a default value for a field the user will not change it&lt;/i&gt;&lt;/b&gt;. A very common example of this is the Folder field of the Add Attachment dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp1heUTVfHwfRK9Ft6B3pVoW2Rrs-fIq0HUwjtTP68ZAQcUDOAYnxv0jAwECWNzgjm7OIYn44C1WXlEiqshvqHXP68ZKY_epVLEaaHFNW60lIAzlaq9Naf0M-mGzptB3OFG1_VxVtBVXQ/s1600/doclinks.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;537&quot; data-original-width=&quot;1140&quot; height=&quot;187&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp1heUTVfHwfRK9Ft6B3pVoW2Rrs-fIq0HUwjtTP68ZAQcUDOAYnxv0jAwECWNzgjm7OIYn44C1WXlEiqshvqHXP68ZKY_epVLEaaHFNW60lIAzlaq9Naf0M-mGzptB3OFG1_VxVtBVXQ/s400/doclinks.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The value of this field will always default to the first folder available in alphabetical order. If we want to force the user to select the most appropriate folder for the attachment, then we have to remove that default value.&lt;br /&gt;
The attribute we want to change is DOCLINKS.DOCTYPE. Unfortunately, setting a default value for this field in Database Configuration will not work (believe me I have tried) so we have use a more powerful feature to control the behavior of this attribute. The solution I have found is to use a very simple automation script. Here it is.&lt;br /&gt;
&lt;br /&gt;
Open the Automation Scrips application and create a new record with the following data:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Type: Script with Attribute Launch Point&lt;/li&gt;
&lt;li&gt;Launch Point: DOCTYPEDEFAULT&lt;/li&gt;
&lt;li&gt;Description: Reset default Attachment Folder for application WOTRACK&lt;/li&gt;
&lt;li&gt;Object DOCLINKS&lt;/li&gt;
&lt;li&gt;Attribute: DOCTYPE&lt;/li&gt;
&lt;li&gt;Event: Run Action&lt;/li&gt;
&lt;li&gt;Script: DOCTYPEDEFAULT&lt;/li&gt;
&lt;li&gt;Script Language: python&lt;/li&gt;
&lt;li&gt;Source: &lt;i&gt;paste code below&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;#-------------------------------------------------------------------------------------------------------------
# Script: DOCTYPEDEFAULT
# Launch Point: DOCLINKS.DOCTYPE - Run Action
# Reset default Attachment Folder for application WOTRACK
#-------------------------------------------------------------------------------------------------------------
from psdi.mbo import MboConstants

if mbo.getOwner() is not None:
  # reset the default value only for a specific set of applications
  if mbo.getOwner().getThisMboSet().getApp() in (&quot;WOTRACK&quot;, &quot;ASSET&quot;):
    if mbo.getMboValue(&quot;DOCTYPE&quot;).getPreviousValue().asString()==&quot;&quot;:
      # set an invalid value so the user is forced to set a correct value
      mbo.setValue(&quot;DOCTYPE&quot;, &quot;-&quot;, MboConstants.NOVALIDATION)
&lt;/pre&gt;
&lt;br /&gt;
The script is quite simple.&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;It first checks if the owner application is in a specific set. This is because we may need to override the default behavior only for a specific set of applications. In the example it work only for Assets and Work Order Tracking applications.&lt;/li&gt;
&lt;li&gt;Verifies that the previous value of the DOCTYPE field is not already set. I have used this trick to detect if the attribute was just initialized or the user already set the value.&lt;/li&gt;
&lt;li&gt;Sets an invalid value &#39;-&#39; so the user is forced to set an appropriate folder.&lt;/li&gt;
&lt;/ol&gt;
</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/2691830860969699018/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2019/08/disable-default-attachment-folder.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/2691830860969699018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/2691830860969699018'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2019/08/disable-default-attachment-folder.html' title='Disable default attachment folder'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp1heUTVfHwfRK9Ft6B3pVoW2Rrs-fIq0HUwjtTP68ZAQcUDOAYnxv0jAwECWNzgjm7OIYn44C1WXlEiqshvqHXP68ZKY_epVLEaaHFNW60lIAzlaq9Naf0M-mGzptB3OFG1_VxVtBVXQ/s72-c/doclinks.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-1012962200710989827</id><published>2019-04-26T16:52:00.001+02:00</published><updated>2019-08-18T22:07:30.537+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="sql"/><title type='text'>Where was an asset located at a certain time in the past?</title><content type='html'>Maximo has a well known feature to display the history of where an asset was located. It is accessible from View Asset Move History from the Asset application.&lt;br /&gt;
In the following example the asset&amp;nbsp;DS01-A-002 was created in location&amp;nbsp;DS01-S-SA-01 and then moved to other two locations.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdUP5ZxrfyO715yywo7MBtpsd75B682p-qINic5mXDKOKT15gsujmgGxn8QkEhEyWYbc5uPZ5QqrBgfvXZkhOB0qi8QPA8fRUGjGgZsM0s4z_0idvss86aJdiyVrRUdfGlh_A4Ml4F818/s1600/asset-move-history-new.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;506&quot; data-original-width=&quot;1058&quot; height=&quot;191&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdUP5ZxrfyO715yywo7MBtpsd75B682p-qINic5mXDKOKT15gsujmgGxn8QkEhEyWYbc5uPZ5QqrBgfvXZkhOB0qi8QPA8fRUGjGgZsM0s4z_0idvss86aJdiyVrRUdfGlh_A4Ml4F818/s400/asset-move-history-new.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
The data displayed in this dialog is stored in the ASSETTRANS database table.&lt;br /&gt;
By querying this table we can answer questions like this:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Where was my asset located at a specific point in time?&lt;/li&gt;
&lt;li&gt;What assets were in a specific location&amp;nbsp;at a specific point in time?&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Now lets start reading date from the ASSETTRANS table for asset DS01-A-002. We will get the same results displayed in the dialog above.&lt;br /&gt;
&lt;br /&gt;
select assetnum, toloc, datemoved&lt;br /&gt;
from assettrans&lt;br /&gt;
where assetnum=&#39;DS01-A-002&#39;&lt;br /&gt;
order by datemoved;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGEpgCkQ0HYgLHr7igLYHCTcrngTshIlsPPL91aaBWD3WZxD0kTuiDViGe0__IQQ0yRMf9WV_X7jqFk6C8UtT0jBEBv6UDQkat8P4j7JMJWGqGYIyRJuT7AYqxmyiOoSffSL9owvbzo-s/s1600/results01.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;82&quot; data-original-width=&quot;275&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGEpgCkQ0HYgLHr7igLYHCTcrngTshIlsPPL91aaBWD3WZxD0kTuiDViGe0__IQQ0yRMf9WV_X7jqFk6C8UtT0jBEBv6UDQkat8P4j7JMJWGqGYIyRJuT7AYqxmyiOoSffSL9owvbzo-s/s1600/results01.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
If we want to know where the asset was the 20th of April we need to know the largest DATEMOVED before that date.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;select assetnum, max(datemoved)
from assettrans
where datemoved&amp;lt;TO_TIMESTAMP(&#39;2019-04-20&#39;, &#39;YYYY-MM-DD&#39;)
and assetnum=&#39;DS01-A-002&#39;
group by assetnum;&lt;/pre&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGcQch2WHWyWHIim-qUTcUSBhCQdEiPD0rksOObEYJvUvVaml_3Z8JnZYuNlYMr8lQ26HjBm1CvzYK3qA1h2tEzyx0XxofwF-ICixVNCj8qTOsrNNtrBgvLcwwWazqapRQOvCUv2CNsN8/s1600/results02.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;47&quot; data-original-width=&quot;197&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGcQch2WHWyWHIim-qUTcUSBhCQdEiPD0rksOObEYJvUvVaml_3Z8JnZYuNlYMr8lQ26HjBm1CvzYK3qA1h2tEzyx0XxofwF-ICixVNCj8qTOsrNNtrBgvLcwwWazqapRQOvCUv2CNsN8/s1600/results02.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Now we can join this result in the following way to retrieve the list of asset&#39;s locations &#39;as of&#39; 20th of April at 11AM.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;select a.assetnum, a.siteid, a.toloc
from assettrans a
join
(select assetnum, siteid, max(datemoved) d
 from assettrans
 where datemoved&amp;lt;TO_TIMESTAMP(&#39;2019-04-20 11:00:00&#39;, &#39;YYYY-MM-DD HH24:MI:SS&#39;)
 group by assetnum, siteid
) h on h.assetnum=a.assetnum and h.siteid=a.siteid and h.d=a.datemoved
order by a.assetnum;&lt;/pre&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqno3UvW5sfKqo5rA8atevEk_Iqbe4fa-ik44Ymp0XF5d0LBMKPJlh83IDFU0xjmP6CHjqTxbTfrS-ORbveGF0MDJkQZBUtqov19QbxgI9XUSa3GHqPEapnZiIXoVC8S2ke59B37btsdo/s1600/results03-new.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;212&quot; data-original-width=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqno3UvW5sfKqo5rA8atevEk_Iqbe4fa-ik44Ymp0XF5d0LBMKPJlh83IDFU0xjmP6CHjqTxbTfrS-ORbveGF0MDJkQZBUtqov19QbxgI9XUSa3GHqPEapnZiIXoVC8S2ke59B37btsdo/s1600/results03-new.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
We can now see that asset DS01-A-002 was located in DS01-S-SA-02 as expected. The query includes all the assets and can be filtered by asset or location.&lt;br /&gt;
&lt;br /&gt;
Note that in this last query we have added the SITEID field since ASSETNUM/SITEID is the primary key of the ASSET table.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/1012962200710989827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2019/04/query-asset-location-history.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1012962200710989827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1012962200710989827'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2019/04/query-asset-location-history.html' title='Where was an asset located at a certain time in the past?'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdUP5ZxrfyO715yywo7MBtpsd75B682p-qINic5mXDKOKT15gsujmgGxn8QkEhEyWYbc5uPZ5QqrBgfvXZkhOB0qi8QPA8fRUGjGgZsM0s4z_0idvss86aJdiyVrRUdfGlh_A4Ml4F818/s72-c/asset-move-history-new.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-735260869352098074</id><published>2019-04-03T21:58:00.001+02:00</published><updated>2019-04-03T22:00:59.012+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="logging"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><title type='text'>Logging in automation scripts</title><content type='html'>I have to admit, I&#39;m a big fan of automation scripts.&lt;br /&gt;
Recent updates released with Maximo 7.6.0.9 have almost covered all the possible customization needs including library scripts, REST APIs, MIF processing, before/after save event. All the new features are well documented in &lt;a href=&quot;https://www.ibm.com/developerworks/community/wikis/form/anonymous/api/wiki/02db2a84-fc66-4667-b760-54e495526ec1/page/03ad118c-6040-43dd-bc6d-d7a03510d135/attachment/1004fd2b-1b51-411e-8df0-a8b02ca86272/media/Scritping76Features%20%285%29.pdf&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this somewhat secret document&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
However whatever nice feature will be added in the next feature pack, we will never have a debugger like we have with Java and Eclipse. This could be a serious problem when you have to develop and maintain a complex set of scripts in your environment.&lt;br /&gt;
The best way to mitigate such problem is to correctly use &lt;b&gt;Maximo logging APIs&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
In my projects I usually define a custom logger in the Logging application. It&#39;s a good practice to give a short name of your customer. In this example I have defined &lt;i&gt;mxdev&lt;/i&gt; logger for my MaximoDev customer.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj828H5JPAuPZiLHrFnAUQWRAr2uvLkexfau_8iwb-A79SYcTC21iU80F7yNYTXfQBM4P1Dv-0DzT0d_07TeYOuG12OfS9eJN8InDaS6TjB5JtDa8qBd_SU2AzHBQmUYF6_KstJwO8urhg/s1600/logger.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;310&quot; data-original-width=&quot;870&quot; height=&quot;142&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj828H5JPAuPZiLHrFnAUQWRAr2uvLkexfau_8iwb-A79SYcTC21iU80F7yNYTXfQBM4P1Dv-0DzT0d_07TeYOuG12OfS9eJN8InDaS6TjB5JtDa8qBd_SU2AzHBQmUYF6_KstJwO8urhg/s400/logger.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
I can now log messages to this custom logger using Maximo APIs. In the following example I first import the MXLoggerFactory class, then I get the reference to my &lt;i&gt;mxdev&lt;/i&gt; logger and then I use the &lt;a href=&quot;https://developer.ibm.com/static/site-id/155/maximodev/7609/maximocore/businessobjects/psdi/util/logging/MXLogger.html&quot; target=&quot;_blank&quot;&gt;MxLogger APIs&lt;/a&gt; to write messages in the system log.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;from psdi.util.logging import MXLoggerFactory

logger = MXLoggerFactory.getLogger(&quot;maximo.mxdev&quot;)

logger.info(&quot;Entering SR_INIT script for ticket &quot; + mbo.getString(&quot;TICKETID&quot;))
logger.debug(&quot;This is a debug message&quot;)
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
There are several good reasons for doing that.&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;I can select the logging level of my scripts dynamically in the Logger applications. I typically have that set to DEBUG in development and test environment. In production I set that to WARN or INFO to reduce verbosity.&lt;/li&gt;
&lt;li&gt;Logging is always a good way of commenting the code.&lt;/li&gt;
&lt;li&gt;It allows me to search for a specific string in the scripts when I see strange behaviors in the logs.&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/735260869352098074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2019/04/logging-in-automation-scripts.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/735260869352098074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/735260869352098074'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2019/04/logging-in-automation-scripts.html' title='Logging in automation scripts'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj828H5JPAuPZiLHrFnAUQWRAr2uvLkexfau_8iwb-A79SYcTC21iU80F7yNYTXfQBM4P1Dv-0DzT0d_07TeYOuG12OfS9eJN8InDaS6TjB5JtDa8qBd_SU2AzHBQmUYF6_KstJwO8urhg/s72-c/logger.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-603535081917592483</id><published>2019-03-18T22:50:00.000+01:00</published><updated>2019-03-18T22:50:24.090+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><title type='text'>Avoiding FetchResultStopLimit errors in Java or scripts</title><content type='html'>Today I had to face an issue deleting a large set of records from a Maximo table using an automation script. My script was something like this.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;mboSet = MXServer.getMXServer().getMboSet(&quot;MYTABLE&quot;, mbo.getUserInfo())
mboSet.deleteAll()
mboSet.save()
&lt;/pre&gt;
&lt;br /&gt;
Unfortunately the table I had to purge (MYTABLE in the example) was having more than 5000 rows so when I launched the script I got the following error.&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;i&gt;BMXAA7387E - While attempting to retrieve 5001 of MYTABLE, the operation was terminated because the preset limit 5000 was exceeded for retrieving MYTABLE into a single set. Reduce the number of selected objects for the operation.
&lt;/i&gt;&lt;/blockquote&gt;
The simple solution would have been to increase the &lt;i&gt;mxe.db.fetchResultStopLimit&lt;/i&gt; Maximo system parameter as documented in &lt;a href=&quot;https://www.ibm.com/developerworks/community/blogs/a9ba1efe-b731-4317-9724-a181d6155e3a/entry/BMXAA7387E_While_Attempting_to_Retrieve_5001_of_MULTIASSETLOCCI?lang=en&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this post&lt;/a&gt; but I was looking for a more elegant solution.&lt;br /&gt;
Searching a little in the Maximo Java code i discovered the &lt;i&gt;MboSet.setLogLargFetchResultDisabled()&lt;/i&gt; method that was exactly what I was looking for. Calling this method before the bulk operation will disable logging of large fetch result set to avoid FetchResultLogLimit errors. As a positive side effect it also increased the performances a lot.&lt;br /&gt;
&lt;br /&gt;
The updated script now works like a charm.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;mboSet = MXServer.getMXServer().getMboSet(&quot;MYTABLE&quot;, mbo.getUserInfo())
scSet.setWhere(where)
# disable logging of large fetch result set to avoid FetchResultLogLimit errors
&lt;b&gt;mboSet.setLogLargFetchResultDisabled(True)&lt;/b&gt;
mboSet.deleteAll()
mboSet.save()
&lt;/pre&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/603535081917592483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2019/03/avoiding-fetchresultstoplimit-errors-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/603535081917592483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/603535081917592483'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2019/03/avoiding-fetchresultstoplimit-errors-in.html' title='Avoiding FetchResultStopLimit errors in Java or scripts'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-8510039218565059113</id><published>2018-11-28T18:48:00.000+01:00</published><updated>2019-03-15T19:49:59.500+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><category scheme="http://www.blogger.com/atom/ns#" term="security groups"/><title type='text'>Automation Script to reset user&#39;s Start Centers</title><content type='html'>In a &lt;a href=&quot;http://maximodev.blogspot.com/2012/11/how-to-reset-users-start-centers.html&quot;&gt;previous post&lt;/a&gt; I have explained how to force the reload of a the start center for a specific group of users.&lt;br /&gt;
I have now developed a useful automation script that can be invoked from the Security Group application to automatically perform this task with just one click.&lt;br /&gt;
Register the script as a Script with an Action Launch Point and link it to a sigoption and to a menuaction, toolbar icon or application button as described in &lt;a href=&quot;https://www.ibm.com/developerworks/community/blogs/a9ba1efe-b731-4317-9724-a181d6155e3a/entry/adding_a_toolbar_button_in_an_application_for_an_automation_script?lang=zh_cn&quot;&gt;this post&lt;/a&gt; or &lt;a href=&quot;http://maximodev.blogspot.com/2014/06/invoke-action-when-button-is-pressed.html&quot;&gt;this one&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;# Reset users Start Centers
# Object: MAXGROUP
# Resets the Start Centers for all users assigned to the selected Security Group
# Should be called when all users are logged off so the start center is reloaded after the login
# See: http://maximodev.blogspot.com/2012/11/how-to-reset-users-start-centers.html

from psdi.server import MXServer
from psdi.mbo import MboConstants
from psdi.util.logging import MXLoggerFactory


def deleteSc(objectName, where):
 scSet = MXServer.getMXServer().getMboSet(objectName, mbo.getUserInfo())
 scSet.setWhere(where)
 logger.debug(&quot;Deleting rows from &quot; + objectName)
 # disable logging of large fetch result set to avoid FetchResultLogLimit errors
 scSet.setLogLargFetchResultDisabled(True)
 scSet.deleteAll()
 scSet.save()


logger = MXLoggerFactory.getLogger(&quot;maximo.maximodev&quot;)
logger.debug(&quot;Entering ASSET_INIT script&quot;)

logger.info(&quot;Entering ASTS_RESET_STARTCENTER&quot;)
grpname = mbo.getString(&quot;GROUPNAME&quot;)

where1 = &quot;scconfigid IN (SELECT scconfigid FROM scconfig WHERE groupname=&#39;&quot; + grpname + &quot;&#39;)&quot;
where2 = &quot;layoutid IN (SELECT layoutid FROM layout WHERE &quot; +where1+ &quot;)&quot;


deleteSc(&quot;RSCONFIG&quot;, where2)
deleteSc(&quot;FACONFIG&quot;, where2)
deleteSc(&quot;INBXCONFIG&quot;, where2)
deleteSc(&quot;KPILCONFIG&quot;, where2)
deleteSc(&quot;KPIGCONFIG&quot;, where2)
deleteSc(&quot;ACTIONSCFG&quot;, where2)
deleteSc(&quot;PORTLETDISPLAY&quot;, where2)
deleteSc(&quot;LAYOUT&quot;, where2)
deleteSc(&quot;SCCONFIG&quot;, where1)
&lt;/pre&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/8510039218565059113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2018/11/automation-script-reset-users-start-center.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/8510039218565059113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/8510039218565059113'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2018/11/automation-script-reset-users-start-center.html' title='Automation Script to reset user&#39;s Start Centers'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-7979365904456835069</id><published>2018-09-28T22:04:00.001+02:00</published><updated>2018-09-28T22:04:05.253+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="preventive maintenance"/><title type='text'>MTTx Terminology</title><content type='html'>When it comes to asset reliability measurement all the different MTTx acronyms start to appear but sometimes is not clear to everybody the exact meanings of these terms.&lt;br /&gt;
In this post I want to give a very simple explanation of these reliability KPIs.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;MTTD &lt;/b&gt;- Mean Time To Detect -&amp;nbsp;How long it takes to discover a problem.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MTTK &lt;/b&gt;- Mean Time to Know -&amp;nbsp;How long it takes to understand the problem.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MTTR &lt;/b&gt;- Mean Time To Repair - How long it takes to fix the problem.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MTTF &lt;/b&gt;- Mean Time To Failure -&amp;nbsp;Amount of time the system is available and operating. Also known as &quot;uptime&quot;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MTBF &lt;/b&gt;- Mean Time Between Failures -&amp;nbsp;Amount of time that elapses between one failure and the next.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
MTBF is the sum of MTTF and MTTR, the total time required for a device to fail and that failure to be repaired.&lt;br /&gt;
MTBF = MTTR + MTTF&lt;br /&gt;
&lt;br /&gt;
Here is a nice representation for these KPIs.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgcmZMe3RvtNzLUGNQw3VKpccBu1K0kZbzn0t8g1KjMBeraA0qf7YHeXebltqrW9dfVAUmMH1BmIsj6XCOmnJ3Rub8111tAAwfLOjbOIMboOsg2I0zIlx1DYgTkxkwW6E4YLfIocUu5_4/s1600/MTTx.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;601&quot; data-original-width=&quot;1600&quot; height=&quot;240&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgcmZMe3RvtNzLUGNQw3VKpccBu1K0kZbzn0t8g1KjMBeraA0qf7YHeXebltqrW9dfVAUmMH1BmIsj6XCOmnJ3Rub8111tAAwfLOjbOIMboOsg2I0zIlx1DYgTkxkwW6E4YLfIocUu5_4/s640/MTTx.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/7979365904456835069/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2018/09/mttx-terminology.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/7979365904456835069'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/7979365904456835069'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2018/09/mttx-terminology.html' title='MTTx Terminology'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgcmZMe3RvtNzLUGNQw3VKpccBu1K0kZbzn0t8g1KjMBeraA0qf7YHeXebltqrW9dfVAUmMH1BmIsj6XCOmnJ3Rub8111tAAwfLOjbOIMboOsg2I0zIlx1DYgTkxkwW6E4YLfIocUu5_4/s72-c/MTTx.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-7306204459111384918</id><published>2018-09-27T17:49:00.000+02:00</published><updated>2018-09-28T21:17:58.782+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="domain"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><title type='text'>How to correctly handle synonym domains in automation script</title><content type='html'>We all know that Maximo allows the definition of new internal values for synonym domains. A common example is the&amp;nbsp;LOCTYPE domain that defines the allowed values for the LOCATIONS.TYPE field.&lt;br /&gt;
If we want to implement a special business logic for the OPERATING type of locations we can write something like this in our automation script.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;loctype = mbo.getString(&quot;TYPE&quot;)
if loctype==&quot;OPERATING&quot;:
  # do something....
&lt;/pre&gt;
&lt;br /&gt;
However, if we define a new alias for the OPERATING type this script will not work as expected because it will not manage automatically the different internal values of the LOCTYPE domain.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnP86571EQJxJgPjzskBz6ql2Bi21gjmRFtlTUkCvHXCslZDcCSasYHVClCWEPJl4ub8xIsP7SLpEOJbaHZmgM9ewPUeY8ooP1IHE2P77OtsxAyCAshIj3RbYSw-R71FUvvXrZzw2TnSQ/s1600/loctype-domain.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;685&quot; data-original-width=&quot;1186&quot; height=&quot;230&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnP86571EQJxJgPjzskBz6ql2Bi21gjmRFtlTUkCvHXCslZDcCSasYHVClCWEPJl4ub8xIsP7SLpEOJbaHZmgM9ewPUeY8ooP1IHE2P77OtsxAyCAshIj3RbYSw-R71FUvvXrZzw2TnSQ/s400/loctype-domain.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The best solution is to use the &lt;i&gt;psdi.mbo.Translate.toInternalString&lt;/i&gt; method like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;from psdi.server import MXServer

loctype = MXServer.getMXServer().getMaximoDD().getTranslator().toInternalString(&quot;LOCTYPE&quot;, mbo.getString(&quot;TYPE&quot;), mbo)
if loctype==&quot;OPERATING&quot;:
  # do something....
&lt;/pre&gt;
&lt;br /&gt;
The&amp;nbsp;&lt;i&gt;toInternalString&lt;/i&gt;&amp;nbsp;method will translate the internal value of the LOCATIONS.TYPE field to the corresponding domain external value.&lt;br /&gt;
&lt;br /&gt;
There are two implementations of the&amp;nbsp;&lt;i&gt;toInternalString&lt;/i&gt;&amp;nbsp;method that are documented in the Javadoc.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;String toInternalString(String listName, String value)&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
Convert a specified value in the list to an internal MAXIMO value.&lt;br /&gt;
String returned is a single value.&lt;br /&gt;
Parameters:&lt;br /&gt;
- listName The valuelist name (valuelist.listname).&amp;nbsp; This is not case sensitive.&lt;br /&gt;
- value The external value (valuelist.value).&amp;nbsp; This is case sensitive.&lt;br /&gt;
Returns The internal value (valuelist.maxvalue)&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;&lt;i&gt;String toInternalString(String listName, String value, MboRemote mbo)&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;
Convert a specified value in the list to an internal MAXIMO value.&lt;br /&gt;
String returned is a single value.&lt;br /&gt;
Framework will use the siteid of the passed in MBO if it is site level, or the orgid of the MBO if it is org level to find out the actual values for the specified domain, and use those values for translation. If the siteid and orgid of the MBO is null, all the value records will be considered.&lt;br /&gt;
Parameters:&lt;br /&gt;
- listName The valuelist name (valuelist.listname).&amp;nbsp; This is not case sensitive.&lt;br /&gt;
- value The external value (valuelist.value).&amp;nbsp; This is case sensitive.&lt;br /&gt;
mbo the MBO that the translation values are used for or the MBO which the site and org is same with the MBO that the translation is used for.&lt;br /&gt;
Returns The internal value (valuelist.maxvalue)&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/7306204459111384918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2018/09/synonym-domain-automation-script.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/7306204459111384918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/7306204459111384918'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2018/09/synonym-domain-automation-script.html' title='How to correctly handle synonym domains in automation script'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnP86571EQJxJgPjzskBz6ql2Bi21gjmRFtlTUkCvHXCslZDcCSasYHVClCWEPJl4ub8xIsP7SLpEOJbaHZmgM9ewPUeY8ooP1IHE2P77OtsxAyCAshIj3RbYSw-R71FUvvXrZzw2TnSQ/s72-c/loctype-domain.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-3937759807194218244</id><published>2018-08-30T18:13:00.002+02:00</published><updated>2018-08-30T18:13:36.073+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="integration"/><category scheme="http://www.blogger.com/atom/ns#" term="java"/><category scheme="http://www.blogger.com/atom/ns#" term="rest"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><title type='text'>Sending SMS from Maximo calling an external Web service</title><content type='html'>In my last project I had to implement a customization to send SMS messages using &lt;a href=&quot;http://developers.skebby.it/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Skebby&lt;/a&gt;. The service APIs are obviously based on REST and JSON so I ended up writing an automation script to integrate Maximo with the Skebby service.&lt;br /&gt;
In the process of writing the code I have faced (and solved) some interesting issues so the developed script is quite complex and is an interesting demonstration of several useful techniques:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;External REST service invocation (POST and GET)&lt;/li&gt;
&lt;li&gt;JSON manipulation&lt;/li&gt;
&lt;li&gt;Retrieve Maximo system properties&lt;/li&gt;
&lt;li&gt;Usage of Java classes&lt;/li&gt;
&lt;li&gt;Appropriate logging using&amp;nbsp;MXLoggerFactory&lt;/li&gt;
&lt;li&gt;Display error messages with parameters&lt;/li&gt;
&lt;/ol&gt;
The script is based on WORKORDER object and requires two custom system properties (sms.username, sms.password) and two messages (SmsSendError, SmsSendOk).&lt;br /&gt;
Here it is.&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;from java.lang import String
from java.io import BufferedReader, InputStreamReader
from java.net import URL, URLEncoder
from java.nio.charset import StandardCharsets
from com.ibm.json.java import JSONObject, JSONArray

from psdi.server import MXServer
from psdi.util.logging import MXLoggerFactory

logger = MXLoggerFactory.getLogger(&quot;maximo.script&quot;)
logger.debug(&quot;Entering SEND_SMS script&quot;)


BASEURL = &quot;https://api.skebby.it/API/v1.0/REST/&quot;
SMS_SENDER = &quot;Maximo&quot;
SMS_DEST = &quot;+3933511111111&quot;

sms_text = &quot;Ticket &quot; + mbo.getString(&quot;WONUM&quot;) + &quot; - &quot; + mbo.getString(&quot;DESCRIPTION&quot;)

properties = MXServer.getMXServer().getConfig()
username = properties.getProperty(&quot;sms.username&quot;)
password = properties.getProperty(&quot;sms.password&quot;)

urltxt = BASEURL + &quot;login?username=&quot; + URLEncoder.encode(username, &quot;UTF-8&quot;) + &quot;&amp;amp;password=&quot; + URLEncoder.encode(password, &quot;UTF-8&quot;)
logger.debug(&quot;Authenticating: &quot; + urltxt)
url = URL(urltxt)
conn = url.openConnection()
conn.setRequestMethod(&quot;GET&quot;)

if conn.getResponseCode() != 200:
  conn.disconnect()
  msg = &quot;HTTP Error: &quot; + str(conn.getResponseCode()) + &quot; - &quot; + str(conn.getResponseMessage())
  logger.error(msg)
  service.error(&quot;asts&quot;, &quot;SmsSendError&quot;, [str(conn.getResponseCode()), str(conn.getResponseMessage()), &quot;Authentication failed&quot;])

br = BufferedReader(InputStreamReader(conn.getInputStream()))
authResp = br.readLine()
conn.disconnect()

#logger.debug(&quot;Authentication output:&quot; + authResp)
# auth tokens are returned separated by a &#39;;&#39; character
user_key,session_key = authResp.split(&#39;;&#39;)

logger.debug(&quot;Authentication tokens:&quot; + user_key + &quot;,&quot; + session_key)

logger.info(&quot;Sending SMS to &quot; + SMS_DEST + &quot; - &quot; + sms_text)

url = URL(BASEURL + &quot;sms&quot;)
conn = url.openConnection()
conn.setRequestMethod(&quot;POST&quot;)
conn.setRequestProperty(&quot;user_key&quot;, user_key)
conn.setRequestProperty(&quot;Session_key&quot;, session_key)
conn.setRequestProperty(&quot;content-type&quot;, &quot;application/json&quot;)
conn.setDoOutput(True)

recipients = JSONArray()
recipients.add(SMS_DEST)

obj = JSONObject()
obj.put(&quot;message_type&quot;, &quot;TI&quot;)
obj.put(&quot;returnCredits&quot;, False)
obj.put(&quot;sender&quot;, SMS_SENDER)
obj.put(&quot;recipient&quot;, recipients)
obj.put(&quot;message&quot;, sms_text)
jsonStr = obj.serialize(False)

logger.debug(&quot;SMS Json Request=&quot; + jsonStr)

os = conn.getOutputStream()
postData = String.getBytes(jsonStr, StandardCharsets.UTF_8)
os.write(postData)
os.flush()

if conn.getResponseCode() != 201:
  br = BufferedReader(InputStreamReader(conn.getErrorStream()))
  output = br.readLine()
  logger.error(&quot;Error: &quot; + output)
  conn.disconnect()
  msg = &quot;HTTP Error: &quot; + str(conn.getResponseCode()) + &quot; - &quot; + str(conn.getResponseMessage() + &quot; - &quot; + output)
  logger.error(msg)
  service.error(&quot;asts&quot;, &quot;SmsSendError&quot;, [str(conn.getResponseCode()), str(conn.getResponseMessage()), output])

br = BufferedReader(InputStreamReader(conn.getInputStream()))
output = br.readLine()
logger.info(&quot;OK: &quot; + output)
conn.disconnect()

service.setWarning(&quot;asts&quot;, &quot;SmsSendOk&quot;, None)
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
The script has been developed to avoid external dependencies like &lt;a href=&quot;https://www.ibm.com/developerworks/community/blogs/a9ba1efe-b731-4317-9724-a181d6155e3a/entry/Maximo_Rest_Client_Example_Calling_a_REST_Service_Logo_Tiger_3_ERP_from_a_Maximo_Client?lang=en&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this example&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/3937759807194218244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2018/08/maximo-call-external-rest-api-sms.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/3937759807194218244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/3937759807194218244'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2018/08/maximo-call-external-rest-api-sms.html' title='Sending SMS from Maximo calling an external Web service'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-5645306761242868886</id><published>2018-08-23T15:41:00.004+02:00</published><updated>2018-08-23T15:42:59.707+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="intermediate"/><category scheme="http://www.blogger.com/atom/ns#" term="scripting"/><title type='text'>Disable automatic asset/location population in Work Order and Ticket applications</title><content type='html'>Maximo has a feature that automatically populates the asset when a user enters a location and viceversa. This is a feature may be useful for most clients but some other clients don’t like this behavior. Unfortunately Maximo does not have a built in switch to disable this.&lt;br /&gt;
&lt;br /&gt;
The best solution to solve the problem is to use an automation script with an attribute launch point.&lt;br /&gt;
This is documented in &lt;a href=&quot;https://www.ibm.com/developerworks/community/blogs/a9ba1efe-b731-4317-9724-a181d6155e3a/entry/turning_off_a_maximo_business_rule_an_example_from_work_order_tracking3?lang=en&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this post&lt;/a&gt; but i made few improvements to it.&lt;br /&gt;
My script resets the asset only when the location has been changed and ASSETNUM is changing from null to a new value. This is because there is already a warning dialog when the asset is changed from another value.&lt;br /&gt;
&lt;br /&gt;
This is how I have defined my automation script. I have tested it for Service Requests application but it should work fine for Work Orders as well.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Script&lt;/b&gt;: SR_LOCATION&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Language&lt;/b&gt;:&amp;nbsp;python&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Launch Point&lt;/b&gt;: SR_LOCATION_ACTION&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Object&lt;/b&gt;: SR (this could be also be WORKORDER or TICKET)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Attribute&lt;/b&gt;:&amp;nbsp;LOCATION&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Event&lt;/b&gt;: Run Action (Validate should also work)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Variables&lt;/b&gt;: none&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;b&gt;Script&lt;/b&gt;:&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;from psdi.mbo import MboConstants

if not mbo.isNull(&quot;LOCATION&quot;):
  if mbo.getMboValue(&quot;ASSETNUM&quot;).getPreviousValue().asString()==&quot;&quot; and not mbo.isNull(&quot;ASSETNUM&quot;):
    mbo.setValueNull(&quot;ASSETNUM&quot;, MboConstants.NOVALIDATION_AND_NOACTION)
&lt;/pre&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/5645306761242868886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2018/08/disable-automatic-asset-location.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/5645306761242868886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/5645306761242868886'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2018/08/disable-automatic-asset-location.html' title='Disable automatic asset/location population in Work Order and Ticket applications'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-253461373893073972</id><published>2018-08-22T16:29:00.000+02:00</published><updated>2018-08-23T16:30:16.420+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="beginner"/><category scheme="http://www.blogger.com/atom/ns#" term="conditional expression"/><category scheme="http://www.blogger.com/atom/ns#" term="domain"/><category scheme="http://www.blogger.com/atom/ns#" term="maximo"/><title type='text'>How to restrict allowed status changes for workorders</title><content type='html'>Maximo has a predefined set of statuses for work orders that are defined in the&amp;nbsp;WOSTATUS synonym domain. The values and their meaning are well documented in the &lt;a href=&quot;https://www.ibm.com/support/knowledgecenter/SSLKT6_7.6.0.9/com.ibm.mbs.doc/mbs_common/c_wo_status.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;official documentation&lt;/a&gt;.&lt;br /&gt;
Unfortunately the allowed state transitions are hardcoded in the&amp;nbsp;&lt;i&gt;psdi.app.workorder.WOStatusHandler&lt;/i&gt; class and cannot be easily changed since they are defined as private arrays.&lt;br /&gt;
Here is a brief summary of the allowed status changes.&lt;br /&gt;
&lt;br /&gt;
&lt;table border=&quot;1&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
&lt;tbody&gt;
&lt;tr bgcolor=&quot;#ddd&quot;&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;WAPPR&lt;/th&gt;
&lt;th&gt;APPR&lt;/th&gt;
&lt;th&gt;WSCH&lt;/th&gt;
&lt;th&gt;WMATL&lt;/th&gt;
&lt;th&gt;INPRG&lt;/th&gt;
&lt;th&gt;COMP&lt;/th&gt;
&lt;th&gt;CANCEL&lt;/th&gt;
&lt;th&gt;CLOSE&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;WAPPR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;APPR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;WSCH&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;WMATL&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;INPRG&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;COMP&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;CANCEL&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Y&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td bgcolor=&quot;#ddd&quot;&gt;&lt;b&gt;CLOSE&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;br /&gt;
From status APPR you can set any target status.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMGXc4rew4T5z6LbaQki8CBT7tT4xv2ukU5XDBq9PWnyb1OF0YBhbjRSkkQ1UpdzbNhqlGwFog5IBNbADgcp-Cda7LiyDiZNc8cMNKogpJXqP46iZSIr8sQI1dKDpIEBjhA8MeNjadw08/s1600/wo-change-status-appr.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;504&quot; data-original-width=&quot;774&quot; height=&quot;208&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMGXc4rew4T5z6LbaQki8CBT7tT4xv2ukU5XDBq9PWnyb1OF0YBhbjRSkkQ1UpdzbNhqlGwFog5IBNbADgcp-Cda7LiyDiZNc8cMNKogpJXqP46iZSIr8sQI1dKDpIEBjhA8MeNjadw08/s320/wo-change-status-appr.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
This allows too much freedom in some cases so we want to restrict the allowed state transitions.&lt;br /&gt;
For example you might want to prevent users from changing the status of work orders that are in APPR (Approved) status to CLOSE (Closed) or CAN (Canceled).&lt;br /&gt;
&lt;br /&gt;
First, navigate to &lt;i&gt;Condition Expression Manager&lt;/i&gt; and create the following conditional expression:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Condition: WONOTAPPR&lt;/li&gt;
&lt;li&gt;Description: Work Order is not in APPR status&lt;/li&gt;
&lt;li&gt;Type: Expression&lt;/li&gt;
&lt;li&gt;Expression: :status not in (&#39;APPR&#39;)&lt;/li&gt;
&lt;li&gt;Always Evaluate: false&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Open the the &lt;i&gt;Domains&lt;/i&gt; application and bring up the WOSTATUS domain.&lt;br /&gt;
Select the CAN status row and click on the&amp;nbsp;&lt;i&gt;View/Modify Conditions&lt;/i&gt;&amp;nbsp;button.&lt;br /&gt;
Select the &quot;new row&quot; button and select the new condition you created above, and click OK.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg285AVmlhnhvg02hSiz_RppE7_2-RHF2u5HYZ1_81W0H51QR1fweyr4PRLXhg6gQsvHAfP9fKdv7tMOg5qJj_d9hOzMDfAuXD_4hMjySA8cPc8y4ewbYO7YOp5QpsyG8IWj9Lwe2Mvahw/s1600/wostatus.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;774&quot; data-original-width=&quot;1243&quot; height=&quot;248&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg285AVmlhnhvg02hSiz_RppE7_2-RHF2u5HYZ1_81W0H51QR1fweyr4PRLXhg6gQsvHAfP9fKdv7tMOg5qJj_d9hOzMDfAuXD_4hMjySA8cPc8y4ewbYO7YOp5QpsyG8IWj9Lwe2Mvahw/s400/wostatus.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Do the same to COMP and CLOSE status if you wish.&lt;br /&gt;
If you now open any work order in APPR status you will notice that the list of allowed target statuses is shorter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDiiSF6VfU0lLK3AM0-HR1UYlVi1lbi8dhQpZLvyqQADYOVI5Ogvsbzl-0y7Wg3TRv0OAGeMXoZN7hCiZK5wVfEKmFxb5Hrft1Q01fX361qHoYDtqSINxPmG04MHjB5gZtBhWUN2R_LKI/s1600/wo-change-status-appr-new.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;463&quot; data-original-width=&quot;503&quot; height=&quot;294&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDiiSF6VfU0lLK3AM0-HR1UYlVi1lbi8dhQpZLvyqQADYOVI5Ogvsbzl-0y7Wg3TRv0OAGeMXoZN7hCiZK5wVfEKmFxb5Hrft1Q01fX361qHoYDtqSINxPmG04MHjB5gZtBhWUN2R_LKI/s320/wo-change-status-appr-new.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
The good part is that the same rule applies also if you click on the quick actions.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin2IaPc0fVv6JHWKxNASdlv_yB1MCH_bCf7mgH7-Fti6IxfgMgM97pDTNnpJgFDJ8p8Iazq4TriTc6A0mcexvvqew30ykRcNcBBRNa3ffpRyMtUQtTLwLHVdcfeLJkQZSCnoL2f6eOXZ4/s1600/wostatus-error.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;602&quot; data-original-width=&quot;902&quot; height=&quot;213&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin2IaPc0fVv6JHWKxNASdlv_yB1MCH_bCf7mgH7-Fti6IxfgMgM97pDTNnpJgFDJ8p8Iazq4TriTc6A0mcexvvqew30ykRcNcBBRNa3ffpRyMtUQtTLwLHVdcfeLJkQZSCnoL2f6eOXZ4/s320/wostatus-error.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;References&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ibm.com/developerworks/community/blogs/a9ba1efe-b731-4317-9724-a181d6155e3a/entry/From_the_Maximo_Support_Desk_Allowable_Status_Changes_for_Work_Orders?lang=en&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;From the Maximo Support Desk - Allowable Status Changes for Work Orders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.ibm.com/developerworks/community/blogs/a9ba1efe-b731-4317-9724-a181d6155e3a/entry/maximo_7_5_restricting_the_list_of_available_statuses_based_on_current_record_status?lang=en_us&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Restricting the list of available statuses based on current record status&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/253461373893073972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2018/08/restrict-allowed-status-changes.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/253461373893073972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/253461373893073972'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2018/08/restrict-allowed-status-changes.html' title='How to restrict allowed status changes for workorders'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMGXc4rew4T5z6LbaQki8CBT7tT4xv2ukU5XDBq9PWnyb1OF0YBhbjRSkkQ1UpdzbNhqlGwFog5IBNbADgcp-Cda7LiyDiZNc8cMNKogpJXqP46iZSIr8sQI1dKDpIEBjhA8MeNjadw08/s72-c/wo-change-status-appr.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-88124114388183469</id><published>2017-10-25T19:05:00.004+02:00</published><updated>2017-10-25T19:05:49.587+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="application"/><category scheme="http://www.blogger.com/atom/ns#" term="email"/><category scheme="http://www.blogger.com/atom/ns#" term="intermediate"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><title type='text'>How to extract emails to notify users</title><content type='html'>There are several situation where you need to quickly notify a set of users sending them an email. These are few examples of such situations.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;There is a urgent maintenance activity to perform on Maximo that requires to enable the admin mode and logoff all the users.&lt;/li&gt;
&lt;li&gt;You are going to rollout an additional validation into an application that will affect the way technicians must enter data when closing work orders.&lt;/li&gt;
&lt;li&gt;An important event has appended (incident or critical problem) and you must alert people as soon as possible.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
The built-in &lt;b&gt;Bulletin Board application&lt;/b&gt; often solves these problem that allows to broadcast information throughout your organization. You can specify an audience for a message, based on organization, site or person group. Messages will appear on the start centers and a notification icon will be displayed at the top of the window.&lt;br /&gt;
Furthermore, the &#39;Create Communication&#39; action allows to send an email to the selected audience.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDBnMtLvKmk6pOQXVc95YdF7U_ZBDqOCHmWWR0xOdAJc1uzIINeGnTOfetFnYLSKqqlBVK12X6Klsl5NnVYg9-Rk3UZbe02y-e3VXCxvpxik1L4RI4OPLGt_xxF5BWu_ilm31-8kZ3418/s1600/bboard.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;704&quot; data-original-width=&quot;1032&quot; height=&quot;272&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDBnMtLvKmk6pOQXVc95YdF7U_ZBDqOCHmWWR0xOdAJc1uzIINeGnTOfetFnYLSKqqlBVK12X6Klsl5NnVYg9-Rk3UZbe02y-e3VXCxvpxik1L4RI4OPLGt_xxF5BWu_ilm31-8kZ3418/s400/bboard.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
There are just two limitation of this approach.&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;You want to use a Security Group to select who to notify.&lt;/li&gt;
&lt;li&gt;You want to send the email from your inbox in order to interact with the recipients more easily.&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
I have solved this little problem with an easy trick. I have added the email address to the list view of the Security Groups application.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
It is really easy... follow this steps:&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;Open the Application Designer application&lt;/li&gt;
&lt;li&gt;Search for application &lt;i&gt;USER&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Add a column in the list view and type &lt;i&gt;PERSON.PRIMARYEMAIL&lt;/i&gt; in the Attribute field&lt;/li&gt;
&lt;li&gt;Save&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDIQqJ_QaUgW6PlVjRJ91-jRUCEaGIsrYfnMXxABGarKPaG3dnZ2ybJVhhMtJX18_Z6TiMWPXzNsGIw6yBIUUgaLAgqVZ7KQ3R4_4vIH9xT7pTrDpb_smirJN-d9_6zCw-FKhkTs_xsw0/s1600/appdesigner.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;658&quot; data-original-width=&quot;1205&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDIQqJ_QaUgW6PlVjRJ91-jRUCEaGIsrYfnMXxABGarKPaG3dnZ2ybJVhhMtJX18_Z6TiMWPXzNsGIw6yBIUUgaLAgqVZ7KQ3R4_4vIH9xT7pTrDpb_smirJN-d9_6zCw-FKhkTs_xsw0/s400/appdesigner.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Now if you go the Users application you will see the email addresses of your users listed. You can also filter by security group in the advanced search to refine your list.&lt;/div&gt;
&lt;div&gt;
Exporting the table and pasting the email addresses cells into your preferred email client will do the trick.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRUbAx5NYqy3f1v4F8Vtz_R2HLzsgk-A4GLlyu9Eq1qhuzGUwflsR76TWEP1-4ZtK_hdaV26lZFhz9rf9NrvddoAQBr0wo51obvVNoCltaD84dBLVWR9Jp5ZpVGPifBmISe9x-44zWzFw/s1600/users-email.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;580&quot; data-original-width=&quot;1347&quot; height=&quot;171&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRUbAx5NYqy3f1v4F8Vtz_R2HLzsgk-A4GLlyu9Eq1qhuzGUwflsR76TWEP1-4ZtK_hdaV26lZFhz9rf9NrvddoAQBr0wo51obvVNoCltaD84dBLVWR9Jp5ZpVGPifBmISe9x-44zWzFw/s400/users-email.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
A similar configuration can also be used in the People application (PERSON). However, you can&#39;t search for security groups from there.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
Now don&#39;t spam your users everyday...&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/88124114388183469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/10/extract-emails-notify-users.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/88124114388183469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/88124114388183469'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/10/extract-emails-notify-users.html' title='How to extract emails to notify users'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDBnMtLvKmk6pOQXVc95YdF7U_ZBDqOCHmWWR0xOdAJc1uzIINeGnTOfetFnYLSKqqlBVK12X6Klsl5NnVYg9-Rk3UZbe02y-e3VXCxvpxik1L4RI4OPLGt_xxF5BWu_ilm31-8kZ3418/s72-c/bboard.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-1180754470124399822</id><published>2017-08-04T15:38:00.001+02:00</published><updated>2017-08-16T10:41:54.050+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="birt"/><category scheme="http://www.blogger.com/atom/ns#" term="security"/><category scheme="http://www.blogger.com/atom/ns#" term="security groups"/><category scheme="http://www.blogger.com/atom/ns#" term="sigoption"/><title type='text'>Security groups and application authorizations</title><content type='html'>We all know how flexible Security Groups are when dealing with user roles and granting application authorizations. However, flexibility often brings complexity.&lt;br /&gt;
You have carefully designed user&#39;s roles defining what applications and actions they are allowed to access in Maximo and implemented all using Security Groups application. The system goes live and after one or two years everything is messed up. Is too hard to check who has access to what and you no longer sure if the young electrician that was just hired 2 months ago has access to Database Configuration or Application Designer &amp;nbsp;:-)&lt;br /&gt;
&lt;br /&gt;
Maximo has a built-in report called S&lt;i&gt;ecurity Group Access&lt;/i&gt; that can help but I hardly find it useful. In my opinion it is too detailed to get an overall idea of the security configuration. For example, I&#39;m now working on a medium-sized Maximo solution with 20 security groups and around 250 users. Well... the &#39;Security Group Access&#39; report is 89 pages long!&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfMF_uxONLqyb-iIrZFhqOki-T9xJd_JJf9bwo1bPQjezZzMvO6AMgfeWewcr8GIT9-BeI2bioClnYjx_78m6mgiNHeDJgfDIudERcO8MGMDqYeK3R7LfNB99tIxxzSQ62jRNuls1JmAM/s1600/sec-access.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;479&quot; data-original-width=&quot;1006&quot; height=&quot;190&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfMF_uxONLqyb-iIrZFhqOki-T9xJd_JJf9bwo1bPQjezZzMvO6AMgfeWewcr8GIT9-BeI2bioClnYjx_78m6mgiNHeDJgfDIudERcO8MGMDqYeK3R7LfNB99tIxxzSQ62jRNuls1JmAM/s400/sec-access.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
That was not going to work. I needed I better solution for my purpose so I decided to open my preferred SQL client and Eclipse BIRT Designer to have some fun. Results were pretty good so I have decided to share them with the Maximo community.&lt;br /&gt;
&lt;br /&gt;
I came up with two custom reports that give me a quick grasp of the setup of user&#39;s authorizations. The first one is called &lt;b&gt;Security Overview&lt;/b&gt;&amp;nbsp;and simply lists all the Security Groups and Start Centers counting how many users are assigned to them.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLgaOEg-f-22l3_nYLoYJF9QTQoCAKtTycNpHQ_7qymXCPPAFx2EyYbxKdp4b0Y9cLeH0uJjt60YeUrK_ep5_62PZLXn7Q8RuBIh2o6houOfWIwjfsdcx3pACTfus2IXhFWAlW4PLqWvU/s1600/security-sc.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;706&quot; data-original-width=&quot;712&quot; height=&quot;395&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLgaOEg-f-22l3_nYLoYJF9QTQoCAKtTycNpHQ_7qymXCPPAFx2EyYbxKdp4b0Y9cLeH0uJjt60YeUrK_ep5_62PZLXn7Q8RuBIh2o6houOfWIwjfsdcx3pACTfus2IXhFWAlW4PLqWvU/s400/security-sc.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The second report is called &lt;b&gt;Application Security Overview&lt;/b&gt;. It tries to represent which security groups provide access to applications. It is not an easy task to represent so many information in a single report but I&#39;m finally proud of the results so here is what I have achieved to get.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih88SUgVbsbloxDxC1g_qp2FDuF9A594nXyYBe3dIoJxneultw1ROwLOxQ1UbKPhxd4k8tXNVerMHAxa9TLK9KZsQ3-9BdUIwT2N26wyRvecfM-fl2HM6c4MS5aIUrLo02otXvHtJil9U/s1600/security-app.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;672&quot; data-original-width=&quot;1013&quot; height=&quot;265&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEih88SUgVbsbloxDxC1g_qp2FDuF9A594nXyYBe3dIoJxneultw1ROwLOxQ1UbKPhxd4k8tXNVerMHAxa9TLK9KZsQ3-9BdUIwT2N26wyRvecfM-fl2HM6c4MS5aIUrLo02otXvHtJil9U/s400/security-app.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The report lists all the applications in the rows and the security groups in the columns. The cell is yellow if read access is granted, orange if write access is granted, the number is the count of sigoptions granted.&lt;br /&gt;
The report can easily get too big if more than 20 security groups are defined so I decided to accept a list of security groups as filter so I can analyze smaller sets of data separately.&lt;br /&gt;
&lt;br /&gt;
Download and installation instruction is available &lt;b&gt;&lt;a href=&quot;https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/W3e358e16d965_4adb_a288_1bf0c3945000/page/Security%20groups%20and%20application%20authorizations&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Any feedback is highly appreciated.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/1180754470124399822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/08/security-groups-application-authorizations.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1180754470124399822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1180754470124399822'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/08/security-groups-application-authorizations.html' title='Security groups and application authorizations'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjfMF_uxONLqyb-iIrZFhqOki-T9xJd_JJf9bwo1bPQjezZzMvO6AMgfeWewcr8GIT9-BeI2bioClnYjx_78m6mgiNHeDJgfDIudERcO8MGMDqYeK3R7LfNB99tIxxzSQ62jRNuls1JmAM/s72-c/sec-access.png" height="72" width="72"/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-8028625437636407551</id><published>2017-06-02T11:58:00.000+02:00</published><updated>2017-08-29T12:09:12.604+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="best practice"/><category scheme="http://www.blogger.com/atom/ns#" term="crontask"/><category scheme="http://www.blogger.com/atom/ns#" term="database"/><category scheme="http://www.blogger.com/atom/ns#" term="performance"/><category scheme="http://www.blogger.com/atom/ns#" term="report"/><category scheme="http://www.blogger.com/atom/ns#" term="tuning"/><title type='text'>Is your Maximo database in good health?</title><content type='html'>We all know Maximo is a complex product. It has plenty of features and is very flexible but sometimes complex to manage especially when system performances are poor.&lt;br /&gt;
A lot of things may affect the perceived performances of Maximo and it may be hard to have an overview of the entire system configuration.&lt;br /&gt;
&lt;br /&gt;
What are the largest tables in the database that may need archiving?&lt;br /&gt;
Are database statistics updated to optimize database queries?&lt;br /&gt;
How much data is stored for each site?&lt;br /&gt;
Has the workload of system increased over the last years?&lt;br /&gt;
What are the most heavy reports users execute?&lt;br /&gt;
What are the most resources-consuming crontasks and escalations?&lt;br /&gt;
How is the reports/crontasks/escalations workload spread across the day?&lt;br /&gt;
&lt;br /&gt;
These and many other questions have an answer in the Maximo Health Check report.&lt;br /&gt;
&lt;b&gt;&lt;a href=&quot;https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/W3e358e16d965_4adb_a288_1bf0c3945000/page/Maximo%20Health%20Check&quot; target=&quot;_blank&quot;&gt;Maximo Health Check report&lt;/a&gt;&lt;/b&gt; is a utility for IBM Maximo and IBM Control Desk that can help identify  and  analyze  issues,  errors,  or  incorrect  configurations  that  can  lead  to unsatisfying  system performances.&lt;br /&gt;
&lt;br /&gt;
Adding more JVMs to your application server cluster seldom solves Maximo performance issues. In our experience, &lt;b&gt;the most effective performance improvement techniques are on the database side&lt;/b&gt;.&lt;br /&gt;
For large Maximo systems &lt;b&gt;data archiving&lt;/b&gt; may be needed. This is because, after several years of usage, large volume  of  data  accumulated into some tables slowing down database inserts and updates.  Moving  unnecessary  data  out  of  those &amp;nbsp;tables  can  greatly improve overall system performances.&lt;br /&gt;
When specific application queries, reports or escalations have unsatisfying execution times &lt;b&gt;database  indexes  optimization&lt;/b&gt;&amp;nbsp;could be the answer. Adding  the  right  indexes  and  removing  the  wrong  ones  is  a complex activity that requires deep skills but can produce outstanding results in many cases.&lt;br /&gt;
Sometimes index optimization is not enough to fix a badly written SQL query. In this case&amp;nbsp;&lt;b&gt;SQL  queries  optimization&lt;/b&gt;&amp;nbsp;is the right technique. SQL  queries  are  everywhere  in  Maximo:  start  center  portlets, application  queries,  escalations  and  reports.  By simply refactoring those  SQL  statements I have obtained impressive results in many cases.&lt;br /&gt;
&lt;b&gt;Database tuning&lt;/b&gt; is the last chance. Assuming IBM suggested settings have been applied, this is &#39;brute force&#39; approach can bring some incremental improvement to overall performances.&lt;br /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;br /&gt;
Download and run the&amp;nbsp;&lt;b&gt;&lt;a href=&quot;https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/W3e358e16d965_4adb_a288_1bf0c3945000/page/Maximo%20Health%20Check&quot; target=&quot;_blank&quot;&gt;Maximo Health Check report&lt;/a&gt;&lt;/b&gt;&amp;nbsp;and you may find interesting information about your Maximo system.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLlbhAXcRjVth5afdb63zCZD6LRZoNC67obm-kzpe4PqNWOxy9qNtIHnFXapuKKrgjVIHEkk0jaSzmsZr-O9eVLB1HOGeOQidMWltLSHnROG-VWM08IYTA8OU1NAcWHf_1THGp4L2mR9o/s1600/MxHealthCheck.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;649&quot; data-original-width=&quot;495&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLlbhAXcRjVth5afdb63zCZD6LRZoNC67obm-kzpe4PqNWOxy9qNtIHnFXapuKKrgjVIHEkk0jaSzmsZr-O9eVLB1HOGeOQidMWltLSHnROG-VWM08IYTA8OU1NAcWHf_1THGp4L2mR9o/s400/MxHealthCheck.png&quot; width=&quot;305&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/8028625437636407551/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/06/maximo-performance-health-check.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/8028625437636407551'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/8028625437636407551'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/06/maximo-performance-health-check.html' title='Is your Maximo database in good health?'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLlbhAXcRjVth5afdb63zCZD6LRZoNC67obm-kzpe4PqNWOxy9qNtIHnFXapuKKrgjVIHEkk0jaSzmsZr-O9eVLB1HOGeOQidMWltLSHnROG-VWM08IYTA8OU1NAcWHf_1THGp4L2mR9o/s72-c/MxHealthCheck.png" height="72" width="72"/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-5829130880769470053</id><published>2017-04-04T18:04:00.001+02:00</published><updated>2017-04-04T18:32:46.915+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="integration"/><category scheme="http://www.blogger.com/atom/ns#" term="mif"/><title type='text'>Maximo REST APIs examples</title><content type='html'>&lt;i&gt;This entry is part of the &lt;a href=&quot;http://maximodev.blogspot.com/p/integration-framework.html&quot;&gt;Maximo Integration Framework&lt;/a&gt; series.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
In this tutorial I will show how easy it is to query and update data in Maximo using the Integration Framework (MIF) REST interface.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;HTTP test client setup&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
To send REST calls you first need to setup an HTTP client. In this tutorial I will use a Google Chrome add-on called Advanced REST Client.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Retrieve a record&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In this first example I will show you to retrieve a PERSON record from Maximo using a REST call with an HTTP GET request:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;b&gt;http://[MXHOST]/maxrest/rest/mbo/person/1&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Probably you will get an authentication error like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;Error 401: BMXAA0021E - User name and password combination are not valid. Try again.&lt;/pre&gt;
&lt;br /&gt;
This means that you have to pass the authentication credentials to your request. If you are using native authentication you can pass the &lt;i&gt;_lid&lt;/i&gt; and &lt;i&gt;_lpwd&lt;/i&gt; arguments as described in this example:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/1&lt;/i&gt;&lt;i&gt;?&lt;b&gt;_lid=wilson&amp;amp;_lpwd=wilson&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Now you should see the PERSON record identified by the PERSONUID=1.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgby_cNyZL5I9h7oIeXRnOOYK_WHOBuvIQZsY_kD3LXBIjJOnOP1hXXnJtBsz77Gwu9LPC-iRyr_0LacBQ3-1GAzq_86lFRQSmHxC0qpBqTtmO6FbmGKFqpdqwLtEiR9m58Srz_Gd7ZGBo/s1600/maximo-rest.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;228&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgby_cNyZL5I9h7oIeXRnOOYK_WHOBuvIQZsY_kD3LXBIjJOnOP1hXXnJtBsz77Gwu9LPC-iRyr_0LacBQ3-1GAzq_86lFRQSmHxC0qpBqTtmO6FbmGKFqpdqwLtEiR9m58Srz_Gd7ZGBo/s320/maximo-rest.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
NOTE: For all the examples below I will exclude the authentication arguments for simplicity.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;MBO and OS resources&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The REST API provides access to business objects and integration object structures.&lt;br /&gt;
&lt;br /&gt;
The two calls below will provide access to the same resource:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/&lt;b&gt;mbo&lt;/b&gt;/&lt;b&gt;person&lt;/b&gt;/1&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/&lt;b&gt;os&lt;/b&gt;/&lt;b&gt;mxperson&lt;/b&gt;/1&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
The first call access data straight from the PERSON object through MBO persistence layer.&lt;br /&gt;
The second call access data from the MXPERSON integration object structure through the MIF.&lt;br /&gt;
You will notice that results are slightly different.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Data format (XML or JSON)&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
By default Maximo retrieves data in XML format. JSON could be used instead passing the &lt;i&gt;_format&lt;/i&gt; argument:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?&lt;b&gt;_format=json&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Query&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
To retrieve the REVIS person record use the following REST call:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?&lt;b&gt;personid=revis&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
Note that Maximo will perform a wildcard search by default so if you type &#39;re&#39; instead of &#39;revis&#39; you will get a list of records that contains &#39;re&#39; in the PERSONID field:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?personid=&lt;b&gt;re&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;
To search with an exact match use the&amp;nbsp;&lt;i&gt;&lt;b&gt;~eq~&lt;/b&gt;&lt;/i&gt;&amp;nbsp;token as demonstrated in this examples:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?&lt;b&gt;personid=~eq~revis&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;div style=&quot;-webkit-text-stroke-width: 0px; color: black; font-family: &amp;quot;Times New Roman&amp;quot;; font-size: medium; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; letter-spacing: normal; margin: 0px; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;&quot;&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i style=&quot;font-family: &amp;quot;Times New Roman&amp;quot;;&quot;&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?&lt;b&gt;personid=~eq~re&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Results can be sorted using the &lt;i&gt;_orderby&lt;/i&gt;, &lt;i&gt;_orderbyasc&lt;/i&gt; or &lt;i&gt;_orderbydesc&lt;/i&gt; argument. Multiple attributes can be passed separated by a comma character.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?personid=re&amp;amp;&lt;b&gt;_orderby=statusdate&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?personid=re&amp;amp;&lt;b&gt;_orderby=status,statusdate&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;br /&gt;&lt;/b&gt;
&lt;b&gt;Create or Update a record (AddChange)&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
To create an existing record the &lt;i&gt;AddChange&lt;/i&gt; action can be used. The following example will create a new person named RESTINT. Note that in this case a&amp;nbsp;&lt;b&gt;POST&lt;/b&gt;&amp;nbsp;request must be used instead of a GET.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/?&lt;b&gt;_action=addchange&lt;/b&gt;&amp;amp;personid=restint&amp;amp;firstname=Rest&amp;amp;lastname=Int&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
To update the same record we can use the PERSONUID returned from the create. In my example it&#39;s 161.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/person/161?_action=addchange&amp;amp;personid=restint&amp;amp;firstname=RestNew&amp;amp;lastname=IntNew&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Updating child objects&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Lets now pretend we need to update an asset specification and one of its attributes. You will see things are now a little more complex.&lt;br /&gt;
&lt;br /&gt;
First of all we can create a new asset with a POST request.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/ASSET/?assetnum=myasset01&amp;amp;siteid=BEDFORD&amp;amp;description=TestTest&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Take note of your ASSETUID and query the new record with a GET request.&lt;br /&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/mbo/ASSET/2585&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Now login to Maximo, classify the MYASSET01 as a BEARING, add an ALN attribute and save it.&lt;br /&gt;
If you query the asset using the GET request above you will notice that you just have a&amp;nbsp;CLASSSTRUCTUREID attribute with a number in it specifying the classification. This is not usable in our scenario and will not allow to update attribute.&lt;br /&gt;
&lt;br /&gt;
The right approach is to switch to the object service structure. Try to query the new record with a GET request like this:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/&lt;b&gt;os/MXASSET&lt;/b&gt;/2585&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
You will see that the&amp;nbsp;HIERARCHYPATH field is now available and a subelement ASSETSPEC returns the attribute.&lt;br /&gt;
If we now want to update the value of the ALN attribute we can use a POST with a dotted notation like this:&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/os/MXASSET/2585?ASSETSPEC.1.ASSETATTRID=BEARTYPE&amp;amp;ASSETSPEC.1.ALNVALUE=ABC&amp;amp;ASSETSPEC.1.LINEARASSETSPECID=0&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
If you want to set a new classification here&#39;s an example:&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;i&gt;http://&lt;/i&gt;&lt;i&gt;[MXHOST]&lt;/i&gt;&lt;i&gt;/maxrest/rest/os/MXASSET/2585?&lt;/i&gt;&lt;i&gt;hierarchypath=BEARING%20\%20ROLLER&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;
&lt;div&gt;
Note how the spaces have been encoded in the URL with the &#39;%20&#39; string.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
Hope this can help all of us dealing with integration scenarios using REST calls...&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;References&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://www.ibm.com/support/knowledgecenter/SSLKT6_7.6.0/com.ibm.mif.doc/gp_intfrmwk/rest_api/c_rest_overview.html&quot; target=&quot;_blank&quot;&gt;IBM Documentation&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://maximodev.blogspot.com/2012/02/maximo-rest-apis-reference-material.html&quot;&gt;Maximo REST APIs reference material&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/5829130880769470053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/04/maximo-rest-apis-examples.html#comment-form' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/5829130880769470053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/5829130880769470053'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/04/maximo-rest-apis-examples.html' title='Maximo REST APIs examples'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgby_cNyZL5I9h7oIeXRnOOYK_WHOBuvIQZsY_kD3LXBIjJOnOP1hXXnJtBsz77Gwu9LPC-iRyr_0LacBQ3-1GAzq_86lFRQSmHxC0qpBqTtmO6FbmGKFqpdqwLtEiR9m58Srz_Gd7ZGBo/s72-c/maximo-rest.png" height="72" width="72"/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-6478649228642322999</id><published>2017-03-16T08:45:00.000+01:00</published><updated>2017-03-16T08:46:51.924+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="intermediate"/><category scheme="http://www.blogger.com/atom/ns#" term="mxloader"/><title type='text'>Load failure codes in Maximo with MxLoader</title><content type='html'>Creating and maintaining the hierarchy of failure codes in Maximo can be quite long and boring task using the standard Failure Codes application. The easiest and fastest way of importing Failure codes and the corresponding hierarchy is using &lt;a href=&quot;https://www.ibm.com/developerworks/community/groups/community/MxLoader&quot; target=&quot;_blank&quot;&gt;MxLoader&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The example described in this post is available in this tailored in &lt;a href=&quot;https://docs.google.com/uc?export=download&amp;amp;id=0B6PxDhwK5tSJb0RNb00xd3NHWlE&quot; target=&quot;_blank&quot;&gt;this sample MxLoader file&lt;/a&gt;. Please download it before proceeding.&lt;br /&gt;
&lt;br /&gt;
Since there is no out-of-the-box object structure in Maximo to import failure codes, you first have to &lt;b&gt;create the MxLoader custom object structures&lt;/b&gt;. This can be easily accomplished by clicking on the &lt;i&gt;Create Custom Object Structures&lt;/i&gt; in the MxLoader ribbon in Excel.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpnz2HzrKDK-YnBxzWJAfmMAssV7sIaz2WriQroe-gdnydsXFvYuPQKr9lsLoJV4fT8BC6HRHJySUm7GwUcN4REAA8PLAiBuiIBTEQD26xxEKpucInkOJh1Izb_AEw9f22ciEC1RsAwCo/s1600/failure_codes_import_0.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;132&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpnz2HzrKDK-YnBxzWJAfmMAssV7sIaz2WriQroe-gdnydsXFvYuPQKr9lsLoJV4fT8BC6HRHJySUm7GwUcN4REAA8PLAiBuiIBTEQD26xxEKpucInkOJh1Izb_AEw9f22ciEC1RsAwCo/s400/failure_codes_import_0.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
The second step is to load the &lt;b&gt;failure codes IDs and descriptions&lt;/b&gt;.&lt;br /&gt;
The &lt;i&gt;FailureCodes&lt;/i&gt;&amp;nbsp;worksheet on the example will load one failure class, two problems, two causes and three remedies.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjH3DnBhsp46IGHAvF3y16pJs3A2_FhgMGRzOvN9-V8WMz43fGnvGxmzZlLMc6_7oQPiKVyOx5DZUCtGvm87ixgMYUXQNCi1z4kMIgpc4LvBmxnJKH1wmTo8vfuSiUhuSnj6NhOr-MGwsc/s1600/failure_codes_import_1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;143&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjH3DnBhsp46IGHAvF3y16pJs3A2_FhgMGRzOvN9-V8WMz43fGnvGxmzZlLMc6_7oQPiKVyOx5DZUCtGvm87ixgMYUXQNCi1z4kMIgpc4LvBmxnJKH1wmTo8vfuSiUhuSnj6NhOr-MGwsc/s320/failure_codes_import_1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Note that in the last column we have the language code. This is helpful if you want to transalate the failure codes in multiple languages.&lt;br /&gt;
&lt;br /&gt;
We have just loaded a flat list of failure codes so now we need to create the hierarchical structure. The Failure Hierarchy template allows you to &lt;b&gt;load failure class hierarchy&lt;/b&gt; using the custom MXL_FAILURELIST Object Structure.
The example in the &lt;i&gt;FailureHierarchy&lt;/i&gt; worksheet loads a small hierarchy using the failure codes defined previously.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjwe6gvJ4QWzuYNnsRSVPezPcdOKTH1qv8S4FYZJ_3ZQcaiZs017WiPa4Xt8F6tVgftEhWCWjQSeaLL0Dplypfns3JMjlk1nW2Sbu-odq3ZDNUI7bBrdK1hyphenhyphennYvufgWpXke_-xC5zIoxg/s1600/failure_codes_import_2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;74&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjwe6gvJ4QWzuYNnsRSVPezPcdOKTH1qv8S4FYZJ_3ZQcaiZs017WiPa4Xt8F6tVgftEhWCWjQSeaLL0Dplypfns3JMjlk1nW2Sbu-odq3ZDNUI7bBrdK1hyphenhyphennYvufgWpXke_-xC5zIoxg/s320/failure_codes_import_2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Note how the failure hierarchy is specified in a flat table.&lt;br /&gt;
The object IDs in the square brackets will be generated dynamically by MxLoader during the import process. Do not enter those IDs manually.&lt;br /&gt;
&lt;br /&gt;
This is how this failure tree will look in Maximo.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_msftsU-zZqUNjFQg2LTISNGES6YD3_qGU3JOptbQXsoJx9n0aKzlm_uJeD9_t8c539Z4y4wX9Iqt40BH-ntBvIJk4BOcXs0zLlJvcooB_48YyEw7CQXguGYmLXo9zFrU8_POUVzou-0/s1600/failure_codes_import_3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;308&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_msftsU-zZqUNjFQg2LTISNGES6YD3_qGU3JOptbQXsoJx9n0aKzlm_uJeD9_t8c539Z4y4wX9Iqt40BH-ntBvIJk4BOcXs0zLlJvcooB_48YyEw7CQXguGYmLXo9zFrU8_POUVzou-0/s400/failure_codes_import_3.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Note that the Failure Hierarchy template does not allow querying existing failure hierarchy. This can be a limitation if you want to copy a failure class hierarchy from one organization to another or from one server to another.&lt;br /&gt;
To extract an existing failure hierarchy you have use an SQL query like this.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;SELECT f.orgid, f.failurelist classid, f.failurecode class,
  p.failurelist problemid, p.failurecode problem,
  c.failurelist causeid, c.failurecode cause,
  r.failurelist remedyid, r.failurecode remedy
FROM failurelist f
LEFT OUTER JOIN failurelist p ON p.parent=f.failurelist AND p.type=&#39;PROBLEM&#39;
LEFT OUTER JOIN failurelist c ON c.parent=p.failurelist AND c.type=&#39;CAUSE&#39;
LEFT OUTER JOIN failurelist r ON r.parent=c.failurelist AND r.type=&#39;REMEDY&#39;
WHERE f.parent IS NULL
ORDER BY f.failurecode, p.failurecode, c.failurecode, r.failurecode;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
MxLoader is also able to upload custom levels of failure codes in the hierarchy. For example, if you have a custom level called &lt;i&gt;SYSTEM&lt;/i&gt;, you can simply add it to the columns and MxLoader will handle it.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG0BxJqgBo6X6JqMZl986uq0VkLW11eyOnmNWiGU1GdNcJy743W2zBdU7MDxpx_pM97oldCwYqXlgE-wngJ7oJhHR0cOTlvH_4yDMCy8dZhkwoHLJXeYo_1I2uDT5lmgfMDFmKolaKKRg/s1600/failure_codes_import_4.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;62&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiG0BxJqgBo6X6JqMZl986uq0VkLW11eyOnmNWiGU1GdNcJy743W2zBdU7MDxpx_pM97oldCwYqXlgE-wngJ7oJhHR0cOTlvH_4yDMCy8dZhkwoHLJXeYo_1I2uDT5lmgfMDFmKolaKKRg/s320/failure_codes_import_4.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: 120%;&quot;&gt;References&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.slideshare.net/RobertZientara/failure-codes-in-ibm-maximo-asset-management&quot;&gt;Failure Codes in IBM Maximo Asset Management (SlideShare)&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://techmcq.com/article/Failure-Codes-Maximo/5&quot;&gt;Failure codes (TechMCQ)&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.anjadev.com/all/ibm_maximo_custom/how-to-load-failure-code-hierarchy-using-mif/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;How to load failure code hierarchy using MIF&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/6478649228642322999/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/03/load-failure-codes-in-maximo.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/6478649228642322999'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/6478649228642322999'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/03/load-failure-codes-in-maximo.html' title='Load failure codes in Maximo with MxLoader'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpnz2HzrKDK-YnBxzWJAfmMAssV7sIaz2WriQroe-gdnydsXFvYuPQKr9lsLoJV4fT8BC6HRHJySUm7GwUcN4REAA8PLAiBuiIBTEQD26xxEKpucInkOJh1Izb_AEw9f22ciEC1RsAwCo/s72-c/failure_codes_import_0.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-9039348506382835358</id><published>2017-02-06T17:34:00.003+01:00</published><updated>2017-02-06T17:38:51.807+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="application"/><category scheme="http://www.blogger.com/atom/ns#" term="beginner"/><category scheme="http://www.blogger.com/atom/ns#" term="functional"/><category scheme="http://www.blogger.com/atom/ns#" term="usability"/><title type='text'>Maximo keyboard shortcuts</title><content type='html'>You know IBM Maximo has a lot of fields and sometimes can be boring entering data. Here are some keyboard shortcuts that can ease the pain. I have highlighted in &lt;b&gt;bold &lt;/b&gt;the most common and useful ones.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Tab&lt;/b&gt; &amp;gt; The most important keyboard shortcut is the TAB key. It allows you to move across fields without using the mouse and also performs data validation and auto-completion.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Space&lt;/b&gt; &amp;gt; Select or clear a check box.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Alt + F1&lt;/b&gt; &amp;gt; Display field help for field in focus.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
There are few other useful shortcuts to move across applications.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Alt + C&lt;/b&gt; &amp;gt; Go to the Start Center.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Alt + G&lt;/b&gt; &amp;gt; Open the Go To menu. Use the arrow keys to choose the desired app.&lt;/li&gt;
&lt;li&gt;Alt + B &amp;gt; Bulletins&lt;/li&gt;
&lt;li&gt;Alt + R &amp;gt; Reports&lt;/li&gt;
&lt;li&gt;Alt + P &amp;gt; Profile&lt;/li&gt;
&lt;li&gt;Alt + S &amp;gt; Sign Out&lt;/li&gt;
&lt;li&gt;Alt + H &amp;gt; Help&lt;/li&gt;
&lt;li&gt;Alt + R &amp;gt; Return&lt;/li&gt;
&lt;li&gt;Alt + W &amp;gt; Return with Value&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
Last but not least you can quickly create and save records with these Toolbar Buttons shortcuts.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Ctrl + Alt + I&lt;/b&gt; &amp;gt; Insert New Record&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ctrl + Alt + S&lt;/b&gt; &amp;gt; Save Record&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ctrl + Alt + A&lt;/b&gt; &amp;gt; Change Status&lt;/li&gt;
&lt;li&gt;Ctrl + Alt + C &amp;gt; Clear changes&lt;/li&gt;
&lt;li&gt;Ctrl + Alt + P &amp;gt; Previous Record&lt;/li&gt;
&lt;li&gt;Ctrl + Alt + N &amp;gt; Next Record&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
This is a simplified list of the available keyboard shortcuts. For more information refer to the &lt;a href=&quot;https://www.ibm.com/support/knowledgecenter/SSLKT6_7.6.0/com.ibm.mbs.doc/mbs_common/r_keyboard_shortcuts.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;official documentation&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/9039348506382835358/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/02/maximo-keyboard-shortcuts.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/9039348506382835358'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/9039348506382835358'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/02/maximo-keyboard-shortcuts.html' title='Maximo keyboard shortcuts'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-87780179554061985</id><published>2017-01-29T16:11:00.003+01:00</published><updated>2017-02-13T21:55:41.983+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="application"/><category scheme="http://www.blogger.com/atom/ns#" term="beginner"/><category scheme="http://www.blogger.com/atom/ns#" term="tips"/><title type='text'>Maximo search operators</title><content type='html'>Maximo search features are quite advanced but often neglected. By using the advanced search techniques described in this post it is possible to find relevant records easier and faster.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Equal&lt;/h3&gt;
The equal &#39;=&#39; operator can be used to find only records that match that a word or  number exactly. In other words &#39;=&#39; means &quot;exact match&quot;.&lt;br /&gt;
Example: Enter =123 to find any records with the exact characters 123 in the field. (Search results would  not include numbers such as 0123 or 1234AB. If you enter just 123, without the =, search results  would include 0123 and 1234AB.)&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Not Equal&lt;/h3&gt;
To search for all values that are not equal to a specific value enter &#39;&lt;b&gt;!=&lt;/b&gt;&#39;.&lt;br /&gt;
For example, typing !=WAPPR in the status field will retrieve all records that are not in WAPPR status.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Greater/Less&lt;/h3&gt;
The &#39;&lt;b&gt;&amp;lt;&lt;/b&gt;&#39; and &#39;&lt;b&gt;&amp;gt;&lt;/b&gt;&#39; characters can also be used to search for records that are bigger or smaller than a specific value.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Greater than &#39;&lt;b&gt;&amp;gt;&lt;/b&gt;&#39;: searches for any date after or number/word greater than the specified value.&lt;br /&gt;Example: Enter &amp;gt;1172 finds records of occurrences that have work order number greater than 1172.&lt;/li&gt;
&lt;li&gt;Less than &#39;&lt;b&gt;&amp;lt;&lt;/b&gt;&#39;: searches for any date before or number/word smaller than the specified value.&lt;br /&gt;Example: Enter &amp;lt;1172 finds records of occurrences that have work order number smaller than 1172.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;
List of values&lt;/h3&gt;
You can use comma &#39;&lt;b&gt;,&lt;/b&gt;&#39; operator to list the records that match with either of the values specified. It basically acts as the OR operator.&lt;br /&gt;
For example, typing WAPPR,COMP in the status field will retrieve all records that are in WAPPR or COMP status .&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Wildcards&lt;/h3&gt;
You can use a &quot;wildcard&quot; characters with letters or numbers to indicate you want to find records that begin with, end with, or contain those letters/numbers.&lt;br /&gt;
There are four characters you can use  as a wildcard:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Asterisk &#39;&lt;b&gt;*&lt;/b&gt;&#39; or percent sign &#39;&lt;b&gt;%&lt;/b&gt;&#39;: stand for any number of characters (zero, one, or multiple) in the specified position.&lt;br /&gt;Example:  Enter 123* to find records that start with 123, such as 123, 12345, 123ABC. &lt;br /&gt;
Example:  Enter *123 to find records that end in 123, such as 123, 5123, PUMP123.&lt;br /&gt;
Example:  Enter *123* to find records that contain 123, such as 123, 1234, PUMP123xy.&lt;/li&gt;
&lt;li&gt;Underscore &#39;&lt;b&gt;_&lt;/b&gt;&#39; or question mark &#39;&lt;b&gt;?&lt;/b&gt;&#39;: stand for a single character in the specified position.&lt;br /&gt;Example:  Enter 123_ to find any four‐character records that start with 123, such as 1234, 1230,  123g.&lt;br /&gt;Example:  Enter or _18 to find any three‐character records that end with 18, such as 418, J18. &lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3&gt;
NULL Values&lt;/h3&gt;
You can search for null and not null values by entering the following values into a search field on the Find tab: &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;To search for a null value enter: &lt;b&gt;~null~&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;To search for not null values enter: &lt;b&gt;!= ~null~&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
If your keyboard does not have the tilde &#39;~&#39; character you may type enter this character by typing 126 on your numeric keypad while pressing the &#39;Alt&#39; key.&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
Dates&lt;/h3&gt;
A small additional tip for searching dates in the current month.&lt;br /&gt;
If you want to search for WO&#39;s with scheduled start date less than today, you don&#39;t need to type or select the whole date into the search field because Maximo automatically appends the current month and year in the where clause.&lt;br /&gt;
For example, if you search with &amp;lt;15, system will return all WO&#39;s where scheduled start date before the 15th of the current month.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;
References&lt;/h3&gt;
&lt;a href=&quot;http://www.ibm.com/support/docview.wss?uid=swg21375684&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Understanding Search Methodologies&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.ibm.com/support/docview.wss?uid=swg21295812&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;To Search For Records in a Maximo Database&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://maximodev.blogspot.it/2012/03/search-for-null-values-in-maximo.html&quot;&gt;Search for NULL values in Maximo applications&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/87780179554061985/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/01/maximo-search-operators.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/87780179554061985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/87780179554061985'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/01/maximo-search-operators.html' title='Maximo search operators'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-811129062081463793</id><published>2017-01-18T15:15:00.000+01:00</published><updated>2017-01-26T17:53:01.899+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="beginner"/><category scheme="http://www.blogger.com/atom/ns#" term="license"/><title type='text'>Find inactive users in Maximo</title><content type='html'>Here is a quick SQL query you can use to find inactive users that haven&#39;t logged into Maximo in the last 2 months.&lt;br /&gt;
&lt;br /&gt;
DB2&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;select * from maxuser
where status=&#39;ACTIVE&#39;
and sysuser=0
and not exists (select userid from logintracking where logintracking.userid=maxuser.userid and attemptresult=&#39;LOGIN&#39; and attemptdate&amp;gt;(current date-60 DAYS))
order by userid;&lt;/pre&gt;
&lt;br /&gt;
Oracle&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;select * from maxuser
where status=&#39;ACTIVE&#39;
and sysuser=0
and not exists (select userid from logintracking where logintracking.userid=maxuser.userid and attemptresult=&#39;LOGIN&#39; and attemptdate&amp;gt;sysdate-60)
order by userid;&lt;/pre&gt;
&lt;br /&gt;
SQL Server&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;select * from maxuser
where status=&#39;ACTIVE&#39;
and sysuser=0
and not exists (select userid from logintracking where logintracking.userid=maxuser.userid and attemptresult=&#39;LOGIN&#39; and attemptdate&amp;gt;getdate()-60)
order by userid;&lt;/pre&gt;
&lt;br /&gt;
Obviously, the above query works only if you have enabled the login tracking feature in Security Groups - Security Controls.&lt;br /&gt;
&lt;br /&gt;
This is very useful if you want a quick idea about how many users are really accessing the system.&lt;br /&gt;
Another interesting use of this query is to optimize Maximo licenses by simply deactivating users that no longer use the system. You can even define an escalation that automatically do the job for you.&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/811129062081463793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/01/find-inactive-users-in-maximo.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/811129062081463793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/811129062081463793'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/01/find-inactive-users-in-maximo.html' title='Find inactive users in Maximo'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-4423600748037462566</id><published>2017-01-17T16:03:00.002+01:00</published><updated>2017-01-17T16:03:26.890+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="beginner"/><title type='text'>Long Descriptions in Maximo</title><content type='html'>Long descriptions in Maximo are a special fields meant to store long text. Unlike all the other fields they are stored in a dedicated table called&amp;nbsp;LONGDESCRIPTION. Tables link to the LONGDESCRIPTION table through their unique ID and the long description attribute is stored in a CLOB field.&lt;br /&gt;
&lt;br /&gt;
Let&#39;s change the long description of the work order &#39;1000&#39; with few lines of text.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTcDJwSUTFcHmOQq88ytAt3NqTENL7EyhQ8ljmMfYp2xcGeRSgAyqittD4pjn5oyC3DIrOglu9z-ApPbk00C4qpvHlIsBRQYwzEyrbxJNokkLlRC7-kQyjErF4UaIq7UttjNPSGeCXGXY/s1600/ld1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;153&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTcDJwSUTFcHmOQq88ytAt3NqTENL7EyhQ8ljmMfYp2xcGeRSgAyqittD4pjn5oyC3DIrOglu9z-ApPbk00C4qpvHlIsBRQYwzEyrbxJNokkLlRC7-kQyjErF4UaIq7UttjNPSGeCXGXY/s400/ld1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
If we run the following SQL we can retrieve the internal ID of the work order.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;select wonum, workorderid, description from workorder where wonum=&#39;1000&#39;;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9pzl8QL9DJyEyljX59umkTp9OAaDiK8EZ1mteXXFasdppIG9wlvoAk187O4sWbhrAnYgVpB46REBHoT0dryQxC3yixWVS-dtLKg7kq961HiZLt_TAxxZtdrwInakQuZEKReVcOayl__o/s1600/ld2.1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;38&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9pzl8QL9DJyEyljX59umkTp9OAaDiK8EZ1mteXXFasdppIG9wlvoAk187O4sWbhrAnYgVpB46REBHoT0dryQxC3yixWVS-dtLKg7kq961HiZLt_TAxxZtdrwInakQuZEKReVcOayl__o/s320/ld2.1.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Here we are interested to the WORKORDERID field which is the internal numeric identifier of the work order. This value is referenced in the LDKEY of the LONGDESCRIPTION table.&lt;br /&gt;
This is how we can retrieve the long description.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;select * from LONGDESCRIPTION where ldkey=37 and ldownertable=&#39;WORKORDER&#39;;&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr00oPhIl080MxQuNV9D7z6lzFeGAEK12ynhvF_CZjjz18FGCLhQYmZU1jWnoG08cnB4oKG3n9IFkbeI4YAbpcGrakvobwtOUnJmd3Cp65ZX69l_w2zoX8pWMP-cyyklxiV7K3i6kknmA/s1600/ld2.2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;25&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgr00oPhIl080MxQuNV9D7z6lzFeGAEK12ynhvF_CZjjz18FGCLhQYmZU1jWnoG08cnB4oKG3n9IFkbeI4YAbpcGrakvobwtOUnJmd3Cp65ZX69l_w2zoX8pWMP-cyyklxiV7K3i6kknmA/s400/ld2.2.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;null&gt;&lt;null&gt;Multiple attributes in the Mbo can have long descriptions. The LDOWNERCOL says which column owns the long description. The LANGCODE allows to have translated versions of the same long description field.&lt;/null&gt;&lt;/null&gt;&lt;br /&gt;
&lt;null&gt;&lt;null&gt;&lt;br /&gt;&lt;/null&gt;&lt;/null&gt;
&lt;null&gt;&lt;null&gt;Long description fields can be associated with any attribute in Database Configuration setting the &#39;Long Description Owner&#39; checkbox.&lt;/null&gt;&lt;/null&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQHm2jB-cvIc9CK4oJkUsNaWN6yVI0yCsJYo-8NHS4y8O6IUFGjojbxz8pChq_qQYh29tFpuDO_ogV3-t9QmI7pZkethdRvqou-4L3ARBcxUQigs9gF1u-_T9wc5I20eXnzn_Ntp2khVk/s1600/ld3.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;362&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQHm2jB-cvIc9CK4oJkUsNaWN6yVI0yCsJYo-8NHS4y8O6IUFGjojbxz8pChq_qQYh29tFpuDO_ogV3-t9QmI7pZkethdRvqou-4L3ARBcxUQigs9gF1u-_T9wc5I20eXnzn_Ntp2khVk/s400/ld3.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;null&gt;&lt;null&gt;&lt;owner attr=&quot;&quot;&gt;&lt;br /&gt;&lt;/owner&gt;&lt;/null&gt;&lt;/null&gt;
&lt;null&gt;&lt;null&gt;&lt;owner attr=&quot;&quot;&gt;In the MAXATTRIBUTE record, the ISLDOWNER column is set to 1 if the column has a long description. For each long description owner there is a nonpersistent attribute named&amp;nbsp;&lt;owner attr=&quot;&quot;&gt;+&quot;[ATTRNAME]_LONGDESCRIPTION&quot; that will store the data in the&amp;nbsp;&lt;/owner&gt;&lt;/owner&gt;&lt;/null&gt;&lt;/null&gt;LONGDESCRIPTION table.&lt;br /&gt;
&lt;null&gt;&lt;null&gt;&lt;owner attr=&quot;&quot;&gt;&lt;owner attr=&quot;&quot;&gt;&lt;br /&gt;&lt;/owner&gt;&lt;/owner&gt;&lt;/null&gt;&lt;/null&gt;
&lt;null&gt;&lt;null&gt;&lt;owner attr=&quot;&quot;&gt;&lt;owner attr=&quot;&quot;&gt;&lt;br /&gt;&lt;/owner&gt;&lt;/owner&gt;&lt;/null&gt;&lt;/null&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/4423600748037462566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2017/01/long-descriptions-in-maximo.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/4423600748037462566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/4423600748037462566'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2017/01/long-descriptions-in-maximo.html' title='Long Descriptions in Maximo'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTcDJwSUTFcHmOQq88ytAt3NqTENL7EyhQ8ljmMfYp2xcGeRSgAyqittD4pjn5oyC3DIrOglu9z-ApPbk00C4qpvHlIsBRQYwzEyrbxJNokkLlRC7-kQyjErF4UaIq7UttjNPSGeCXGXY/s72-c/ld1.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-7197355728269306378</id><published>2016-12-28T12:10:00.002+01:00</published><updated>2016-12-28T16:48:27.950+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="application"/><category scheme="http://www.blogger.com/atom/ns#" term="beginner"/><category scheme="http://www.blogger.com/atom/ns#" term="usability"/><title type='text'>Improving Assets and Locations drilldown dialog</title><content type='html'>The Assets/Locations drilldown dialog is one of the most longstanding and criticized features of Maximo.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiv4lSP4OLrLubw9PMtjeK_8TXFvj4CuvFz3jN3TGoosXRtYMTbo0JQbRR4Zcx0dE_Z5stJKsR_Rqygs29UBVzQP0JfMgN96qggW883XvkbMjZRjPT_ojQfezoVCzguVag8QtNl2MABBA/s1600/asset-drilldown.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;203&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiv4lSP4OLrLubw9PMtjeK_8TXFvj4CuvFz3jN3TGoosXRtYMTbo0JQbRR4Zcx0dE_Z5stJKsR_Rqygs29UBVzQP0JfMgN96qggW883XvkbMjZRjPT_ojQfezoVCzguVag8QtNl2MABBA/s400/asset-drilldown.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
This dialog&amp;nbsp;is almost unchanged from release 6.1 and definitely lacks some important capabilities to provide a unified view of assets and location hierarchy. However, we can make few minor improvements to the standard dialog to make it slightly better.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Increase size of the dialog&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I think the most usability improvement is to increase the size of the dialog allowing to see more elements in the drilldown. The default size is definitely too small for the typical modern screen resolutions.&lt;br /&gt;
Unfortunately there is no system setting for this and we have to tweak the dialog definition in the library.&lt;br /&gt;
Open the Application Designer and select the Export System XML action from the menu. Click on the small arrow for the LIBRARY row to export the file. Open the XML file with a good text editor and search for &lt;i&gt;psdi.webclient.beans.common.DrilldownTreeBean&lt;/i&gt;.&lt;br /&gt;
There are two occurrences of this string in the file inside the &#39;&lt;i&gt;drilldown&lt;/i&gt;&#39; dialog definition. One is for the Locations tab and one is for Assets tab.&lt;br /&gt;
Change the&amp;nbsp;&lt;i&gt;height&lt;/i&gt; attribute increasing it from the default 150 to 350 or 400.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;&amp;lt;tree id=&quot;locations_tree&quot; beanclass=&quot;psdi.webclient.beans.common.DrilldownTreeBean&quot;
width=&quot;500&quot; &lt;b&gt;height=&quot;350&quot;&lt;/b&gt; checkfornewnodes=&quot;true&quot;
ignorestructurechange=&quot;false&quot; orderby=&quot;location asc&quot; relationship=&quot;LOCATIONS&quot; selectfirstnode=&quot;true&quot;&amp;gt;&lt;/pre&gt;
&lt;br /&gt;
Now in the Application Designer app, click on the &lt;i&gt;Import Application Definition&lt;/i&gt; to import the modified LIBRARY.xml file.&lt;br /&gt;
&lt;br /&gt;
You can see from the screenshot below how much easier it is to get a grasp of the location hierarchy with&amp;nbsp;the new&amp;nbsp;larger dialog.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5xrl9QdQ4Cx-onqPwzlamBpRkH6WqtPx0jSdty0qwmspJz3CK91zHieQ23TW2ie-qFOggLEmI11CBJd6RIBZ8Ul-agDDRAqUp_zNgWHTANB4tK62NAQEcEFeOu-I0rJ-3gJcTQK_znEE/s1600/asset-drilldown-new.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;351&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5xrl9QdQ4Cx-onqPwzlamBpRkH6WqtPx0jSdty0qwmspJz3CK91zHieQ23TW2ie-qFOggLEmI11CBJd6RIBZ8Ul-agDDRAqUp_zNgWHTANB4tK62NAQEcEFeOu-I0rJ-3gJcTQK_znEE/s400/asset-drilldown-new.PNG&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;i&gt;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Increase&amp;nbsp;child records limit&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Another small improvement that can be made is to improve the default limit of child records that can be displayed. The default value is set in the &lt;i&gt;control-registry.xml&lt;/i&gt; file and is typically set to 50 which is too low.&lt;br /&gt;
To override the default value, just add the &lt;i&gt;maxchildren&lt;/i&gt; attribute and specify a larger value like 500. This is how the &lt;i&gt;locations_tree&lt;/i&gt; definition should look like.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;&amp;lt;tree id=&quot;locations_tree&quot; beanclass=&quot;psdi.webclient.beans.common.DrilldownTreeBean&quot;
width=&quot;500&quot; height=&quot;350&quot; &lt;b&gt;maxchildren=&quot;500&quot;&lt;/b&gt; checkfornewnodes=&quot;true&quot;
ignorestructurechange=&quot;false&quot; orderby=&quot;location asc&quot; relationship=&quot;LOCATIONS&quot; selectfirstnode=&quot;true&quot;&amp;gt;&lt;/pre&gt;
&lt;br /&gt;
For more information refer to &lt;a href=&quot;https://www.ibm.com/developerworks/community/wikis/home?lang=en#!/wiki/IBM%20Maximo%20Asset%20Management/page/Drilldown%20limit%20in%20Maximo&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;this post&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/7197355728269306378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2016/12/improving-assets-locations-drilldown.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/7197355728269306378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/7197355728269306378'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2016/12/improving-assets-locations-drilldown.html' title='Improving Assets and Locations drilldown dialog'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiv4lSP4OLrLubw9PMtjeK_8TXFvj4CuvFz3jN3TGoosXRtYMTbo0JQbRR4Zcx0dE_Z5stJKsR_Rqygs29UBVzQP0JfMgN96qggW883XvkbMjZRjPT_ojQfezoVCzguVag8QtNl2MABBA/s72-c/asset-drilldown.PNG" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-1563459573995392819</id><published>2016-11-29T16:02:00.000+01:00</published><updated>2016-11-29T16:28:52.054+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="advanced"/><category scheme="http://www.blogger.com/atom/ns#" term="application"/><category scheme="http://www.blogger.com/atom/ns#" term="audit"/><title type='text'>Tracking Changes using Audit feature</title><content type='html'>A common requirement in Maximo is to track changes made by users on a specific object (database table). In Maximo terms this is called &#39;Audit Tracking&#39;.&lt;br /&gt;
In this post I will describe how to enable audit tracking for a specific set of attributes of an object and how to display the updates in a separate tab of the corresponding application.&lt;br /&gt;
I will use the Assets application for this tutorial and here is the final outcome I have achieved.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGv32qUFiB9iF5sTJ1BWfZMAD-61OjdCE4GOJECk2oYJvWn9Suz_gU3f8pqAUIV9ytDkLwLsFpHKvGWOSc0V2qyK72CNybh7nCJISpZPBgPW0x7D4JxxAXm0IiZf3IJh-8PLyhvs6PuW8/s1600/assetaudit2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGv32qUFiB9iF5sTJ1BWfZMAD-61OjdCE4GOJECk2oYJvWn9Suz_gU3f8pqAUIV9ytDkLwLsFpHKvGWOSc0V2qyK72CNybh7nCJISpZPBgPW0x7D4JxxAXm0IiZf3IJh-8PLyhvs6PuW8/s400/assetaudit2.png&quot; width=&quot;500&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
There are three configurations to be implemented for this:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Enable audit of the main object and select attributes to be audited&lt;/li&gt;
&lt;li&gt;Define relationship to the audit table&lt;/li&gt;
&lt;li&gt;Customize the application to display the audit log from the UI&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;h4&gt;
Enable audit&lt;/h4&gt;
&lt;br /&gt;
First step is to enable the auditing of the table you want to monitor.&lt;br /&gt;
Open the Database Configuration application, select ASSET object and check the &lt;i&gt;Audit Enabled&lt;/i&gt; flag.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisPKlIJb3lxtCzS7Q54i-ID4yXbX9furZ_iWuLDv1hvaFVmDq7gnkCUTBAxQ1bqzMALgNBJd6Y9S26jtdCL3teuggW83gTRjnfLd4KIiKZ2P6hE7k2bp7CCd1aC9ZZ4o81OO-fsI3XQF4/s1600/assetaudit1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;106&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisPKlIJb3lxtCzS7Q54i-ID4yXbX9furZ_iWuLDv1hvaFVmDq7gnkCUTBAxQ1bqzMALgNBJd6Y9S26jtdCL3teuggW83gTRjnfLd4KIiKZ2P6hE7k2bp7CCd1aC9ZZ4o81OO-fsI3XQF4/s400/assetaudit1.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
You now have to select which fields will trigger the audit record. Switch to the Attributes tab and select the &lt;i&gt;Enable Auditing&lt;/i&gt; flag for STATUS, SERIALNUM, LOCATION, DESCRIPTION fields.&lt;br /&gt;
&lt;br /&gt;
Enable admin mode, apply configuration changes and disable admin mode.&lt;br /&gt;
A new database table A_ASSET will be created and, from now on, all the changes to the audited fields will be traced in the audit table.&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Define relationship&lt;/h4&gt;
&lt;br /&gt;
In order to be able to display the audit records we have to create a relationship from the ASSET table to the A_ASSET table.&lt;br /&gt;
Open the Database Configuration application, select ASSET object and in the Relationships tab create the following relationship.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Relationship: A_ASSET&lt;/li&gt;
&lt;li&gt;Child Object: A_ASSET&lt;/li&gt;
&lt;li&gt;Where Clause: assetnum=:assetnum and siteid=:siteid&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;h4&gt;
Customize application&lt;/h4&gt;
&lt;br /&gt;
Now you can use the relationship you have just created to display records from the child A_ASSET audit table in the Asset application.&lt;br /&gt;
Open Application Designer application, select the ASSET application and export the app&#39;s XML definition.&lt;br /&gt;
Backup the file and edit it with a text editor. Paste the text below before the last &lt;i&gt;&amp;lt;/tabgroup&amp;gt;&lt;/i&gt; before the &lt;i&gt;&amp;lt;/clientarea&amp;gt;&lt;/i&gt; tag.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;post-code&quot;&gt;&amp;lt;tab id=&quot;myhist&quot; label=&quot;History&quot;&amp;gt;
  &amp;lt;section id=&quot;myhist_grid1&quot;&amp;gt;
    &amp;lt;sectionrow id=&quot;myhist_grid1_11&quot;&amp;gt;
      &amp;lt;sectioncol id=&quot;myhist_grid1_11_1&quot;&amp;gt;
        &amp;lt;section id=&quot;myhist_grid1_11_1_1&quot;&amp;gt;
          &amp;lt;multiparttextbox dataattribute=&quot;assetnum&quot; descdataattribute=&quot;description&quot; id=&quot;myhist_grid1_1&quot;/&amp;gt;
        &amp;lt;/section&amp;gt;
      &amp;lt;/sectioncol&amp;gt;
    &amp;lt;/sectionrow&amp;gt;
  &amp;lt;/section&amp;gt;
  &amp;lt;table id=&quot;myhist_t1&quot; inputmode=&quot;readonly&quot; label=&quot;Asset history&quot; orderby=&quot;EAUDITTIMESTAMP desc&quot; relationship=&quot;A_ASSET&quot;&amp;gt;
    &amp;lt;tablebody displayrowsperpage=&quot;10&quot; id=&quot;myhist_t1_tb&quot;&amp;gt;
      &amp;lt;tablecol dataattribute=&quot;SERIALNUM&quot; id=&quot;myhist_t1_SERIALNUM&quot;/&amp;gt;
      &amp;lt;tablecol dataattribute=&quot;STATUS&quot; id=&quot;myhist_t1_STATUS&quot;/&amp;gt;
      &amp;lt;tablecol dataattribute=&quot;LOCATION&quot; id=&quot;myhist_t1_LOCATION&quot;/&amp;gt;
      &amp;lt;tablecol dataattribute=&quot;DESCRIPTION&quot; id=&quot;myhist_t1_DESCRIPTION&quot;/&amp;gt;
      &amp;lt;tablecol dataattribute=&quot;EAUDITUSERNAME&quot; id=&quot;myhist_t1_EAUDITUSERNAME&quot; label=&quot;Changed By&quot;/&amp;gt;
      &amp;lt;tablecol dataattribute=&quot;EAUDITTIMESTAMP&quot; id=&quot;myhist_t1_EAUDITTIMESTAMP&quot; label=&quot;Changed Date&quot;/&amp;gt;
    &amp;lt;/tablebody&amp;gt;
  &amp;lt;/table&amp;gt;
&amp;lt;/tab&amp;gt;
&lt;b&gt;&amp;lt;/tabgroup&amp;gt;
...
&amp;lt;/clientarea&amp;gt;&lt;/b&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/1563459573995392819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2016/11/tracking-changes-using-audit-feature.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1563459573995392819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/1563459573995392819'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2016/11/tracking-changes-using-audit-feature.html' title='Tracking Changes using Audit feature'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGv32qUFiB9iF5sTJ1BWfZMAD-61OjdCE4GOJECk2oYJvWn9Suz_gU3f8pqAUIV9ytDkLwLsFpHKvGWOSc0V2qyK72CNybh7nCJISpZPBgPW0x7D4JxxAXm0IiZf3IJh-8PLyhvs6PuW8/s72-c/assetaudit2.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2002636098451095610.post-3769643890445485950</id><published>2016-06-03T12:18:00.001+02:00</published><updated>2016-06-03T12:23:42.962+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="intermediate"/><category scheme="http://www.blogger.com/atom/ns#" term="iot"/><category scheme="http://www.blogger.com/atom/ns#" term="mqtt"/><category scheme="http://www.blogger.com/atom/ns#" term="tutorial"/><title type='text'>Watson IoT MQTT APIs walkthrough</title><content type='html'>&lt;br /&gt;
After several experiments with IBM Watson IoT Platform I have decided to take a step back and play MQTT manually to really understand how it works. In this post I will walk through my experiments with of the Watson IoT Platform MQTT messaging API for devices, applications and gateways. &lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Prerequisites&lt;/h4&gt;
First of all you need an account on &lt;a href=&quot;http://www.ibm.com/internet-of-things/&quot; target=&quot;_blank&quot;&gt;IBM Watson IoT Platform&lt;/a&gt; on &lt;a href=&quot;https://bluemix.net/&quot; target=&quot;_blank&quot;&gt;Bluemix&lt;/a&gt;. In all cases you need to create your own &lt;a href=&quot;https://new-console.ng.bluemix.net/catalog/services/internet-of-things-platform/&quot; target=&quot;_blank&quot;&gt;Internet of Things Platform service&lt;/a&gt; and create your own device type and device. I suggest you to follow the &lt;a href=&quot;http://m2m.demos.ibm.com/iotstarter.html&quot; target=&quot;_blank&quot;&gt;IoT Starter&lt;/a&gt; tutorial if you are on familiar with Watson IoT.&lt;br /&gt;
&lt;br /&gt;
Another important preliminary step is to have an &lt;b&gt;MQTT client&lt;/b&gt; to simulate MQTT calls. I have decided to use MQTT Spy tool. &lt;a href=&quot;https://github.com/kamilfb/mqtt-spy/wiki/Downloads&quot; target=&quot;_blank&quot;&gt;Download it from here&lt;/a&gt; and have it ready on your PC. There is a very good tutorial &lt;a href=&quot;http://www.hivemq.com/blog/mqtt-toolbox-mqtt-spy&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; if you want to learn more.&lt;br /&gt;
If you don&#39;t like it you can also try &lt;a href=&quot;https://chrome.google.com/webstore/detail/mqttlens/hemojaaeigabkbcookmlgmdigohjobjm?hl=en&quot; target=&quot;_blank&quot;&gt;MQTT Lens&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;Publish event from a device&lt;/h4&gt;
&lt;br /&gt;
This is the most simple example. A device sending MQTT messages to the cloud.&lt;br /&gt;
The device must be first registered on Watson IoT Platform. On you IBM Bluemix dashboard, click on the &lt;i&gt;Internet of Things Platform&lt;/i&gt; service. Open the dashboard by clicking on the &#39;Launch Dashboard&#39; button.&lt;br /&gt;
Open the &lt;i&gt;Devices&lt;/i&gt; page and click on the &lt;i&gt;Create Device&lt;/i&gt; button. First create a Device Type and then a new Device with the following details:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Type: TestDeviceType&lt;/li&gt;
&lt;li&gt;Name: TestDev1&lt;/li&gt;
&lt;li&gt;Security token: test1234 &lt;/li&gt;
&lt;/ul&gt;
A summary page will be displayed with the device information needed for the connection.&lt;br /&gt;
&lt;br /&gt;
Now we are ready to send our first message.&lt;br /&gt;
Devices use the following identification/authentication information (&lt;a href=&quot;https://docs.internetofthings.ibmcloud.com/devices/mqtt.html&quot; target=&quot;_blank&quot;&gt;detailed documentation&lt;/a&gt;):&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Client ID in formatted as &lt;i&gt;&lt;b&gt;d:[OrgId]:[DeviceType]:[DeviceId]&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Username is &lt;i&gt;&lt;b&gt;use-token-auth&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Password is the authentication token generated during device registration&lt;/li&gt;
&lt;li&gt;Topic for publishing events is &lt;i&gt;&lt;b&gt;iot-2/evt/status/fmt/json&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Create an new connection on MQTT Spy (replace [OrgId] with your Organization ID).&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Protocol version: MQTT 3.1.1&lt;/li&gt;
&lt;li&gt;Server URI: [OrgId].messaging.internetofthings.ibmcloud.com:1883&lt;/li&gt;
&lt;li&gt;Client ID: d:[OrgId]:TestDeviceType:TestDev1&lt;/li&gt;
&lt;li&gt;Username: use-token-auth&lt;/li&gt;
&lt;li&gt;Password: test1234&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn9-mWdFr4YjiVIWHCtT4I1LQWNvd4-cvRhaAx0FXKzDg5FRyIiIdYbFqcqiR7KboTQLZCYySHXJ-t7AoZsvQyUDLUD47OTuv_hajDEl_mXb9SvKnVhlN9x2_swlLU_sveRF-tRx2M3OM/s1600/mqtt-spy-dev1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;152&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn9-mWdFr4YjiVIWHCtT4I1LQWNvd4-cvRhaAx0FXKzDg5FRyIiIdYbFqcqiR7KboTQLZCYySHXJ-t7AoZsvQyUDLUD47OTuv_hajDEl_mXb9SvKnVhlN9x2_swlLU_sveRF-tRx2M3OM/s320/mqtt-spy-dev1.png&quot; width=&quot;320&quot; /&gt;&amp;nbsp;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0FkusH1wrKxdkACXJFWsaz6yMALXmbR5IVUoz176woQbeTAf9S-Gx36SgfuCnXySPRgD0BaqaJN3M6WIc2SqM6ASgeS0qBHbFcNv8Jg3Ds1jfAEGuldGnP_nPTnfbAXS37BXAGyzOlzs/s1600/mqtt-spy-dev1-2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;152&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0FkusH1wrKxdkACXJFWsaz6yMALXmbR5IVUoz176woQbeTAf9S-Gx36SgfuCnXySPRgD0BaqaJN3M6WIc2SqM6ASgeS0qBHbFcNv8Jg3Ds1jfAEGuldGnP_nPTnfbAXS37BXAGyzOlzs/s320/mqtt-spy-dev1-2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Now you can publish the first MQTT message. &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Topic: iot-2/evt/status/fmt/json&lt;/li&gt;
&lt;li&gt;Data: {&quot;d&quot;:{&quot;status&quot;:&quot;Hello Watson IoT&quot;}}&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvSC0xvY7Q02IomZuC_p0anElYt_wb7zWLC-nsvrLpiJhKcckWj7NuqnZxzoc0pxH6ECvyOoa0MZO7gxcaoW_sDDBdI0CT-JuYEL0wU2w_KQLY9OffCFNxHOyrynmOuvkhTIUxhO64IrE/s1600/mqtt-spy-dev1-publish.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvSC0xvY7Q02IomZuC_p0anElYt_wb7zWLC-nsvrLpiJhKcckWj7NuqnZxzoc0pxH6ECvyOoa0MZO7gxcaoW_sDDBdI0CT-JuYEL0wU2w_KQLY9OffCFNxHOyrynmOuvkhTIUxhO64IrE/s320/mqtt-spy-dev1-publish.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Now open the Watson IoT device details and click on the Publish button on MQTT Spy. You should see the incoming message like this.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG6PI9R8f6z3_xeh8Unbiz3lHgR1USdGHcfA3_Skocp1z4GQY7gk6XAJxWo6RiZbORoGSxsNqb7fOFDgA1lpb9uj437G3HzHAXQIuD2XPc8dC43_1UnBooVLznSAQOFg0NWOPgleLEcxM/s1600/mqtt-spy-dev1-publish2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;242&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjG6PI9R8f6z3_xeh8Unbiz3lHgR1USdGHcfA3_Skocp1z4GQY7gk6XAJxWo6RiZbORoGSxsNqb7fOFDgA1lpb9uj437G3HzHAXQIuD2XPc8dC43_1UnBooVLznSAQOFg0NWOPgleLEcxM/s320/mqtt-spy-dev1-publish2.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;Publish event from an application on behalf of the device&lt;/h4&gt;
The Watson Iot Platform allow to define external applications that can publish events on behalf of any device and subscribe to device events. In this tutorial we will publish a message for the Dev1 device and subscribe to its events.&lt;br /&gt;
&lt;br /&gt;
We first need to define the application on Watson Iot Platform Dashboard. Open the &lt;i&gt;Access&lt;/i&gt; and &lt;i&gt;API Keys&lt;/i&gt; tab, then click on &lt;i&gt;Generate API Keys&lt;/i&gt; button. Take note of the API Key and Authentication Token.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_N05NOSOAZ1fsGG8Izpvand2EVCrqHhuF003xojoMQDH8jpS88spKc2D2pjFQZecqh2XjIomqef1MoDX_WC1pWyIQNv8px_iIYj_bi32-_OBTN4rpvSDMIqu5tS3mUnM7vUAMs0bFjuI/s1600/2-app-registration.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;144&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_N05NOSOAZ1fsGG8Izpvand2EVCrqHhuF003xojoMQDH8jpS88spKc2D2pjFQZecqh2XjIomqef1MoDX_WC1pWyIQNv8px_iIYj_bi32-_OBTN4rpvSDMIqu5tS3mUnM7vUAMs0bFjuI/s320/2-app-registration.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Applications use the following identification/authentication information (&lt;a href=&quot;https://docs.internetofthings.ibmcloud.com/applications/mqtt.html&quot; target=&quot;_blank&quot;&gt;detailed documentation&lt;/a&gt;):&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Client ID in formatted as &lt;i&gt;&lt;b&gt;d:[OrgId]:[AppId]&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Username id the API Key generated during registration&lt;/li&gt;
&lt;li&gt;Password is the Authentication Token generated during registration&lt;/li&gt;
&lt;/ul&gt;
An application can publish events as if they came from any registered device.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Topic for publishing events is &lt;i&gt;iot-2/type/&lt;b&gt;[DeviceType]&lt;/b&gt;/id/&lt;b&gt;[DeviceId]&lt;/b&gt;/evt/&lt;b&gt;[EventId]&lt;/b&gt;/fmt/json&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
Create an new connection with your MQTT client.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Protocol version: MQTT 3.1.1&lt;/li&gt;
&lt;li&gt;Server URI: [OrgId].messaging.internetofthings.ibmcloud.com:1883&lt;/li&gt;
&lt;li&gt;Client ID: a:[OrgId]:App1&lt;/li&gt;
&lt;li&gt;Username: enter your API Key&lt;/li&gt;
&lt;li&gt;Password: enter your Authentication Token&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
Now you can publish a message on behalf of device TestDev1 used before. &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Topic: iot-2/type/TestDeviceType/id/TestDev1/evt/status/fmt/json&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Data: {&quot;d&quot;:{&quot;status&quot;:&quot;Hello Watson IoT&quot;, &quot;sender&quot;:&quot;I&#39;m App1&quot;}}&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBkMo_j05g11KiSEo9juyLzutihwr2IdFcDtKG8VYwctoFhPkmNdIOUaLeIV0xJj-0quyxc-h7P3j08dJ3n8J3T8eeEmq_49V3wwrmvLRGV8Bma4swdP-oU2tw7C1QMfyRYp9V3EDyRPo/s1600/2-app-publish.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;238&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBkMo_j05g11KiSEo9juyLzutihwr2IdFcDtKG8VYwctoFhPkmNdIOUaLeIV0xJj-0quyxc-h7P3j08dJ3n8J3T8eeEmq_49V3wwrmvLRGV8Bma4swdP-oU2tw7C1QMfyRYp9V3EDyRPo/s400/2-app-publish.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
Subscribe to device events from an application&lt;/h4&gt;
&lt;br /&gt;
An application can subscribe to events from one or more devices using topic &lt;i&gt;iot-2/type/&lt;b&gt;[DeviceType]&lt;/b&gt;/id/&lt;b&gt;[DeviceId]&lt;/b&gt;/evt/&lt;b&gt;[EventId]&lt;/b&gt;/fmt/json&lt;/i&gt;&lt;br /&gt;
The MQTT wildcard character &#39;+&#39; can be used to subscribe to more than one type of event. &lt;br /&gt;
&lt;br /&gt;
On MQTT Spy subscribe to all events from the TestDev1 device using topic &lt;i&gt;iot-2/type/TestDeviceType/id/TestDev1/evt/+/fmt/json&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio5kdgD13snd81ix-fNw9LYiZ8dTNLWXdL9xMa0eOBXbIx9VI_heRpDQECUn7h1Cko3Of5IfefMFPg5occOdTe3g4flyEknFfVShVdPoayg_DKZEUou5H9m6b7zPIIC_yme_taDbUtFNU/s1600/2-app-subscribe.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;250&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEio5kdgD13snd81ix-fNw9LYiZ8dTNLWXdL9xMa0eOBXbIx9VI_heRpDQECUn7h1Cko3Of5IfefMFPg5occOdTe3g4flyEknFfVShVdPoayg_DKZEUou5H9m6b7zPIIC_yme_taDbUtFNU/s320/2-app-subscribe.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Play with MQTT Spy and see how App 1 is notified when publishing events from the device. Try changing the subscription topic as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;Gateway&lt;/h4&gt;
&lt;br /&gt;
Gateways can publish events from itself and on behalf of any device
connected to it. In this tutorial we will publish a message for the Dev1 device 
and see how it is received from the subscribed app.&lt;br /&gt;
&lt;br /&gt;
Open the &lt;i&gt;Devices&lt;/i&gt; page on your Watson IoT dashboard and click on the &lt;i&gt;Add Device&lt;/i&gt; button. First create a Gateway Type and then a new Gateway.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Type: TestGwType&lt;/li&gt;
&lt;li&gt;Name: TestGw1&lt;/li&gt;
&lt;li&gt;Security token: test1234 &lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
Gateways use the following identification/authentication information (&lt;a href=&quot;https://docs.internetofthings.ibmcloud.com/gateways/mqtt.html&quot; target=&quot;_blank&quot;&gt;detailed documentation&lt;/a&gt;):&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Client ID in formatted as &lt;i&gt;&lt;b&gt;g:[OrgId]:[GwType]:[GwId]&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Username is &lt;i&gt;&lt;b&gt;use-token-auth&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Password is the authentication token generated during device registration&lt;/li&gt;
&lt;/ul&gt;
Note that these information are very similar to the device connection 
properties but the Client ID has now a &#39;g&#39; prefix instead of &#39;d&#39;.&lt;br /&gt;
A gateway can publish events on behalf of a device.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Topic for publishing events is &lt;i&gt;iot-2/type/&lt;b&gt;[DeviceType]&lt;/b&gt;/id/&lt;b&gt;[DeviceId]&lt;/b&gt;/evt/&lt;b&gt;[EventId]&lt;/b&gt;/fmt/json&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Create an new connection with your MQTT client.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Protocol version: MQTT 3.1.1&lt;/li&gt;
&lt;li&gt;Server URI: [OrgId].messaging.internetofthings.ibmcloud.com:1883&lt;/li&gt;
&lt;li&gt;Client ID: g:[OrgId]:TestGwType:TestGw1&lt;/li&gt;
&lt;li&gt;Username: use-token-auth&lt;/li&gt;
&lt;li&gt;Password: test1234&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
Publish an event for the gateway:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Topic: iot-2/type/TestGwType/id/TestGw1/evt/status/fmt/json&lt;/li&gt;
&lt;li&gt;Data: {&quot;d&quot;:{&quot;status&quot;:&quot;Hello Watson IoT&quot;, &quot;sender&quot;:&quot;I&#39;m Gw1&quot;}}&lt;/li&gt;
&lt;/ul&gt;
Publish an event for the device:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Topic: iot-2/type/TestDeviceType/id/TestDev1/evt/status/fmt/json&lt;/li&gt;
&lt;li&gt;Data: {&quot;d&quot;:{&quot;status&quot;:&quot;Hello Watson IoT&quot;, &quot;sender&quot;:&quot;I&#39;m Gw1&quot;}}&lt;/li&gt;
&lt;/ul&gt;
Note haw the App1 subscription is receiving the events from the device. You can also try to subscribe to the gateway&#39;s events.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;h4&gt;
References&lt;/h4&gt;
&lt;br /&gt;
&lt;a href=&quot;https://docs.internetofthings.ibmcloud.com/&quot; target=&quot;_blank&quot;&gt;IBM Watson IoT Platform documentation&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.hivemq.com/blog/mqtt-toolbox-mqtt-spy&quot; target=&quot;_blank&quot;&gt;MQTT Spy tutorial&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://maximodev.blogspot.com/feeds/3769643890445485950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://maximodev.blogspot.com/2016/06/watson-iot-mqtt-apis-walkthrough-tutorial.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/3769643890445485950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2002636098451095610/posts/default/3769643890445485950'/><link rel='alternate' type='text/html' href='http://maximodev.blogspot.com/2016/06/watson-iot-mqtt-apis-walkthrough-tutorial.html' title='Watson IoT MQTT APIs walkthrough'/><author><name>Bruno</name><uri>http://www.blogger.com/profile/13748160755424198810</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn9-mWdFr4YjiVIWHCtT4I1LQWNvd4-cvRhaAx0FXKzDg5FRyIiIdYbFqcqiR7KboTQLZCYySHXJ-t7AoZsvQyUDLUD47OTuv_hajDEl_mXb9SvKnVhlN9x2_swlLU_sveRF-tRx2M3OM/s72-c/mqtt-spy-dev1.png" height="72" width="72"/><thr:total>13</thr:total></entry></feed>