Clear global customization cache

Here is a refresher on how to clear global M3 personalizations for non-administrators:

mforms://_command/?value=clear custcache

M3 personalizations

I am currently doing maintenance of M3 personalizations (hyperlinks, conditional styles, shortcuts, labels, tab orders, views, show/hide fields, and scripts), for all users (role GLOBAL_CUSTOMIZATIONS):
2

Maintenance

To change a personalization, either I use the Personalization Manager (for that I need the administrator role), or I change the file with a text editor directly in the MNEDATA folder (for that I need read/write access to the MNEDATA folder):
4
3

Clear customization cache

To clear the global customization cache, I use the Net Extension Manager > Clear customization cache (for that I need to be administrator):
5

Non-administrators

There is another environment where I am not administrator, there is no Net Extension Manager, and yet I need to clear the global customization cache. I realized I can simply execute the clear command, and it will clear the global customization anyway:

mforms://_command/?value=clear custcache

6

7

That’s the actual command behind the Clear button.

I traced the calls, from the Smart Office Dlls, to the MNE server Java classes, and it seems to really do a global clear, even without being administrator:

MForms.dll
MForms.Services.Applications.Admin.NetExtensionManager.IComponentConnector.Connect
MForms.Services.Applications.Admin.NetExtensionManager.OnClickClearCustCache

mne-app-10.2.2.0.jar
com.intentia.mc.command.RunCmd.doChangeEnvironment
com.intentia.mc.mgmt.ServerMgr.clearCustomizationCache
com.intentia.mc.customization.CustomizationManager.clearCentralCache

Maybe there’s a good explanation for the lack of authorization; or maybe I am administrator somewhere afterall. I haven’t read the administrator’s guide or looked any further.

That’s it!

Related posts

Who is the author of an M3 mod?

Today I needed to find who is the developer of an M3 customer modification. There is a bug in the MForms Bookmark of program M3 Customer. Connect Addresses – OIS002 which the developer modified for our customer’s needs, and I needed to report the bug to that developer. But I do not have the MAK training nor tool, so I cannot easily see the list of modifications and their authors. My colleague Shashank remind me of the following answer in M3 Server View.

  1. Go to M3 Server View (from the Grid Management Pages, or from LifeCycle Manager):
    0
  2. Find the interactive subsystem that is running the program (in my case OIS002), and select Tools:
    1
  3. Select Find Class:
    2
  4. Search for the M3 program (in my case OIS002):
    3
  5. The line with the customer class will give the file path, version, author, date, and unique ID (in my case I found the author, Rajesh):
  6. Note: Up to here, we can access this page anonymously, without being an authenticated user nor an administrator (security vulnerability anyone?)
  7. Now, if we have access to the M3 Business Engine file system, we can open the file itself and see the full list of developers; in my case the file is at:
    D:\Infor\M3BE\env\M3BE_15.1_TST\Fix\CUS\VFix\src\mvx\app\pgm\customer\OIS002.java:
    5

That’s it.

Let me know in the comments below if you have other tips. Click Like. Share this post with your colleagues. Click Follow to subscribe. And come write the next blog post with us. This is a volunteer-based community, and your participation keeps this blog going. And send some love to the other M3 blogs too. Thank you.

Poll: How to add 80 million item/warehouse records in M3?

My customer is doing data conversion in preparation for go live, of which 80 million item/warehouse records, they want to complete the upload over a week-end, but M3 is being a bottleneck, i.e. it cannot absorb the data as fast as they are feeding it to.

What would you do? I am not an expert at item/warehouse, nor at M3 performance, and from what I have seen in the past, each project handles it at their own sauce.

Synopsis

My customer has about 80,000 items to add to MMS001, and each item needs to be connected to about 1,000 warehouses in MMS002.

The result is about 80 million item/warehouse records to create.

M3 can handle gazillions of records. So this should be a piece of cake, right?

Failed tentative 1

Because the M3 API MMS200MI does not cover all the fields, my customer initially used M3 Web Services (MWS) of type M3 Display Program (MDP) to simulate a user entering data in all the desired fields.

It takes about 10ms per record, or 100 records per second. Loop 80 million times, and that would take about 800ks, which is about 222h, which is about 10 days to complete.

Yikes!!! 10 days to upload???

We need faster. We need one or two orders of magnitude faster.

Failed tentatives 2, 3, 4

I did A/B testing of various alternatives:

  • Use MWS MDP, versus use M3 API (I thought this would be the silver bullet, nope)
  • Create the item from scratch, versus create the item from an item template
  • Call the Add transaction, versus call the Copy transaction
  • Let M3 auto-create (we create the item oursleves but let M3 auto-create the item/warehouse), versus manually create (we create both ourselves).
  • Remote Desktop Connect inside the M3 BE server or database server to avoid any potential network issues
  • etc.

Either way, we only get a marginal, insignificant benefit in some cases, but the order of magnitude is equally bad.

Concurrency

Then, I decided to create the records concurrently (in parallel) rather than sequentially (one after the other).

With the help of some command line Kung fu I was able to automatically split my big CSV file into 80 smaller chunks, create 80 M3 Data Import (MDI) descriptions, and run 80 parallel threads that each upload one million records:
poll2

It turns out M3 can comfortably handle the throughput. It created many jobs in the API subsystem to process the records in parallel:
poll

Each job takes about 1% CPU. So that should max out the server to about 80% CPU utilization.

However, M3 seems to have capped well before the 80 jobs. I guess that is Amdahl’s law of maximum expected performance in parallel computing.

The result was about 1,100 records per second, which would complete in about 20h, less than a day. That is one order of magnitude improvement!!!

With some more benchmarking we could plot the curve of Amdahl’s performance and find the optimum number of jobs and have a pretty accurate estimate of the expected duration.

I also automatically generated a cleanup script that deletes everything, and I noticed the delete takes four times longer than the add.

Reality check

By the time I had come up with my results, the customer had completely changed strategy and decided to upload the records directly with SQL INSERT. [Cough] [Cringe] <your reaction here>. They consulted with some folks at Infor, and apparently it is OK as long as the data has been pre-validated by API or by MWS MDP, and as long as M3 is shut down to avoid collisions with the M3 SmartCache. It is important to get clearance from Infor as SQL INSERT will void your Infor Support warranty.

Future work

I have also heard of the Item Data Interface (IDI) and the Warehouse Interface (WHI). I do not know if those could help. To be explored.

Poll

What would you do? How have you uploaded millions of records at once? Leave me a comment below.

Disclaimer

Do not take these results as a reference. I was just providing some help to my customer and to the colleagues that are handling this.

I am not a reference for item/warehouse in M3, and I am not a reference for M3 performance, there are special teams dedicated to each.

Also, these results are specific to this customer at this time. Results will vary depending on many factors like CPU, memory, disk, tweaks, etc.

Experimenting with middle-side modifications

With Infor M3, there are server-side modifications, client-side modifications, and the unexplored middle-side modifications. I will experiment with servlet filters for the M3 UI Adapter.

Modification tiers

There are several options to modify M3 functionality:

  • Server-side modifications are M3 Java mods developed with MAK; they propagate to all tiers, including M3 API, but they are often avoided due to the maintenance nightmare during M3 upgrades, and they are banned altogether from Infor CloudSuite multi-tenant. There are also Custom lists made with CMS010 which are great, they are simply configured by power users without requiring any programming, and they survive M3 upgrades.
  • Client-side modifications for Smart Office are Smart Office scripts in JScript.NET, Smart Office SDK features, applications and MForms extensions in C#, Smart Office Mashups in XAML, and Personalizations with wizards. They do not affect M3 upgrades but they apply only to Smart Office. And client-side modifications for H5 Client are H5 Client scripts in JavaScript, and web mashups converted from XAML to HTML5. Likewise, they do not affect M3 upgrades but they apply only to H5 Client.
  • Middle-side modifications are servlet filters for the M3 UI Adapter. They propagate to all user interfaces – Smart Office AND H5 Client – but this is unexplored and perilous. In the old days, IBrix lived in this tier.

M3 UI Adapter

The M3 UI Adapter (MUA), formerly known as M3 Net Extension (MNE), is the J2EE middleware that talks the M3 Business Engine protocol (MEX?) and serves the user interfaces. It was written mostly single-handedly by norpe. It is a simple and elegant architecture that runs As Fast As Fucking Possible (TM) and that is as robust as The Crazy Nastyass Honey Badger [1]. The facade servlet is MvxMCSvt. All the userids/passwords, all the commands, for all interactive programs, for all users, go thru here. It produces an XML response that Smart Office and H5 Client utilize to render the panels. The XML includes the options, the lists, the columns, the rows, the textboxes, the buttons, the positioning, the panel sequence, the keys, the captions, the help, the group boxes, the data, etc.

For example, starting CRS610/B involves:
com.intentia.mc.servlet.MvxMCSvt.doTask()
com.intentia.mc.command.MCCmd.execute()
com.intentia.mc.command.RunCmd.doRunMovexProgram()
com.intentia.mc.engine.ProtocolEngine.startProgram()

The following creates a list with columns:

import com.intentia.mc.metadata.view.ListColumn;
import com.intentia.mc.metadata.view.ListView;

ListView listView = new ListView();
ListColumn listColumn = new ListColumn();
listColumn.setWidth(length);
listColumn.setConstraints(constraints);
listColumn.setCaption(new Caption());
listColumn.setConditionType(1);
listColumn.setHeader(headerSplitterAttr);
listColumn.setName("col" + Integer.toString(columnCount));
listColumn.setJustification(1);
listColumns.add(listColumn);
listView.addFilterField(posField, listColumn);
listView.setListColumns((ListColumn[])listColumns.toArray(new ListColumn[0]));

Here is an excerpt of the XML response for CRS610/B that shows the list columns and a row of data:
Fiddler

Experiment

This experiment involves adding a servlet filter to MvxMCSvt to transform the XML response. Unfortunately, MNE is a one-way function that produces XML in a StringBuffer, but that cannot conversely parse the XML back into its data structures. Thus, we have to transform the XML ourselves. I will not make any technical recommendations for this because it is an experiment. You can refer to the existing MNE filters for examples on how to use the XML Pull Parser (xpp3-1.1.3.4.O.jar) that is included in MNE. And you can use com.intentia.mc.util.CstXMLNames for the XML tag names.

To create a servlet filter:

/*
D:\Infor\LifeCycle\host\grid\XYZ\runtimes\1.11.47\resources\servlet-api-2.5.jar
D:\Infor\LifeCycle\host\grid\XYZ\grids\XYZ\applications\M3_UI_Adapter\lib\mne-app-10.2.1.0.jar
javac -cp servlet-api-2.5.jar;mne-app-10.2.1.0.jar TestFilter.java
*/

package net.company.your;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import com.intentia.mc.util.Logger;

public class TestFilter implements Filter {

    private static final Logger logger = Logger.getLogger(TestFilter.class);

    public void init(FilterConfig filterConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (logger.isDebugEnabled()) {
            logger.debug("Hello, World");
        }
        chain.doFilter(request, response);
    }

    public void destroy() {}

}

Add the servlet filter to the MNE deployment descriptor at D:\Infor\LifeCycle\host\grid\XYZ\grids\XYZ\applications\M3_UI_Adapter\webapps\mne\WEB-INF\web.xml:

<filter>
    <filter-name>TestFilter</filter-name>
    <filter-class>net.company.your.TestFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>TestFilter</filter-name>
    <servlet-name>MvxMCSvt</servlet-name>
</filter-mapping>

Then, reload the M3UIAdapterModule in the Infor Grid. This will destroy the UI sessions, and users will have to logout and logon M3 again.

Optionally, set the log level of the servlet filter to DEBUG.

Limitations

MvxMCSvt is the single point of entry. If you fuck it up, it will affect all users, all programs, on all user interfaces. So this experiment is currently a Frankenstein idea that would require a valid business case, a solid design, and great software developers to make it into production.

Also, changes to the web.xml file will be overriden with a next software update.

Discussion

Is this idea worth pursuing? Is this another crazy idea? What do you think?

How to create a picking list in M3

As part of my Google Glass project to display Infor M3 picking lists on Glass, I had to learn how to easily create picking lists in M3. M3 is a comprehensive Enterprise resource planning (ERP) suite that does customer sales, supply chain, manufacturing, inventory, packing, shipping, accounting, and many other functions. It takes learning and practice to conquer it. I’m a technical consultant for M3, not a functional consultant, so I had to ask for help for the setup to create picking lists. My dear colleagues Philip Cancino, M3 Business Consultant – SCM at Infor in Manila, and Marie-Pascale Authié, Fashion Solution Consultant at Infor in Chicago generously helped me.

I recorded Philip’s and Marie-Pascale’s instructions and the final setup, and I’m sharing the results here so you can follow my Glass project along. Watch the videos in full screen and in high definition to see the small details. Also, Philip’s video has audio, and I transcribed it, so you can turn on closed captioning (CC) if needed; the other videos don’t have audio.

Philip’s instructions and demo

Philip showed me detailed instructions to create a picking list on one of the Infor Education servers that was already setup for Manufacturing, and we recorded a demo.

Philip’s instructions are:

  1. Create a customer order in M3 Customer Order. Open – OIS100
  2. Create order lines in M3 Customer Order. Open Line – OIS101
  3. Select the order > Related Options > Delivery Toolbox CTRL+43; it takes us to M3 Delivery. Open Toolbox – MWS410
  4. Select the delivery > Related Options > Release for Picking CTRL+32
  5. Refresh until Released for Picking RIP = 1; it can take a while for the auto-jobs
  6. Back in OIS300, the order will change to Status 44
  7. Back in MWS410, select the delivery > Related Options > Picking Lists CTRL+11; it takes us to M3 Picking List. Report – MWS420
  8. Select the picking list > Related Options > Pick List Lines CTRL+11; it takes us to M3 Picking List. Report Lines – MWS422
  9. It shows the picking list lines with item numbers, quantities, and stock locations; this is what I need for Google Glass
  10. Select one line at a time > Related Options > Confirm Issues CTRL+16, that’s what the picker will do on Google Glass to complete the pick list
  11. When all the picking list lines have been confirmed, the picking list and the delivery will change to status 90, and the order will change to status 66.

Here is Philip’s demo:

Back to basics

After Philip’s demo, I wasn’t able to reproduce the instructions on another server that had a different setup for Equipment service management and rental (ESM&R). So Marie-Pascale helped me setup that other server. She setup everything from scratch, mostly copying from existing records, then going back and forth adjusting what was important for my project until it was working as desired.

Setup 1/4 – configuration tables

First, Marie-Pascale set up of the configuration tables company, division, facility, warehouse, and stock locations:

  • M3 Company. Open – MNS095
  • M3 Company. Connect Division – MNS100
  • M3 Facility. Open – CRS008
  • M3 Warehouse. Open – MMS005
  • M3 Stock Location. Open – MMS010:
    • In panel B we set the Warehouse (WHLO) and the Location (WHSL)
    • In panel E we set the Name (TX40) of each location to the respective aisle, rack, and bin
    • In panel F I will later set the Geo codes XYZ based on my previous work Geocoding of Stock Locations in MMS010.

Here is my quick walkthrough of the result (pause the video as needed):

Setup 2/4 – order type

Then, Marie-Pascale set up the all-important order type, and she chose a fast order type that automatically allocates inventory, creates a picking list, and does not require packing nor shipping:

  • M3 CO Type. Open – OIS010:
    • Allocation method: 1-Automatic/manually
  • M3 CO Type. Connect Documents – OIS011:
    • Print document: Yes
  • M3 CO Type. Update Field Selection – OIS014:
    • Route: blank
    • Route departure: blank
    • Contact method: phone
  • M3 Dispatch Policy. Open – MWS010:
    • 030 Released for allocation: Yes
    • 040 Released for picking: Yes
    • 100 Auto print of picking lists: Yes
    • 160 Shipment assembly point: 9-Not used
    • 240 Packing reporting method: 0-Packing not used
    • 330 Automatic connection to shipment: 0-No auto connect

Here is the result:

Setup 3/4 – items and inventory

Then, Marie-Pascale setup the items and inventory:

  • M3 Item. Open – MMS001:
    • Status: 20-Released
    • Responsible
    • Make/buy code: 2-Purchased
    • Lot control method: 0-Not used
    • Lot numb method: 0-Manual entry
    • Purchase price
    • Sales price
    • Supplier
  • M3 Item. Connect Warehouse – MMS002:
    • Planner
    • Acquisition code: 2-Purchased
    • Status: 20-Released
    • Location
  • M3 Item. Connect Facility – MMS003
  • M3 Physical Inventory. Quick Entry – MMS310:
    • Warehouse
    • Item number
    • Location
    • Physical inventory quantity (STQI)
    • Status – ph inv (STAG): 1-Auto approved

Here is the result:

Setup 4/4 – customer and supplier

Then, Marie-Pascale the setup of the customer and supplier:

  • M3 Customer. Open – CRS610:
    • Status: 20-Definite
    • Order Type
    • Warehouse
  • M3 Supplier. Open – CRS620

Here is the result:

Final demo

And finally, here is the quick demo to create a customer order and get the picking list with item numbers, quantities, and stock locations to display in Google Glass:

And here is a screenshot of the final picking list:
result

They are the same steps as Philip’s, except now everything is automatic: allocation and picking are automatic, and there’s no packing nor shipping.

We had a problem with automatic allocation though, it failed, and we had to allocate manually in M3 Allocation. Perform Detailed – MMS121. Marie-Pascale said she will look into it.

Future work

Next, I will capture the event that creates the picking list, and I will gather more information about the Items, like names, and I will send the formatted picking list to Glass. For that, I will use Event Analytics and Infor Process Automation (IPA) and the Glass API.

 

That’s it!

Special thanks to Philip Cancino and Marie-Pascale Authié for making this possible. I wouldn’t have been able to progress without your help.

Subscribe to this blog to follow my Google Glass adventures. Comment. Share. Enjoy.