Calling M3 APIs

For easy access to M3 APIs we have created a few classes that you can use both in your JScripts and in your features. For those of you who don’t know the difference, JScripts are used on a standard M3 and S3 forms to add new functionality. A feature is an application that runs natively within Lawson Smart Office. This is the way we build the UI to our applications such as M3, S3, LBI, Process Server, Document Archive… to mention a few.

I got a question from one of our Solution Consultants, Peter Johansson. He was using MIAccess to get customer data but he was experience delays due to the amount of data.

“Is there a way to specify which fields should be returned by the API?”

Of course there is!

And this is how you do it:

    private void FindCustomers(object sender, RoutedEventArgs e)
      var api = "CRS610MI";
      var trans = "LstByNumber";

      var record = new MIRecord();
      record["CUNO"] = txtCustomerNumber.Text;

      var outparms = new MIParameters
                    OutputFields = new String[] { "CUNO", "CUNM", "PHNO" }

      MIWorker.Run(api, trans, record, OnCompleted, outparms);

    private void OnCompleted(MIResponse response)
      CustomersList = new List<Customer>();

      foreach (var itm in response.Items)
        var tmpCustomerNumber = itm.GetString("CUNO");
        var tmpCustomerName = itm.GetString("CUNM");
        var tmpPhoneNumber = itm.GetString("PHNO");

        CustomersList.Add(new Customer { CustomerName = tmpCustomerName, PhoneNumber = tmpPhoneNumber, CustomerNumber = tmpCustomerNumber });

      // Databind the UI list to the response.
      lstCustomers.ItemsSource = CustomersList;

Lawson.M3.MI.MIWorker has a set or Run methods. You pass in your delegate and once the call is done your callback method, in this example OnCompleted will be called on the UIThread. In his example Peter gets the data and place it in a Customer object but you could just as well bind the datasource directly to the response.Items collection. In that case use the indexer in the same way you do in Mashups, [“fieldName”].

Happy Coding!

And a special thanks to Peter Johansson for submitting the final result to me. MIAccess is available in LSO 9.1.3.

For a richer example of Calling a M3 APIs in JScript check out this post, Validating M3 panels using JScript and MI programs before a request

40 thoughts on “Calling M3 APIs

  1. Pingback: Calling M3 APIs « M3 ideas

  2. Pingback: How to add a column to a list « M3 ideas

  3. Pingback: How to get the user password in a Smart Office script « Geiger's Counter

  4. Pingback: How to get the user password in a Smart Office script « M3 ideas

    1. Eric

      Replying to my own comment… the code below would work with JScript…

      //private void FindCustomers(object sender, RoutedEventArgs e) { // bad. This is like C# impl
      //function FindCustomers(sender : Object, e : RoutedEventArgs) { // better implmentation for JScript.Net
      //function FindDeliveryMethods(sender : Object, e : RoutedEventArgs) { // if you set up listener
      function FindDeliveryMethods() {
      var api = “CRS070MI”;
      var trans = “LstDelyMethod”;
      var record = new MIRecord();

      //var MyIntArray : int[] = new int[5];
      //var outParameters : String[] = [“CUNO”,”CUMN”,”PHNO”];
      //var outParameters = new MIParameters();
      //var outputParams = new MIParameters(new String[]{“CUNO”,”CUMN”});

      var fields : String[] = [“MODL”,”LNCD”,”TX15″,”TEL2″]; //this works
      //var fields : String[] = new String[4]; // this works too
      //fields[0] = “MODL”;
      //fields[1] = “LNCD”;
      //fields[2] = “TX15”;
      //fields[3] = “TEL2”;
      var outParameters = new MIParameters(fields);

      MIWorker.Run(api, trans, record, OnCompleted, outParameters);

      private function OnCompleted(response : MIResponse) {

      //CustomersList = new List(); // C# not JScript.Net

      //foreach (var itm in response.Items) { // this is VB programming ; just use for-loop
      for (var itm in response.Items) {
      var tmpDeliveryMethod = itm.GetString(“MODL”);
      var tmpLanguage = itm.GetString(“LNCD”);
      var tmpName = itm.GetString(“TX15”);
      var tmpFedExCode = itm.GetString(“TEL2”);
      debug.WriteLine(“MODL: “+tmpDeliveryMethod+”,\tLNCD: “+tmpLanguage+”,\tTX15: “+tmpName +”,\t TEL2 – FedExCode: “+tmpFedExCode);
      //CustomersList.Add(new Customer { CustomerName = tmpCustomerName, PhoneNumber = tmpPhoneNumber, CustomerNumber = tmpCustomerNumber });

      // Databind the UI list to the response.
      //lstCustomers.ItemsSource = CustomersList;

    2. karinpb Post author

      Hi, There are many examples on the blog the uses M3 APIs, so check those for JScritp syntax. Here is one
      Or – perhaps better – check MSDN JSCript reference giude:
      And one note on your solution – the code on this blog is never VB :-). It could have been (becuase VB has foreach) -but is isn’t.

  5. Amr Nabil

    I am new to Lawson and have a programming back ground. What do i need to start Lawson JScripting and where do i write this code??

    Thanks very much for your help.

    1. karinpb Post author

      You write the code within Smart Office itself in the JScript tool.

      The user’s Role (assigned in Security User Maintenance and maintained in ISO Role Manager) must have ‘Allow Scripting’ set.
      Then user will see Script Tool under Lawson Transactions -> Other or enter “sforms://jscript”

      Start by reading the Lawson Developers Guide found on the Infor Info Center (that is a server were you can install documentation).

    1. karinpb Post author

      I assume you mean M3 APIs.

      You can always run MRS001 to look in the repository. The same information is also visible in the serverview under tools (that is in the grid management pages for M3). You might not have access to those. There are some tools in the Toolkit (M3 APIS) that allow you to set up a web server with all the programs and transactions which is a nice way of browsing the API. The toolkit also has a help file in Windows html help format. This is all M3 API stuff and has nothing to do with Smart Office. In smart Office you can see what API are available in mforms://mitest or when you add a MIPanel in a Mashup since they all read the Repository (MRS001), but for browsing I recommend downloading the API Toolkit.

      We don’t provide a public online resource of APIs.

    1. karinpb Post author

      In that case you can use the M3.Client.MIAccess.Execute() directly. I’m not sure if the overloads the execute method has will prevent the JScript from determine which method to call. That could be an issue. Please try and let me know how it goes. But if you are writing C# code that is the class to use for accessing the APIs if you are on a Background thread already. I have also seen (unsupported use) of the MIDataService class that is used from DataPanels in Mashups where MI is the datasource.

      In either case it will throw an exception if you are not on a background thread.

      1. doublemcz

        It Works! 🙂 MIAccess.Execute is great. It must be in different thread from main thread but this is the situation I am talking about. I am actually in own thread so this “Magic” method is absolutelly worth! Thank you.

  6. olaborde2015

    I search an API to recover all the VAT of an order based on M3 rules. Our VAT are not managed in the lines of the order (all VAT code = 1) but are handled differently. (Customer location …)

    thanks very much for your help

    1. karinpb Post author

      I’m sorry but this is a M3 functionality question that I’m unable to answer since I work on the technology development side of Infor and not M3 Core development. I suggest you ask the question to Infor Support.

  7. deepm3

    Hi Karin,

    Is there a way to get erroneous input field from MIResponse after MI request gets error from M3?
    Ex. If I get error from M3 as “Transaction number &1 does not exist”, then I would like to get “TRNO” (error field) from somewhere.

  8. deepm3

    Hi Karin,
    Any idea on the below query posted earlier?
    Is there a way to get erroneous input field from MIResponse after MI request gets error from M3?
    Ex. If I get error from M3 as “Transaction number &1 does not exist”, then I would like to get “TRNO” (error field) from somewhere.

  9. karinpb Post author

    Hi deepm3,
    Sorry for my late reply. I’m not sure of the context of the call. For mashups there is no way to get the TRNO but I have an enhancement ticket on improving the error handling which means I’ll add an error event and then I can make sure that TRNO is accessible. But in the case of the Mashup MIPanel the panel will show a dialog. If you are using the MIAccess classes in script or in the SDK the TRNO can be retreived from the MIResponse using: MIResponse.ErrorMessage – but that can also be a timeout exception or another error so you can’t be sure it is a M3 message.

    You could try and use MIResponse.Item[“TRNO”] as well. I’m not sure the REST implementation returns a result string in the same way as the traditional API – but if it does TRNO will be available in the first item in the response. Note that Item can be null as well if there are no errors and the transaction don’t return anything.

    1. deepm3

      Hi Karin,
      Thank you for your response. The context of this call of API is from ISO SDK developed client. When do you think we will get this API error event enhancement implemented in ISO SDK? In SDK we have MIResponse.Error, MIResponse.ErrorCode & MIResponse.ErrorMessage. What’s missing is MIResponse.ErrorField. This is where I can expect to get the field where error has occurred. Is it possible to include this field name easily and quickly as a hotfix in ISO so that our project gets a closure on this issue?

      Thank you once again.

      1. karinpb Post author

        I did a quick test run and it seems like there is an ErrorField that we don’t set on the Response from the Exception we get. What MIProgram and transaction are you using that sets this?

        <soap:Envelope xmlns:soap=""><soap:Body><soap:Fault><faultcode>soap:Server</faultcode><faultstring>Customer Hej does not exist                                                                                                                                                                                                                      WCU0203           </faultstring><detail><MITransactionException xmlns=""><errorType>ServerReturnedNOK</errorType><errorCode>WCU0203 </errorCode><errorCfg>  </errorCfg><errorField>          </errorField></MITransactionException></detail></soap:Fault></soap:Body></soap:Envelope>

        As for fixes – a new version of the SDK can be requested but it follows the scheduled delivery of fixes. We can give previews of the SDK for testing purpose but it would have to go via official support channels. Note that new enhancements are only done on 10.2.1 at this time. The SDK is usually not included so you would still need to request it from support. Start with entering an enhancement request for the errorField in MIResponse.

      2. deepm3

        Hi Karin,

        You can use CRS610MI/LstByGroup and input a non-existent company. You should get error field as “CONO” and the obvious error message.

      3. deepm3

        Hi Karin,
        Thank you for registering enhancement request. I will wait for next release of hotfix for ISO 10.2.1. So in this release should I expect to access error field as MIResponse.ErrorField?

      4. deepm3

        Hi Karin,
        Could you please let me know your enhancement request ID? I would like to register this ID with our issue report and follow up through Infor support.

      5. karinpb Post author

        It’s not an official enhancement request but an internal JIRA ticket that we use. You should simply but that you need to follow and have an SDK delivery for JIRA: UID-22443: Add MI result TRNO to MIResponse.ErrorField.

  10. justAskin

    Hi, we would like to validate the M3 user’s role assignment (MNS410) via jscript. I’m able to retrieve the user ID but now need to check if that user ID belongs to a specific M3 role before the user can proceed/hit next on the M3 panel to which we’re implementing the jscript.

    Would you have a specific sample in jscript of how to retrieve the user’s M3 role given the M3 user ID? Our MNS410MI only has one transaction available and it doesn’t include the userID, it just lists roles.

    Also, like the user ID, cono, and divi fields, is there also a standard m3 field for the m3 user role?

    Your feedback will be appreciated.

    1. norpe

      If you are logged on to M3 from Smart Office (at least one program is started) the M3 roles for a user are available in the property MForms.UserContext.Roles. Note that the MForms Application Setting “Use M3 roles” must be enabled as well, otherwise the roles will not be loaded. See code example below.

      import System;
      import System.Windows;
      import System.Windows.Controls;
      import MForms;
      package MForms.JScript {
          class ListRoles {
              public function Init(element : Object, args : Object, controller : Object, debug : Object) {
                  var roles = UserContext.Roles;
                  if (roles.Count == 0) {
                      debug.WriteLine("No roles found");
                  for (var i = 0; i < roles.Count; i++) {
                      var role = roles[i];
                      debug.WriteLine("Role: " + role.Role + " Name: " + role.Name + " Description: " + role.Description);
  11. deepm3

    Hi Karin,
    Is there a way to disable M3 API receive timeouts in SDK? I have a custom developed API that requires interactive processing of large jobs. If this API takes long time to process (ex. 2 mins) then MIWorker times out. Could please give an example on how to disable receive timeouts programatically? Thank you.

    1. karinpb Post author

      Hi, You need to call MIAccess.Execute(“program”,”transaction”, mirecord, miparameters). The mirecord is the input as usual and the MIParameters class is the miparameters parameter. It has different TimeSpan that you can set. Eg, ConnectTimeOut and ReceiveTimeout.

              var inputRecord = new MIRecord();
              inputRecord["PAVR"] = currentView;
              inputRecord["PGNM"] = panelState.ProgramName;
              inputRecord["PIC1"] = panelState.PanelNavigator.PanelLetter;
              var param = new MIParameters { MaxReturnedRecords = 5000, ConnectTimeout = new TimeSpan(0,0,5,0),ReceiveTimeout = new TimeSpan(0,0,15,0)};
              var response = MIAccess.Execute("CRS020MI", "LstAllColumns", inputRecord, param);
              if (response.HasError)
                Logger.Warn("Transaction failed", response.Error);
                return false;
  12. wendra arinegara

    Hi, Karin, is M3 API support paging on retrieving large record? For example I have 1000 records to be retrieve but I want to retrieve 100 at a time so the first request will retrieve records #1..100, the second records will retrieve records #101..200 and so on…

    1. karinpb Post author

      Hi Wendra,
      The list API supports paging in an indirect way. For the list APIs you can use the last entry in your result as input to the next request. In that result set you will get the last line again so you need to skip it and then continue until you only get a single entry back which is the item you sent in as input. It’s a little bit of work and not a clean design but the APIs are very dynamic in terms of what data you have as input so this approach will work as long as you are writing script or code against the API. If you set max records to 100 it till look like this:
      – get record 1..100
      – take the last record and use the mandatory fields from that record as input to the list API again
      – You will get record 100…200. Skip the first record as you already have record 100. If you have 100 new records you need to get a new pages set, if you have 88 record there are no new records
      – if you get a new records and there is only one you have all records

  13. bm

    Hi Karin,

    I have developped a specific transaction in OIS100MI but when I try to use it in a jscript I get following error: “Transaction xxxx not found in program OIS100MI”
    Does it mean that we can’t use specific API transaction in script?

    Remark :
    – My specific transaction is present in MRS002 and MRS003. (this is added by the specific program)
    – When I launch MITest it works good.
    However when I use it in ISO thru mforms://mitest, I get same error message.

    So I’m wondering if it’s possible to use specific API transaction in jscript.

    1. deepm3

      Hi bm,
      After modifying MRS001 and/or MRS002 and/or MRS003 with your new API program and/or transaction and/or I/O field you must clear smart office metadata cache. This can be done by launching mforms://mitest and then click Tools->Clear Metadata Cache. Your issue will be resolved after doing this.

      Hi Karin,
      Perhaps as smart office enhancement, in smart office sdk for MI one could trap such error and try (just one iteration) to refresh metadata cache for only requested MI program before returning back with this error.

      1. karinpb Post author

        Hi deepm3,
        It’s an interesting enhancement suggestion. But we can’t do it just for the SDK. If there is a specific exception then it might be possible to do the enchangement. But it is not enough to just check the message. Please add a support request if this is important to you. This is only an issue for SDK / Mashup developers and a restart of Smart Office would also fix this.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s