JScript Feedback

We would like to get feedback from all JScript developers.

What kind of utility methods have you developed? What kind of information do you need from the M3 panels?
If you are looking for stuff in the visual tree, what are you looking for, can we provide you with an API since accessing stuff in the visual tree is not supported and might brake in coming releases?

How can we help you be more productive?
Please describe the scenario and what you would like to do with the JScript. Reply by entering a comment.

142 thoughts on “JScript Feedback

  1. José Ramon

    Hi,
    I’m trying to program a script that changes the looks of a row in a listview.
    In panel MWS060 I want to make easier for the user see the different warehouses for the same item, i.e. changing the color of the row, or the font…
    I’m obtaining the Container Generator and then changing properties:

     
    listViewItem = listView.ItemContainerGenerator.ContainerFromIndex(i);
    listViewItem.Background = color;
    

    But seems a lot of programming, I have to control when the ContainerFromIndex can be applied, control the scrolling on the listview, keeping temp values for the warehouses to compare them with the rest of the rows… and not sure if that’s the best way to do it (if possible).

    Thanks.

    Reply
  2. Jose Ramón

    Hi again :).
    It’s clear now how to change the looks of the row but in the script I’m working I need to set different templates according to values for the previous row.
    Can I set different templates depending on values of the previous row?, like if previous row has column[2] = ‘some_string’ then the template is templateGreen, otherwise templateRed?.

    Thanks.

    Reply
    1. karinpb Post author

      In the SelectTemplate method you can use the name property on the item to get the Row name of the current row.

      var rowName = item.Name; // r1, r2 etc. To get the row index substring the name to get the number eg, r3->3-1=2-> current row index.

      Then get the previous row:
      var previousRow = listView.Items[currentRowIndex-1] (don’t forget checks if you are on the first row).

      Reply
  3. Lode Vlaeminck

    Hi, I would like to know how i can acces the browse popup when you press F4 on a field to limit the value that can be selected

    Reply
    1. Lode Vlaeminck

      I found it, but now my script is running in an other program. how do i end the script and keep it inside 1 program ?

      Reply
      1. karinpb Post author

        I’m afraid there is not enough information for us to help you. You should be very careful when running scripts to make sure the script is unloaded and all event handles are removed, once you leave the program.

  4. Jim Stewart

    Currently planning an upgrade from 7.1 to 13.2(3). I am trying to avoid recreating extension tables and modifications to the Java source. I’m thinking JScript is the way to go but can’t find a great example that does this, or even if its possible. I am basically trying to replace the code in PEDSP,PECHK,PEPMT,PEUPD. I’m trying to update CUGEX1 using apis AddFieldValue and ChgFieldValue. For instance I have a custom table with “Assignment Type” and “Bank for Season”. Assignment type is a field I need to prompt 4 (or have in a list view as I only have a few), Bank for Season is a check box. I’d need to protect the fields in Display mode. I do not own Mashups which may make the F4 tricky from what I’ve found so far. Any awesome great examples would be appreciated, or am I trying to take this one step too far.

    Reply
    1. karinpb Post author

      Hi, I would think that trying to replace code in PEDSP,PECHK,PEPMT,PEUPD is taking it too far but perhaps not it applies to only showing a field or two in one panel. But as you mention that you would need to Browse(F4) for it – then it requires validation as well – probably with an API. For the F4 you would need a Mashup (possibly with enterprise search).

      Even if you don’t have Mashups (so you can’t build new ones – perhaps there is an existing Mashup that you can use or perhaps a partner can help?). You can use the Mashup runtime without having the Mashup Designer at least as far as I understand. Mashups are great and you should definately consider adding it. We don’t have a full example like that and it depends on all the available functions and the specific program as well. There is one about validation that would help and one that has the custom browse example.

      Reply
  5. Mark

    Hi,

    I am working on a custom screen using Jscript in M3 and I am having trouble with the text validation.

    Here is my problem:

    I am validating two parameter fields in a custom form using JSCRIPT and the error should be ” Input parameter 1 is missing, please fill value” and Input Parameter 2 is missing, please fill value”

    It seems that the program is validating all fields even if the input parameter 1 field is not yet filled. What I want in my program is to validate my first parameter. Once I have the provided a value on that parameter, then that is the only time the 2nd validation will be processed.
    Basically, I dont want my program to proceed to another validation or action until my 1st parameter has been validated.

    I am sorry. I am just newbie in Jscript and M3. I Hope you can help

    Mark

    Reply
    1. karinpb Post author

      I’m not sure I fully understand your scenario. As it involves validation I’m assuming that you would like to do the validation as the user press next to go to the next screen. Thus the request is already submitted so you would need to always cancel that request – perform your jscript validation – and then trigger the “next/enter/submit” action in the background if both input1 and input2 is valid. This kind of script that spans requests is complex as in most cases you will end up not detaching events correctly with the script running in multiple instances on the same panel as a consequence. I would not recommend this to a newbie wihout assistance from an experienced jscript developer. Check the validation example since you don’t need to call an MI program your scenario would be easier that this one.

      Reply
      1. Mark

        Hi,

        Thanks for the reply but I already saw the solution from the same link. Cool!

        Can I ask you another question?

        I am working on this particular custom screen using jscript via Smart office that will trigger a flow. The custom screen contains 20 parameter/input fields and will be used by PFI (thru service variable definition) when the flow is triggered from custom form.

        Unfortunately, I am encountering an internal server error and it seems that PFI doesn’t allow us to process more than 15 service variables names.

        Have you encounter this issue before? If yes, what alternative solution do you propose if we have more than 15 service variables needed in the flow?

        Error:
        TEST Master Setup %26varName[0]=Company%26varValue[0]=1%26varName[1]=Division%26varValue[1]=010%26varName[2]=UserId%26varValue[2]=test%26varName[3]=RequestedBy%26varValue[3]=DEV%26varValue[3]=TEST TEST%26varName[4]=CurDate%26varValue[4]=Mon Mar 2 16:37:49 EST 2015%26varName[5]=VendorRequest%26varValue[5]=%26varName[6]=VendorName%26varValue[6]=%26varName[7]=Address1%26varValue[7]=%26varName[8]=Address2%26varValue[8]=%26varName[9]=TelNum%26varValue[9]=%26varName[10]=FaxNum%26varValue[10]]=%26varName[11]=ContactDtl%26varValue[11]=%26varName[12]=ProdDtl%26varValue[12]=%26varName[13]=DateDtl%26varValue[13]=%26varName[14]=AmountDtl%26varValue[14]=%26varName[15]=AnnTranDtl%26varValue[15]=test
        Error: The remote server returned an error: (500) Internal Server Error

        And last question, how do you validate the checkbox if its checked or unchecked in jscript?

        Thanks again!

  6. Maxric

    Hi to all,

    I would like to submit you a problem i am not able to solve on a script running in a single panel A (no list).
    The panel is used to create packages in a customer order by flashing bar codes; the data red by the mobile device (data acquisition) is written into an input field on the panel and the device adds the ENTER key at the end. So each time we flash something, the javex program validates the data.
    – if the data is correct, we can continue (the input field is cleared and the cursor has focus on it so that the next flash will fill up the input field with new data)
    – if the data is incorrect, the error message is displayed in a classic errorTextBox. The problem is that the user is not always in front of the screen and he is not aware of the error if there is one : here comes the script.

    On the next ENTER (i.e. on the next OnRequesting event), if the errorTextBox.Text is not blank, then the screen is changed in red, the error message is enlarged in a bigger textBox and a sound is provided to alert the user. The curor focus is not any more on the input textBox and any new flash will block the user. The only possibility he has to continue is to come in front of the M3 panel and press Fxx key.

    The main complaint of the user is that he has to wait the next ENTER key (so the next flash) to be alerted fron an error on the previous flash. I don’t know how to catch immediately the content of the errorTextBox when the javex program displays the panel after the control; i tried to use TextChanged event on the errorTextBox but without success.

    Do you have any idea about how to catch the content of a TextBox without using OnRequesting event ?

    Thanks!

    Reply
  7. EB

    Hello,
    Until the last update, everything worked fine.
    But in the last update , we have a problem to reffer to LABELS.

    when I use the method ScriptUtil.FindChild(controller.RenderEngine.Content,ControlName), So if it is text box, check box etc. etc. – then it work good.

    BUT when it is a Label (part of System.Windows.Controls.TextBlock) – So we get an Error : Object Requiered.

    I need to know, what changed in the last version regarding to this issue, and how to fix it.
    It is VERY IMPORTANT. Please reply me ASAP.
    Thanks & regards
    EB

    Reply
    1. karinpb Post author

      Hi, I have forwarded this question to Norpe.

      Reply:
      We had to change the Labels to use TextBlock instead of text to show the text. The reason is that some labels had underscore which would turn to accellerator keys. A label is a content control so it can have any content. In the last version the content is a TextBlock and not a string. You can get the content and check if it is of type TextBlock an in that case you need to get the Text() property to get the text.

      Reply
  8. Jose R.

    Hi,
    I’m working on this mashup that shows customer information.
    I have to retrieve the CUNO from data that comes from another program being executed on the pc.
    I don’t know how to send information from this program to the mashup inside Smart Office, and I don’t know where to start looking into, JScript, Extensions, Smart Office SDK…
    is there a way, with an url, to call a mashup from outside Smart Office?, and even to set data into it?.

    Thanks for your time.

    Reply
    1. karinpb Post author

      This “other program on the PC” is this a program you can develop/modify?
      There are two communication options (if the install is ClickOnce).
      1. Launch a new Smart Office with a URL that has a TASK parameter. The task parameter would startwith mashup://xxxx. The mashup can have default parameters. There is one example covering that in the Mashup Designer examples. I would need to check a shortcut to a deployed mashup to get a real example (I’ll add the full example URL later)
      2. Use a local port and submit a message to it – but then the “other program” must be able to detect the port – and only programs launched from SmartOffice would know the port
      3. Named pipe integration. This is standard Microsoft technology but requires coding.

      If you can get the other program to launch an URL (and IE is the default browser) you should be able to calculate the task. BUT CUNO must be valid as a URL paramter without special characters- eg “arla” is OK but not “skånemejerier” – as it will give you a URL with bad encoding. Or you must be able to encode parts of the URL after adding the CUNO part.

      Reply
      1. Jose R.

        Hi,
        I could modify the code of the ‘other app’, and open the mashup with a link like the one on the example in the designer, but I had to encode the uri, otherwise I get an error.

        Thanks!

  9. Jose R.

    Hi,

    At this stage I’m not sure how much I would change the code of the other software.
    But I think I can try the first option, calling the mashup and encoding the URL parameters.
    Then in the mashup I will have to find a way to refresh the information shown depending on the parameter.

    Tack.

    Reply
  10. Linda N A

    Hi,
    when the script is running in a mashup – is there a way to get hold of the runner.Host for the mashup so that you can access the HostContent, say for example a textbox and write some values to it?

    Reply
    1. karinpb Post author

      Hi,
      When you are running a script you can access anything in the visual tree. I would recommend using Snoop to check the visual tree and then the class called VisualTreeHelper to first find a parent of a specific type and then search for the textbox using the name. We have our own util built on top of that standard class – but I need to check if it is public. If you have a more specific scenario that would help as you will only find the textbox if it has a specific name. But navigating the visual tree is not fully supported as the structure might change between versions. But navigating for a specific name or class type is usually never changed.

      I would need to have a quick look into the code to be sure I give you the correct classes to search for but some more info would be nice. Is the textbox in a M3 detail / MI detail or why would you set it in script and not by an event?

      Reply
      1. Linda N A

        Hi!
        My script is intended to give the user a possibility to delete multiple rows at once from a customlist and imitate normal M3 behaviour. I have successfully used the Visualtreehelper to find my mashup textbox and placed the key values for the rows to be deleted in there. So when a delete button is clicked, a loop in the script can send the selected row data into a bookmark string and execute it.

        But there is a big problem that I’m hoping you have the solution for. If I don’t enable the listview somehow in the mashup (opening and closing the filter works) and then do a manual refresh of the mashup, I can’t go up the visual tree to the top parent that I find when using Snoop on the mashup window. It’s like the visual tree doesn’t know that it’s currently in a mashup (with extra content) instead of the M3 program unless I do this, and therefor the visual tree stops at GridContent and I never get to the content that’s in the mashup.

        I hope I have described the problem so you understand it. Is there any way you can think of that this can be fixed, or am I doing something wrong in my code?

  11. Angelos Arampatzis

    Hello! I am building a script that needs to read information from a database external to M3 and then display this information in a panel. The problem I have is that the JScript Tool refuses to recognize the declaration of SqlConnection. I am importing both System.Data and System.Data.SQLClient, but when I am trying to declare a variable of type SqlConnection I get an error when compiling:
    var aDbConnection = new SqlConnection(‘server=T-M3DB;database=M3FDBTST;uid=username;pwd=password’);

    Variable ‘SqlConnection’ has not been declared

    I have copied the script from https://thibaudatwork.wordpress.com/2011/09/09/sql-to-xml-in-a-script/ and it compiles just fine.

    Thanks in advance for your time.

    Reply
    1. karinpb Post author

      Hi,
      Did the example compile and run for you? Becuase there must be a typo or something in the script and the variable in the example was called connection and not var aDBConnection so you have done modifications so I would need the entire script and the exact error information. I had not seen this example before and I have to inform you that it is very unsecure to have the user and password in the connection string like this. It has to be a user that has very limited access to the databse, only read access and you have to be fine with everyone being able to get the user and password as the script files are loaded with http and which means that they are visible in plain text and the connection string pattern is an easy partter to search for. I’m just saying that it is a very unsecure and I would recommend using a web service (like Infor Web Service that can create web services from a stored procedure) instead of exposing the connection string. It’s easy I know just a big security risk. Even if access is correct and very strict to start with you never know if someone will give that user more rights to the DB in the future.

      Reply
      1. Angelos Arampatzis

        Karin thank you for your reply and all the security-related issues you pointed out. I am well aware of those, and the plan is to use a WS to supply the information to the script. For now I am building a just proof-of-concept to allow the users to evaluate the solution.

    2. Angelos Arampatzis

      I found what the problem was: System.Data.SQLClient needs to be System.Data.SqlClient.

      Reply
  12. Jose R.

    Hi, is there a way to read/write messages that appear on the bottom of a panel (status bar) from JScript?.
    I tried:
    WriteProperty(“Message “, panelState.Message);
    WriteProperty(“MessageId “, panelState.MessageId);
    But is not working.

    Thanks.

    Reply
    1. karinpb Post author

      Hi,
      There is a method to read the message from M3 and a way to add a message. But if the message appears in the statusbar or in a dialog depends on a user setting. You have no control of that.
      The following methods should be available if you are on 10.0.5.x or later.

      controller.RenderEngine.ShowMessage("Message text");
      
      // To read the message. Note! Read-only property
      controller.PanelState.Message
      controller.PanelState.MessageId
      
      Reply
  13. Mikael

    Hi,

    I am building mashup that merges that product information from PDS001/PDS002 etc in a mashup. However I have encountred a problem (small). I would like to have search-button that is displayed in the detail panel, which should diplay item related information when clicked on. I tried to do this using a button which call MMS200MI – Get (MIPanel). But I don’t konw how to configure the button to search? The information I have is the product number (PHPRNO) from MPDHED.

    Br,
    Mikae

    Reply
  14. Jose R.

    You can try to trigger the API call to MMS200MI/Get to fill a detail panel.
    On the click event of ths button you can retrieve the PHPRNO from the list (PDS001/002).

    Reply
  15. Suraj

    Hi,

    We have build a number of Smart Office personalisation’s based on Jscript to enhance the usability of some of the screens. These scripts utilize calls to M3API and Some custom REST services that we have written and hosted within the Network.

    The client has just informed that they want to start providing their users the ability to use H5 client.

    My question is
    1. Can the scripts be ported to the H5 Client?
    2. If not what are the options available on H5 client to do something similar?

    Thanks,
    Suraj

    Reply
  16. Jose R.

    When adding a colunm to a List Panel in Smart Office through scripting, is there a way to add a personalization (Conditional Style) to that new column?.
    I tried editing the personalization xml, adding the name of the new column, with no success…

    Thanks,
    Jose

    Reply
  17. Shawn VS.

    Lawson S3 jscript help to access a tab area defined in a detail area.

    I am attempting to add a new tab to the Infor delivered PO20 screen in S3 via jscript. The form contains the main form grid. On that is a detail area which contains 5 detail lines. On each detail line is a set of 6 tabs. I am attempting to add a 7th tab to the detail area. However, when I try to use any of the Infor defined helper functions none of them seem to be able to access the tab area under the detail area.
    I tried using both of the code examples below to either access or update the tab area and both of the objects are coming back as undefined.
    var aa = formGrid.GetTabPageContainer(“TF0-0”);
    console.WriteLine(“GetTabPageContainer: ” + aa);

    var bb = formGrid.AddTabPage(“TR0”, “TF0-6”, “NewTab”, “”);
    console.WriteLine(“AddTabPage: ” + bb);

    Any help is appreciated.
    Thanks,
    Shawn

    Reply
    1. karinpb Post author

      Comments from S3 Developer:
      I see a couple problems with the script provided:
      1) formGrid is a global variable, but it does not have a method of GetTabPageContainer. The method is available on the other global variable named form.
      2) When working with detail areas, such as adding tab pages or other visual elements, you must use of on the static methods in ControlsUtil. For tab pages the method is named, AddDetailTabPage.

      The Object Browser, available from the Help menu of the Script Tool provides documentation and sample code that can be quite useful.
      Also, look to the code insertion helpers in the upper right corner of the tool. If you use that, it would have inserted:

      var count = ControlsUtil.AddDetailTabPage(form, detailName, tabPageName, text);

      Then you would fill in necessary parameter names:

      var count = ControlsUtil.AddDetailTabPage(form, “DT0”, “TF0_6”, “New Tab”);

      If the count is greater than zero, the method succeeded and you could add controls to the tab:

      if (count > 0)
      {
      // add controls to the tab pages
      ControlsUtil.AddDetailLabel(form, “DT0”, “TF0_6”, “MyLabel”, 3, 5, 20, “Label content”);

      }

      This is one of the code examples found in the Object Browser.

      Reply
  18. Martin Stephens

    Hi,

    We are upgrading M3 from modified 7.1 to vanilla 13.3. We are using Jscripts to get around some of the old modifications. One of these maintains records in CUGEX1 using ChgFieldValueEx.

    This updates the new part of the record that holds dates and check boxes.

    My script writes and updates dates ok, but I am having trouble clearing a date value using the API. I have tried using a zero length string “”, a string containg 0 (“0”), and various other permutations of “00000000”, “0000/00/00″ etc. but all return ” an “Incorrect date” error.

    Do you know how to do this?

    Regards,

    Martin

    Reply
    1. karinpb Post author

      Hi,
      Is this a standard API? What is the program name and is the transaction ChgFieldValueEx? Perhaps if you can change the metadata for the field in the transaction and try and pass in “” (blank) it might work. If a field is a date then I don’t know how to pass in a blank date when using the rest-end point. But I don’t know if this is a valid scenario. The position based API uses ‘?’ to indicate “no value / clear value” but this should be wrapped in the REST call. But if the metadata says it has to be a date – it don’t know how to clear the date since we would validate and transform. It’s an interesting question and if this is a standard API I need to know more details so that I can ask the M3 Development Organisation.

      Reply
      1. Martin Stephens

        Hi Karin,

        It is a new standard transaction in the CUSEXTMI API. The customer extension table has a new section to store check boxes and dates. I reported it to the xtreme helpdesk yesterday as well. I tried blank “”, and ? etc nothing seems to work.

        Regards,

        Martin

      2. Martin Stephens

        Hi Karin, Just to let you know this has gone to development to get the API fixed.

        Regards,

        Martin

  19. Joe Walker

    Hi – I am trying to write a script that opens OSS415 in M3 and populates the order number in the field that is an entry field in the part of the B panel. I can get it to populate the header fields fine but can not find a way to get it to populate this field. It is an entry box but part of the list panel rather than a header field. The script is below but I can’t get the ORNO.Text field I have picked up to go into this box. I can get it into the WWUFLD field that is at the top but this is not where it needs to go.

    Any ideas whether this is possible or how to resolve it?

    Thanks,
    Joe

    var auto = new MFormsAutomation();
    auto.AddStep(ActionType.Run, “OSS415”);

    auto.AddStep(ActionType.Set, String.Empty);

    auto.AddField(‘WHRPID’, ‘LSALE2’);
    auto.AddField(‘WASBRL’, ‘2’);
    auto.AddField(‘WBACPE’, ‘1510’);
    //auto.AddField(‘UCORNO’, ORNO);
    //auto.AddField(‘XJSBFA’, ORNO);
    auto.AddField(‘WWUFLD’, ORNO.Text);

    //auto.AddStep(ActionType.Key, ‘ENTER’);

    var uri = auto.ToUri();
    DashboardTaskService.Manager.LaunchTask(new Task(uri));

    Reply
  20. Colm Hayes

    // Hi. I’m wondering if anyone can help out. I’m trying to develop a script to create records in PCS260 using data stored in an excel file. When the form loads a button is added and on click of that button the first record is created and the instance Cache increments up so the second time the form loads there is if statement to get more data from the excel file without the need for the user to click the button.

    //Everything works fine with the button but the next time the form loads after cycling through Panel E and back to Panel A the excel information is not added and the “System.Windows.Forms.SendKeys.SendWait(“^1″);” doesn’t create a new record.

    //Any help would be much appreciated

    import System;
    import System.Windows;
    import System.Windows.Controls;
    import MForms;
    import System.Windows.Forms;
    import Excel;
    import System.Reflection

    package MForms.JScript {
    class PCS260_A_Loop {

    var debug, button, content, gcontroller;
    var giStep;
    var gITNO;
    var bRemoved;

    public function Init(element: Object, args: Object, controller : Object, debug : Object)
    {
    //Create An Instance Cache and a Counter
    var counterInstanceCache = 0;
    var key = “TestCounterInstanceCache”;

    //Check if Instance Cache Already Exists and if so set the counter value
    if(InstanceCache.ContainsKey(controller, key))
    {
    counterInstanceCache = InstanceCache.Get(controller, key);
    }

    // Increment the Instance Cache Counter
    counterInstanceCache++;

    InstanceCache.Add(controller, key, counterInstanceCache);
    MessageBox.Show(“Instance Cache Counter: = ” + counterInstanceCache);

    //Create a Controler for the Mform
    this.gcontroller = controller;
    content = controller.RenderEngine.Content;

    //Add A Button
    button = new Button();
    button.Content = “Import”;
    Grid.SetColumnSpan(button, 10);
    Grid.SetColumn(button, 26);
    Grid.SetRow(button, 12);
    content.Children.Add(button);
    button.add_Click(OnClick);
    button.add_Unloaded(OnUnloaded);

    //IF STATMENT TO CHECK IF THE CODE HAS AREADY RAN AND IF SO RUN AGAIN WITHOUT NEED OF THE BUTTON
    if (counterInstanceCache>1)
    {
    if (counterInstanceCache<15)
    {
    MessageBox.Show("In The Loop");
    try
    {
    // Create an Excel Instance
    var exExcel = new ActiveXObject("Excel.Application");
    // Set the Work book to not show
    exExcel.Visible = false;
    // Set the Workbook Address and Open The Workbook
    var wbBook = exExcel.Workbooks.Open("C:\\Users\\colm.hayes\\Desktop\\PCS260 upload.xlsm");
    // Get Values from the Workbook
    var Item_Number = wbBook.Worksheets(1).Cells(2,1).Value
    var Cost_type = wbBook.Worksheets(1).Cells(2,8).Value
    var Cost_Date = wbBook.Worksheets(1).Cells(2,7).Text
    var Date_Offset = wbBook.Worksheets(1).Cells(2,9).Text
    // Save and Close the Workbook
    wbBook.Save();
    wbBook.Close();
    //Find the fields on the Mform
    var W1ITNO = ScriptUtil.FindChild(content, "W1ITNO"); // Item Number
    var W1STRT = ScriptUtil.FindChild(content, "W1STRT"); // Structure Type
    var W1PCTP = ScriptUtil.FindChild(content, "W1PCTP"); // Costing Type
    var W1PCDT = ScriptUtil.FindChild(content, "W1PCDT"); // Costing Date
    //Calculate the Date for the Costing Date
    var dtCurrent : DateTime = DateTime.Now;
    var dtCurrent = dtCurrent.AddDays(Date_Offset); // Today + 1 day
    //Add the Values from the Excell Workbook to the Mform Fields
    W1PCDT.Value = dtCurrent ;
    W1ITNO.Text = Item_Number;
    W1PCTP.Text = Cost_type;
    W1STRT.Text = "001";
    //Set the focas back on the MForm and send the keyboard shortcut CTLR + 1
    MessageBox.Show("Send Wait");
    W1PCTP.Focus();
    System.Windows.Forms.SendKeys.SendWait("^1");

    //Catch errors
    }
    catch(ex)
    {
    debug.WriteLine(ex.Message);
    }

    }
    }

    }

    public function OnClick(sender: Object, e: RoutedEventArgs)
    {
    try
    {
    // Create an Excel Instance
    var exExcel = new ActiveXObject("Excel.Application");
    // Set the Work book to not show
    exExcel.Visible = false;
    // Set the Workbook Address and Open The Workbook
    var wbBook = exExcel.Workbooks.Open("C:\\Users\\colm.hayes\\Desktop\\PCS260 upload.xlsm");
    // Get Values from th Workbook
    var Item_Number = wbBook.Worksheets(1).Cells(2,1).Value
    var Cost_type = wbBook.Worksheets(1).Cells(2,8).Value
    var Cost_Date = wbBook.Worksheets(1).Cells(2,7).Text
    var Date_Offset = wbBook.Worksheets(1).Cells(2,9).Text
    // Save and Close the Workbook
    wbBook.Save();
    wbBook.Close();
    //Find the fields on the Mform
    var W1ITNO = ScriptUtil.FindChild(content, "W1ITNO"); // Item Number
    var W1STRT = ScriptUtil.FindChild(content, "W1STRT"); // Structure Type
    var W1PCTP = ScriptUtil.FindChild(content, "W1PCTP"); // Costing Type
    var W1PCDT = ScriptUtil.FindChild(content, "W1PCDT"); // Costing Date
    //Calculate the Date for the Costing Date
    var dtCurrent : DateTime = DateTime.Now;
    var dtCurrent = dtCurrent.AddDays(Date_Offset); // Today + 1 day
    //Add the Values from the Excell Workbook to the Mform Fields
    W1PCDT.Value = dtCurrent ;
    W1ITNO.Text = Item_Number;
    W1PCTP.Text = Cost_type;
    W1STRT.Text = "001";
    //Set the focas back on the MForm and send the keyboard shortcut CTLR + 1
    W1PCTP.Focus();
    System.Windows.Forms.SendKeys.SendWait("^1");

    //Catch errors
    }
    catch(ex)
    {
    debug.WriteLine(ex.Message);
    }
    }
    // Remove the button from Memory
    public function OnUnloaded(sender: Object, e: RoutedEventArgs)
    {
    button.remove_Click(OnClick);
    button.remove_Unloaded(OnUnloaded);
    }

    }
    }

    Reply
    1. norpe

      I’m not sure exactly why the script does not work as expected but here are a couple of things I noticed.

      You should never rely on the Unloaded event to disconnect events. This event is might not fire in all cases which can cause incorrect behaviors with multiple active event handlers. Always use the Requesting event on the controller instance and disconnect all events there (including the Requesting event). There should be lots of examples of this in the scripts examples in the blog.

      The create list option can be triggered by a method on the controller instead of using SendKeys.SendWait.

      Examples with constant and hardcoded option (option -1 is used internally for create compared to option 1 for select):

      controller.ListOption(MForms.MNEProtocol.OptionCreate);
      controller.ListOption("-1");
      

      I’m not sure why the Excel document is loaded for each panel? It seems like it just gets the same values each time so the values could be cached. If the Excel document must be loaded each time I would create a function for that to avoid duplicating the code.

      Is it necessary to Save the Excel document? It does not seem like the content is modified.

      Reply
  21. Dirk Deperz

    Hi, I am searching for an example of a mforms automation uri which is launched within a mashup (example through a button)
    mashup:Event SourceEventName=”Click” LinkUri=”mforms://automation….

    the pgm that I want to launch has no bookmarks and in this way I want to prefill the fields with a value from the mashup

    Reply
    1. karinpb Post author

      Hi,
      You should check the Smart Office SDK. The M3 Developers guide included in the download zip has a few examples and the zip also contains MFormsAutomationBuilder.exe (External\M3\Tools) that is a program that will help you build the xml template. I think the syntax you have for the button if fine the trick is building the XML with the values as well as understanding the limitations with automation. If you have the MFormsAutomationBuilder tool you can get a launch URL that you can try in Smart Office. But keep in mind that automation only works for a specific view etc.

      Reply
  22. Raul

    Hello,
    I have two questions that I’m sure you can answer (I’m not very experienced jscript developer):

    1. I’m trying to develop a jscript to add a column to a list. Your scripts have been very useful and I did it but, when I use “Display” option on a row, my news column for that row is empty and I don’t know how to refresh again the information for it.

    I’ve been trying to add a routine on OnRequested function, but no success. Any idea?

    2. I saw that the OnRequested or OnRequestCompleted functions seems that they are removing themselves or other functions. That means that the removed functions will not work anymore? I mean, when I double click a row on a program with a script, the function OnRequested is running and its removing itself. Then, the second time that I double click another row, nothing happens because the function doesn’t exists. Is this normal?

    function OnRequestCompleted(sender: Object, e: RequestEventArgs) {
    try {
    var controller: MForms.InstanceController = sender;
    if (controller.RenderEngine == null) {
    scrollViewer.remove_ScrollChanged(OnScrollChanged);
    controller.remove_RequestCompleted(OnRequestCompleted);
    }
    } catch (ex: Exception) {
    debug.WriteLine(“OnRequestCompleted: ” + ex);
    }
    }

    Thank you in advance.

    Reply
    1. norpe

      Most of the times when you get back from to a list panel to a detail panel the BE program will return updated list rows. Any local modification such as added columns will be list and have to be reapplied again.

      A script that modifies list columns must check which list rows that needs to be updated each time the script loads.

      The script should always disconnect all events when the panel is reloaded (when the Requested event is triggered) to avoid memory leaks and multiple instances of a script executing at the same time.

      Reply
      1. Raul

        Thank you very much for you reply.
        I know the selected row and I tried to update, but no success. The program is entering within the routine, but the row is not updated.
        Any idea?

        Thank you in advance

  23. Angelos Arampatzis

    I am building an MForms automation script that changes the Warehouse From field in DPS170/E, but so far all my efforts have failed. For reason unknown, I can change none of the panel’s fields. A very simple script that demonstrates the problem is this:

    import MForms;
    import Mango.UI;
    import Mango.UI.Core;
    import Mango.UI.Core.Util;
    import Mango.UI.Services;

    package MForms.JScript {
    class Test {
    public function Init(element: Object, args: Object, controller : Object, debug : Object) {
    var auto = new MFormsAutomation();

    // Start DPS170
    auto.AddStep(ActionType.Run, “DPS170”);
    auto.AddStep(ActionType.Key, “ENTER”);

    // Set the sorting order
    auto.AddField(“WWQTTP”, “15”);
    auto.AddStep(ActionType.Key, “ENTER”);

    // Specify the planned order number
    auto.AddField(“W1OBKV”, “3017892”);
    auto.AddStep(ActionType.Key, “ENTER”);

    // Call the Edit option
    auto.AddStep(ActionType.ListOption, “2”)

    // Specify the desired value for the Warehouse From field
    auto.AddField(“WEFWHL”, “133”);

    // For testing pusrposes
    auto.AddField(“WEPRIP”, “4”);
    auto.AddField(“WEPTXT”, “Test text editing…”);

    // This is commented out to demonstrate that we are indeed in edit mode in DPS170/E
    //auto.AddStep(ActionType.Key, “ENTER”);

    var uri = auto.ToUri();
    DashboardTaskService.Manager.LaunchTask(new Task(uri));
    }
    }
    }

    The script successfully changes the sorting order, specifies the planner order number and calls Change (option 2), thus entering DPS170/E in edit mode. But all calls to AddField accomplish nothing.

    Does anyone have any ideas about what might be causing the problem I am facing?

    Thanks!

    Reply
    1. norpe

      First of all you should always add a step first and then add the fields that you want to set for that step. In your example it seems a bit mixed up and there were some unnecessary Enter steps. I have modified your example to make it easier to see which step a field belongs to.

      If you want to set values on a panel without committing the panel with Enter you need to use a step with ActionType.Set. This will set values on the last panel in an automation but it is up to the user to actually commit the values. Note that ActionType.Set can only be used on the last panel in an automation.

      import MForms;
      import Mango.UI;
      import Mango.UI.Core;
      import Mango.UI.Core.Util;
      import Mango.UI.Services;
      
      package MForms.JScript {
          class AutomationRepro {
              public function Init(element : Object, args : Object, controller : Object, debug : Object) {
                  var auto = new MFormsAutomation();
      
                  // Start DPS170
                  auto.AddStep(ActionType.Run, "DPS170");
      
                  // Set the sorting order
                  auto.AddStep(ActionType.Key, "ENTER");
                  auto.AddField("WWQTTP", "15");
      
                  // Specify the planned order number
                  auto.AddStep(ActionType.Key, "ENTER");
                  auto.AddField("W1OBKV", "3017892");
      
                  // Call the Edit option
                  auto.AddStep(ActionType.ListOption, "2")
      
                  // Set values without committing the panel with ENTER
                  auto.AddStep(ActionType.Set);
                  auto.AddField("WEFWHL", "133");
                  auto.AddField("WEPRIP", "4");
                  auto.AddField("WEPTXT", "Test text editing…");
      
                  // Set values and commit the panel with ENTER
                  //auto.AddStep(ActionType.Key, "ENTER");
                  //auto.AddField("WEFWHL", "133");
                  //auto.AddField("WEPRIP", "4");
                  //auto.AddField("WEPTXT", "Test text editing…");
      
                  var uri = auto.ToUri();
                  DashboardTaskService.Manager.LaunchTask(new Task(uri));
              }
          }
      }
      
      Reply
  24. Daniel

    Hi,
    I try to get a text out of a text panel in PMS101. The idea is to have kind of marco that opens the text panel, takes the text, modifies the text, paste it back in and press next. All without having complicated “select” and “update” web services or using APIs.

    The problem is that the window of the text panel is somehow out of everything.

    ScriptUtil.FindChild(content, “TX60”) does not work.
    So I tried with copy and past the text with keyboard commands and work with the clipboard in the script.
    this.controller.PressKey(“F6”); works to open the text panel. But with “PressKey()” I cannot do key combinations; as far as I know.
    System.Windows.Forms.SendKeys.SendWait(“^a”); will mark all text but as it is a “SendWait” it does wait until the window gets closed by the user.
    Forms.SendKeys.Send(“^a”); does not work; error that it cannot run inside this application because the application is not handling Windows messages.

    Any idea to that?

    Br
    Daniel

    Reply
    1. karinpb Post author

      Hi Daniel,
      I discussed this with *norpe* since he is the expert and it should be possible just that there are many bits and pieces and they are all complex and it could take as long as one day for us to write an example on this.

      There are a few different parts:
      1. Leave the script running and do not unload on onRequestedCompleted if the panel the text panel is loaded. Dispatch to the UI thread to look for the text panel dialog – possible with a small delay so you don’t try and access the dialog before it has opened.
      2. The text can have multiple lines so you would need to handle that as well
      3. Check if you can find the text panel dialog using System.Application.Windows collection over windows. To get the text field you can search the WPF visual tree using System.Windows.Media.VisualTreeHelper or our Mango.UI.Helpers. If that does not work there might be some native APIs that can be used to get the current window. It’s a modal dialog.

      I would use Snoop to investigate what to search for in the visual tree but first you need to find the modal dialog and I’m not sure how to do that so that would require some research. I wish I could be more specific but this is not an easy task.

      Reply
  25. Amy

    I am looking to somehow have some validation at entry on OIS100/A so that if the order type is DIR the facility is updated to A08, OR that it warns the user to change the facility to A08.

    Reply
    1. karinpb Post author

      Hi,
      I don’t have such a script but I might create one as this would be a rather easy task. You need to add an event handler to the OnRequesting event and then if the facility and order types does not match you can cancel the request and change the facility. I don’t think you should do this automatically since it will be more complicated.

      Reply
  26. Len Lim

    Hi,
    I’m just starting to learn H5 client scripting. How can we get the user Role of the user who is currently login? In ISO, we use
    var userRole : String = UserContext.Roles[0].Role;
    How do I do that in H5 client? And also how can I get the text value from a label?
    In ISO, I use this
    var content = controller.RenderEngine.Content;
    var tmpOrderNum : String = ScriptUtil.FindChild(content, ‘OAORNO’).Text;

    Thanks,
    Len

    Reply
    1. gsmarquez

      Hi Len,

      If you are starting with H5 scripting, I would recommend looking into Infor M3 H5 Development Guide.

      Regarding your questions:

      1) The user roles are not yet available in H5 client but it is on its way. For now you can retrieve UserContext values by using ScriptUtil.GetUserContext(contextProp).
      2) To get the text values, you can use the function ScriptUtil.GetFieldValue(fieldName).

      Here is a sample code.

      var Test = new function () {
          this.Init = function (scriptArgs) {
             
              // get a specific property from the UserContext
              console.log(ScriptUtil.GetUserContext("CONO"));
      
              // get field value from detail panel
              console.log(ScriptUtil.GetFieldValue("WFSLCT"));
          }
      }
      
      Reply
      1. Len Lim

        Hi,
        Thanks for the reply. I have another question. Is there a conversion for H5 script of OnRequesting and OnRequested function?

        Here is a sample :

        public function OnRequesting(sender : Object, e : CancelRequestEventArgs)
        {
        if ((e.CommandType == “KEY” && e.CommandValue == “ENTER”) || (e.CommandType == “LSTOPT” && e.CommandValue == “2”) || (e.CommandType == “LSTOPT” && e.CommandValue == “4”) )
        {
        if (datestring == tmpOrderDate)
        {
        debug.WriteLine(“same date”);
        }
        else
        {
        e.Cancel = true;
        ConfirmDialog.ShowWarningDialog(“Change Not Permitted”, “”, null);
        }
        }

        }

        public function OnRequested(sender : Object, e : RequestEventArgs)
        {
        controller.remove_Requesting(OnRequesting);
        controller.remove_Requested(OnRequested);
        debug.WriteLine(“Script unloaded”);
        }

      2. karinpb Post author

        Hi,
        For H5 questions please use the new H5 Scripting page to submit comments.
        The example is JScript and not JavaScript (H5). I thought the question was if there was a “convention” – of how to best use the events. In you case you are detaching the events just fine and the same pattern applies to Javascript.
        But as for as if there is a conversion of H5 script? Do you mean if you can convert a JScript to a H5 Script? No. There are two different languages and technologies. Some of the MForms objects are the same and the architecture with the events are the same (if you are on one of the latest of H5 – 10.3.0.x) but they are different.

      3. Len Lim

        Hi,
        The sample script was used in Jscript for ISO. I’m trying to convert this script to work on H5. I have read the developer’s guide, I’m just not sure how to convert it.

      4. gsmarquez

        Hi Len,

        Here is a sample script for H5 that contains OnRequesting, OnRequested and OnRequestCompleted event handlers. You can use this as reference for your conversion.

        var H5SampleRequestTracer = (function () {
            function H5SampleRequestTracer(args) {
                this.scriptName = "H5SampleRequestTracer";
                this.controller = args.controller;
                this.log = args.log;
            }
            H5SampleRequestTracer.prototype.logEvent = function (eventName, args) {
                this.log.Info("Event: " + eventName + " Command type: " + args.commandType + " Command value: " + args.commandValue);
            };
            H5SampleRequestTracer.prototype.attachEvents = function (controller) {
                var _this = this;
                controller.Requesting.On(function (e) {
                    _this.onRequesting(e);
                });
                controller.Requested.On(function (e) {
                    _this.onRequested(e);
                });
                controller.RequestCompleted.On(function (e) {
                    _this.onRequestCompleted(e);
                });
            };
            H5SampleRequestTracer.prototype.onRequesting = function (args) {
                this.logEvent("Requesting", args);
            };
            H5SampleRequestTracer.prototype.onRequested = function (args) {
                this.logEvent("Requested", args);
            };
            H5SampleRequestTracer.prototype.onRequestCompleted = function (args) {
                this.logEvent("RequestCompleted", args);
            };
            H5SampleRequestTracer.prototype.run = function () {
                var controller = this.controller;
                var key = this.scriptName;
                var cache = InstanceCache;
                // Check the instace cache to see if this script has already attached to this program instance.
                if (cache.ContainsKey(controller, key)) {
                    // The script is already attached to this instance.
                    return;
                }
                this.log.Info("Running...");
                // Add a key to the instance cache to prevent other instances of this script on the same program instance.
                cache.Add(controller, key, true);
                // Attach events.
                this.attachEvents(controller);
            };
            /**
             * Script initialization function.
             */
            H5SampleRequestTracer.Init = function (args) {
                new H5SampleRequestTracer(args).run();
            };
            return H5SampleRequestTracer;
        }());
        

        Regards,
        Gerard

      5. Len Lim

        Hi,
        Based on your sample code in event handlers. What if I want to cancel the request because it didn’t meet my condition, where should I put the cancel code and how should I do it?

        Thanks,
        Len

      6. gsmarquez

        Hi Len,

        You can put it in the H5SampleRequestTracer.prototype.onRequesting method. You can cancel the request by setting the args.cancel to “true”.

            H5SampleRequestTracer.prototype.onRequesting = function (args) {
                this.logEvent("Requesting", args);
        
        	// set conditions here
                args.cancel = true;
            };
        

        Regards,
        Gerard

      7. Len Lim

        Hi Gerard,
        The script you gave me work. Right now I have another problem. the cancellation doesn’t work when I put a condition inside another condition. The request will just proceed the command. Here’s my code.

        H5SampleRequestTracer3.prototype.onRequesting = function (args) {
        this.logEvent(“Requesting”, args);

        if ((args.commandType == “LSTOPT” && args.commandValue == “4”) || (args.commandType == “LSTOPT” && args.commandValue == “2”) || (args.commandType == “KEY” && args.commandValue == “ENTER”))
        {
        debug.WriteLine(“change is ” + permit);
        if (permit == false)
        {
        args.cancel = true;
        this.log.Info(“CANCEL!”);
        }
        else
        {
        this.log.Info(“APPROVE!”);
        }
        }
        else
        {
        this.log.Info(“PROCEED”);
        }
        };

      8. Len Lim

        It does work when it is triggered for the first time. After that, when I test it to another transaction, it won’t work anymore. I’m thinking i think I’m missing the
        controller.add_Requesting(OnRequesting);
        controller.add_Requested(OnRequested);
        controller.remove_Requesting(OnRequesting);
        controller.remove_Requested(OnRequested);

        Not sure how do you do that in H5?

      9. gsmarquez

        Hi Len,
        We have tried your sample code with the conditions and it works on our side.

        H5SampleRequestTracer3.prototype.onRequesting = function (args) {
         this.logEvent(“Requesting”, args);
        
        if ((args.commandType == “LSTOPT” && args.commandValue == “4”) || (args.commandType == “LSTOPT” && args.commandValue == “2”) || (args.commandType == “KEY” && args.commandValue == “ENTER”))
         {
        debug.WriteLine(“change is ” + permit);
         if (permit == false)
         {
         args.cancel = true;
         this.log.Info(“CANCEL!”);
         }
        else
         {
         this.log.Info(“APPROVE!”);
         }
         }
        else
         {
         this.log.Info(“PROCEED”);
         }
         };
        

        We’ve tried pressing enter(Key/Enter) on a position field and it canceled the request. We tried it several times and the request was always canceled. Please the check the permit variable, your code should work as long as permit is false.

        Regards,
        Gerard

      10. Len Lim

        Hi, it is working when the script is trigger for the first time. when I tried it in a different transaction it won’t work anymore. Example : I test it to CO#1, the script works perfectly. Then I test it in CO#2 to test the 2nd condition in the code. That’s the time when it won’t wont work anymore. It is still showing the result from the CO#1

      11. Len Lim

        What I noticed is that I put the script in OIS101. But even go back to OIS300, the script in OIS101 is still running.

      12. gsmarquez

        Hi Len,

        For future posts about H5 scripting, please use our new H5 Scripting page (https://smartofficeblog.com/h5-scripting/).

        Based on your jscript, you need to detach the requesting and requested event when a request has been completed, would that be correct?

        When attaching the requesting/requested event handler using the method On(), it returns a function that you can use to detach the event handler. Here is how the requeting/requested event handler can be detached.

            H5SampleRequestTracer.prototype.attachEvents = function (controller) {
                var _this = this;
                this.detachRequesting = controller.Requesting.On(function (e) {
                    _this.onRequesting(e);
                });
                this.detachRequested = controller.Requested.On(function (e) {
                    _this.onRequested(e);
                });
            };
            ...
            H5SampleRequestTracer.prototype.onRequested = function (args) {
                this.logEvent("Requested", args);
                this.detachRequesting();
                this.detachRequested();
            };
        

        All event handlers can also be removed by using the method Clear().

        	...
        	controller.Requesting.Clear();
        	controller.Requested.Clear();
        

        Also please take note of the InstanceCache on the sample H5 script that I have provided. Line 6 makes sure that the script’s event handlers are attached only once even if the form is refreshed which may not exist on your jscript.

            H5SampleRequestTracer.prototype.run = function () {
                var controller = this.controller;
                var key = this.scriptName;
                var cache = InstanceCache;
                // Check the instace cache to see if this script has already attached to this program instance.
                if (cache.ContainsKey(controller, key)) {
                    // The script is already attached to this instance.
                    return;
                }
                this.log.Info("Running...");
                // Add a key to the instance cache to prevent other instances of this script on the same program instance.
                cache.Add(controller, key, true);
                // Attach events.
                this.attachEvents(controller);
            };
        

        Regards,
        Gerard

  27. Linda

    Hi,

    is it possible to get a sample code of how to retrieve values from a list row in H5 Scripts?

    Thanks,
    Linda

    Reply
    1. rdespiritu

      Hi,

      This function returns the selected row/s in the list.

      ListControl.ListView.SelectedItem();
      

      These functions collect all the selected item(s) then get the value relative to the column name/index.

      ListControl.ListView.SelectedItem();
      ListControl.ListView.GetValueByColumnIndex(parseInt(textFieldValue, 10));
      ListControl.ListView.GetValueByColumnName(textFieldValue.toUpperCase());
      

      Thanks,
      Reah

      Reply
  28. Greg Wiers

    Hi,

    I’m new to the JScript/Mashup development, and thanks to some information on your blog have successfully implemented a button to launch another internal website, and manipulate the DOM of the resulting page with data from selected items in a list.

    What I am looking for is a way to determine in JScript which M3 environment I am connected to so I can alter the URL to point the proper environment of the website I am calling. Do you know of a way to handle this?

    Thanks,
    Greg

    Reply
    1. karinpb Post author

      Hi,
      An M3 environment does not have a name. What you can get is the runtime URL from the profile. Then you would need to know what environment that URL matches within your code.
      Below is an example on how to get the URL from the profile. The API is documented in the API documentation if you need more information. The parameters are all just strings but my example uses the constants from MForms.

      Include the following namespaces:
      Mango.Services
      MForms

      If ProfileDefinition isn’t public in your version the strings are: “RuntimeUrl”, “RuntimeUrlLogon”. From the ApplicationServices.SystemProfile you can get any value that is in the profile using the group, application and key values of the elements in the profile xml. Please note that if the application is not in the profile at all it will throw a KeyNotFoundException.

      var profile = ApplicationServices.SystemProfile;
      var runtimeUrl = profile.GetProperty(ApplicationGroupType.M3, "MForms", ProfileDefinition.RuntimeUrl);
      var runtimeUrlLogon = profile.GetProperty(ApplicationGroupType.M3, "MForms", ProfileDefinition.RuntimeUrlLogon)

      Reply
  29. potatoit

    What is the recommend location to store per environment settings for your scripts?

    Traditional I’ve followed what an Infor partner did and have a separate text configuration file which is read during the scripts Init(), but with the newer versions of the MUA this has become troublesome.

    I know we can store settings in the Profile – and ideally I’d like to create my own group, rather than lump the settings under M3, SmartClient or External, but if I can’t which group would be recommended?

    Reply
    1. karinpb Post author

      Hi,
      If you can use the script parameters for passing the values that is the preffered way.
      You can greate your own group but for applications that have a dependency to M3 it’s ok to add it to M3. You still need to add an application group for the values, eg the name of the script or something unique. Perhaps you have all jscript configuration under a single application name like JscriptConfiguration.

      I would say the recommended way is to add the values you need as parameters to the script if that is possible. If not then add an application under the M3 group.

      Reply
  30. Len

    Hi,
    Is there a way to disable a field using jscript? for example in PPS300, I don’t want the user to be able to change the Trans date field.

    Thanks,
    Len

    Reply
    1. karinpb Post author

      Hi Len,
      I’m on vacation so I can’t check the details but a disabled field has a specific style applied and I think it would be enough to set the style on the field. Below is an example for a textbox.
      The way to check is a field is enabled or not is to check the style of the TextBox. If the style is styleTextBoxDisabled the field is disabled. All disabled TextBoxes have this style.
      var isEnabled = true;
      If (yourTextBox.Style == Mango.UI.Core.StyleManager.StyleTextBoxDisabled){
      isEnabled=false;
      }

      For a DatePicker I would guess that the name of the style is: StyleDatePickerDisabled
      But I can’t verify it. But please try.

      Reply
  31. Tom Bateup

    Are there any methods or utils that can be called to copy data from the windows clipboard into a variable in a JScript?

    Reply
    1. karinpb Post author

      Hi,
      No, we have no utils for that. Is there a specific data structure that Smart Office stores in the clipboard that you are interested in? If not see MSDN

      Reply
      1. Tom Bateup

        Hej Karin,
        The inquiry I received from my colleague was whether we could copy a number of cells from an Excel spreadsheet and paste them directly into the corresponding fields within M3. The specific example being copying data from 7 fields in an Excel spreadsheet and then having a JScript within GLS120 paste that data into the New Accounting Line fields WXAIT1 to WXAIT7.
        KR,
        Tom.

  32. karinpb Post author

    Hi Tom,
    Yes it is possible. I don’t know the details of a GLS120 but the following StackOverflow question should get you started on what to look for:

    http://stackoverflow.com/questions/8614910/paste-from-excel-into-c-sharp-app-retaining-full-precision

    or some simpler approach to get the clipboard values as texts:

    http://stackoverflow.com/questions/1679778/is-it-possible-to-paste-excel-csv-data-from-clipboard-to-datagridview-in-c

    http://stackoverflow.com/questions/31238873/copy-paste-from-excel

    I wouldn’t use any third party but instead just parse the text or XML depending on what is easiest. If this is a tricky script to write I would write is as a dll using the Mashup SDK so that I could debug in Visual Studio and write anything in C#. Then the script can be the dll if it follows naming convention as described in https://smartofficeblog.com/2013/06/20/script-assemblies-in-mforms/

    Don’t forget to localize the solution to support . / or , or whatever number format you might need to support.

    Reply
  33. Linda

    Hi,

    is there a folder on ISO server where you can place a textfile and use the URL to retrieve the data via xmlhttp.open in a jscript? I’m building a popup with a listview and the customer would like to populate it using a web request rather than open the textfile using a path to the folder.

    Thanks,
    Linda

    Reply
    1. karinpb Post author

      Hi,
      There is no folder on the ISO server where you can place a file. There is the web application which has the download page and it might be possible to pace something next to that index.html file. BUT when Smart Office is upgraded the file will be lost. I would recommend placing the file in a IIS web root somewhere else.

      Reply
    1. karinpb Post author

      Hi,
      If it is your own dialog you can add a timer and then close the dialog or click the button. If it is a standard message box (which you shouldn’t use) or a Smart Office dialogs there is no API for that and I can’t help you with it. Consider other options.

      Reply
  34. Joeerg

    Hi All,
    I’ve a problem in MWS420 with focussing on field WCPLRI when I connect my script via personalization. It does not focus !!! When I test my script with the ISO-script-tool ist works !
    Could someone help me please ?
    BR Jörg

    Reply
  35. Joerg

    Hi All,
    I’ve a problem in MWS420 with focussing on field WCPLRI when I connect my script via personalization. It does not focus !!! When I test my script with the ISO-script-tool ist works !
    Could someone help me please ?
    BR Jörg

    Reply
    1. karinpb Post author

      Hi,
      In the init method controls aren’t rendered yet. Please try and dispatch before making the call or include Mango.Core.Util and use FocusAsync() instead of Async() as it is an extension method that will dispatch before trying to set focus.

      Reply
  36. Jörg Wanning

    Hi All,
    I’ve a problem in MWS420 with focussing on field WCPLRI when I connect my script via personalization. It does not focus !!! When I test my script with the ISO-script-tool ist works !
    Could someone help me please ?
    BR Jörg

    Reply
    1. Jose Ramon

      Hi,
      Maybe is a problem of timing (when the script is executed and when the control can receive the focus).
      You can try to use the Application.Current.Dispatcher funtion:

      public function Init(element : Object, args : Object, controller : Object, debug : Object) {
      this.controller = controller;
      var action : Action = ChangeTemplate;
      Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, action);
      }

      https://smartofficeblog.com/2014/08/21/custom-data-templates-in-m3-lists-with-jscript/

      Reply
    2. Joerg

      import System;
      import System.Windows;
      import System.Windows.Controls;
      import MForms;

      package MForms.JScript {
      class MWS420JW {

      var content,controller,debug,gElement,argumente,gArgs;
      var hasValues = false;
      var valueField;
      var fields = new Array(“WCPLRI”);
      var butText : String;
      var col : int;
      var row : int;

      public function Init(element: Object, args: Object, controller : Object, debug : Object)
      {
      debug.WriteLine(“Script Initializing.”);
      this.controller = controller;
      this.content = controller.RenderEngine.Content;
      this.debug = debug;

      var panelState = controller.PanelState;
      var fieldName = “WWQTTP”;
      var valueQTTP = panelState[fieldName];

      debug.WriteLine(“Start-qttp: “+valueQTTP);
      debug.Info(“” + valueQTTP);

      if (valueQTTP == “88”)
      {
      debug.Info(“SortingOrder88 selected !”);
      valueField = ScriptUtil.FindChild(content,fields[0]);
      valueField.Focus();
      }

      controller.add_Requested(OnRequested);
      controller.add_Requesting(OnRequesting);
      }

      public function OnRequesting(sender: Object,e: CancelRequestEventArgs) {
      debug.Info(“OnRequesting”);
      valueField = ScriptUtil.FindChild(content,fields[0]);
      valueField.Focus();

      }

      public function OnRequested(sender: Object, e: RequestEventArgs) {
      debug.Info(“OnRequested”);
      var listControl = controller.RenderEngine.ListControl;
      var listView = listControl.ListView;
      listView.SelectedItems.Clear();
      controller.remove_Requesting(OnRequesting);
      controller.remove_Requested(OnRequested);
      }
      }
      }

      Reply
      1. karinpb Post author

        Hi,
        As pointed out by our readers this is a timing issue. There are lots of factors controlling the focus, like tab order etc. and in the init method the controls are not guaranteed to be rendered. (Which they will always be when you debug in the tool because the panel is already running. Try adding Mango.Core.Util and use the FocusAsync() method (it uses the dispatcher behind the scenes). Or dispatch once with a really low priority. If that does not work dispatch once and then use FocusAsync. This is a standard trick for render issues and there are many different sources for setting focus in a standard M3 panel so you need to be sure that your code is run last.

    3. Jörg Wanning

      **** Below the script ********************************************************
      import System;
      import System.Windows;
      import System.Windows.Controls;
      import MForms;

      package MForms.JScript {
      class MWS420JW {

      var content,controller,debug,gElement,argumente,gArgs;
      var hasValues = false;
      var valueField;
      var fields = new Array(“WCPLRI”);
      var butText : String;
      var col : int;
      var row : int;

      public function Init(element: Object, args: Object, controller : Object, debug : Object)
      {
      debug.WriteLine(“Script Initializing.”);
      this.controller = controller;
      this.content = controller.RenderEngine.Content;
      this.debug = debug;

      var panelState = controller.PanelState;
      var fieldName = “WWQTTP”;
      var valueQTTP = panelState[fieldName];

      debug.WriteLine(“Start-qttp: “+valueQTTP);
      debug.Info(“” + valueQTTP);

      if (valueQTTP == “88”)
      {
      debug.Info(“SortingOrder88 selected !”);
      valueField = ScriptUtil.FindChild(content,fields[0]);
      valueField.Focus();
      }

      controller.add_Requested(OnRequested);
      controller.add_Requesting(OnRequesting);
      }

      public function OnRequesting(sender: Object,e: CancelRequestEventArgs) {
      debug.Info(“OnRequesting”);
      valueField = ScriptUtil.FindChild(content,fields[0]);
      valueField.Focus();

      }

      public function OnRequested(sender: Object, e: RequestEventArgs) {
      debug.Info(“OnRequested”);
      var listControl = controller.RenderEngine.ListControl;
      var listView = listControl.ListView;
      listView.SelectedItems.Clear();
      controller.remove_Requesting(OnRequesting);
      controller.remove_Requested(OnRequested);
      }
      }
      }

      Reply
  37. joseramoncll

    Hi,
    Maybe using this method: Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, action) solves the problem.

    public function Init(element : Object, args : Object, controller : Object, debug : Object) {
    this.controller = controller;
    var action : Action = ChangeTemplate;
    Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, action);
    }

    Fro this post: https://smartofficeblog.com/2014/08/21/custom-data-templates-in-m3-lists-with-jscript/

    Reply
  38. Jasper

    Hi Len,

    Can I please ask a quick question about the H5 Requesting event?
    I had a read of the H5 developer guide but that doesn’t mention anything about Requesting, Requested and Requested Completed event.
    I’m on M3 H5 v10.2.2.0.
    When I run your script H5SampleRequestTracer.
    I’ve got exception Uncaught TypeError: Cannot read property ‘On’ of undefined(…)
    This is the code.
    controller.Requested.On(function(args){
    console.log(“Requesting triggered”);
    });
    Thanks for your help.

    Reply
  39. PrabodhA

    Hi

    These days im developing Smart office SDK application in which i wanted to display Current Company and the current division name in form header as standard M3 programs . I m using UserContext.CurrentDivisionName to get division name.

    The problem is that when user logged to the smart office and once changed the default division using mforms://cmp100110 command it does not get reflected to the UserContext.CurrentDivisionName until manually run what ever M3 program.(Mform).

    What could be the possible reason for that .

    Reply
    1. karinpb Post author

      Hi,
      Smart Office supports many versions of MUA and M3 in parallell. This is originally by design since we did not receive the new information when executing the change company / Division command. This has been changed if you use M3 User Adapter (MUA) 10.3 or later. In that case we can automatically change the display names. I have created an enhancement ticket to add support for this when using MUA 10.3 or later. If you would like to follow this ticket you would have to report the issue to support and then ask them to track UID-23557 (Jira identifier) for you.

      Reply
      1. PrabodhaA

        Hi Karin
        Thanks for the response .

        How should I track UID-23557 ? Do I need to report this to the infor extreme

      2. karinpb Post author

        Hi,
        Yes, you would need to report this to Infor extreme and give them the ID to say that a Jira ticket exists but you want to connect your report to that ticket. That way support will track when the ticket is completed and resolved. That is the process for bugs and I think it will apply to the enhancement as well. The other option is to wait for the next two fixes (we release one each month). I don’t think it will make it to HF19 because that is submitted to test tomorrow but perhaps the next one. You can always check the release notes upon each fix to see if this enhancement is included.

  40. SamanJ

    Hi

    I m developing JScript Smart assembly script for PPS200/E. My required functionality is that to update a table when user changed date filed in the E panel .

    So OnRequesting i event i did the update logic. But my concern is when WARNNING or BE error occurred how do i avoid the execution of my update logic ?

    Reply
    1. karinpb Post author

      Hi,
      OnRequesting is before the request is made. If you need to wait for a successful change of panel you need to use RequestCompleted instead and check if you are on the next panel or not.

      Reply
  41. PrabodhaA

    Hi,

    Is there way to access SDK application via smart office navigator ? . Currenlty im accessing it via typing name in the search bar,
    I have tried with showInMenu=”true” in application manifest .But it seems does not worked for me .

    Is that possible ?
    Thanks
    Prabodha

    Reply
    1. karinpb Post author

      Hi,
      You need to implement IClientApplicationTasks or use the MenuExtensionService. This is documented in the developers guide and I also think that we have the two approaches as samples. I know for sure that we have the MenuExtensionService in the samples but I think that we have the IClientApplicationTasks as well. With IClientApplicationTasks you will have your own root node and with the MenuExtensionService you will have a node under “Other”. There is no way to get into another applications menu.

      Reply
  42. PrabodhaA

    Hi

    I am developing smart office mashup for display some PO lines . In which i have a requirement to change the row color based on value of the ROW .(some conditional style- if status is 45 etc ).

    How can i do this ?

    Any idea appreciated .

    Reply
    1. karinpb Post author

      Hi, If you are using a M3 program to display the lines (eg ListPanel) you use personlizations to color the lines. Please note that these personlizations needs to be managed separately and will also be the same as in the PO program in M3. You can also create local personalizations in the Mashup, called inline personalizations.
      See: https://smartofficeblog.com/2013/04/15/inline-personalizations-in-m3-mashups/

      If the lines are from an MIProgram you need to use standard WPF DataTemplates.

      Reply
  43. Patrik

    Hi Karin,
    I’ve been looking for the syntax in jscript, xaml, mformsautomation, etc that corresponds to
    the well known commands: CTRL-A (Mark), CTRL-C (Copy) and CTRL-V (Paste).
    Example: I wan’t to open an M3 program, Tab, Enter etc and move to a certain field/information that I wan’t to copy, and recycle downstream the process.
    Since I write to you I’ve not found any help anywhere…
    Hope I’m not completely out in the blue here, thx in advance.
    Regards
    Patrik

    Reply
    1. karinpb Post author

      Hi Patrik,
      Are you sure that you would like to add text to the computers clipboard? Because that is what those commands do.
      It seems like a really strange way to solve a requirement when you are writing code and can save the value in a variable and then update a field with that value using JScript.
      What is the requirement?
      The only reason to involve the clipboard would be to later paste it in another Windows application.

      To access the clipboard? System.Windows.Clipboard.SetText(“”);

      Links:
      https://msdn.microsoft.com/en-us/library/system.windows.clipboard(v=vs.110).aspx
      How to: Add Data to the Clipboard

      Reply
  44. Patrik

    Hi Karin,
    first, thx for the reply!

    Well I understand that it sounds weird but let me rephrase:
    I work a lot with mformsautomation, either as is or hidden behind a button in a Mashup, and
    consider it a really easy and powerful tool. And sometimes when I develop a “process” (=several
    M3 steps consolidated to one or fewer) I might wan’t to go in to one program and retrieve information (ex copy) and recycle that information somewhere downstream (ex paste).
    Does this “example” make it more understandable?
    (I’ve many years experience of Movex/M3 and even though I’ve done development
    in RPG, Java, jscripts and whatever, I always start from the application perspective…)
    Regards
    Patrik

    Reply
    1. karinpb Post author

      Hi Patrik,
      I understand your scenario but we don’t have that kind of support when you mix-in automation with scripts. But you could do with scripts more or less what automation does but it would be visible to the end-user. Add an overlay and take it away, get the data you need and store it and do whatever you like because JScript is a powerful tool. But we have not added any advanced methods to call automation and retrieve data from it or reuse data in one step in another and so on. There are no plans to add that kind if stuff either but if we get a lot of requests we might reconsider but that is not currently the case.

      It is great that you have a big toolbox to use but automation will only take you so far.

      Reply
  45. Jacob Fierro

    Hello,

    I am trying to developing a script that is capable of change supplier number on several Purchase order proposals (PPS170 / B). The idea is:
    1.The user select all lines on B panel where he wants the supplier to be changed
    2.Press the button (script). The new supplier number is asked
    3. Supplier is changed for all selected lines.

    Every time you change supplier on a proposal a pop up window is shown asking for a confirmation on a Purchase Price Update. I can not handle that message in the script (by using automation at least) and im getting an error message: “Failed to render panel”.

    This is the automation I’m using:
    Try {
    Var listViewControl = gController.RenderEngine.ListViewControl;
    Var tmpBaseUrl = ‘mforms: // _ automation /? Data = ‘
    + ‘ ‘
    + ”
    + ” + sorting_order + ”
    + ”
    + ”
    + ” + IN_1 + ”
    + ” + IN_2 + ”
    + ” + empty + ”
    + ”
    + ”
    + ” + first_row + ”
    + ”
    + ”
    + ” + valueSupplier + ”
    + ”
    + ” // Make Sure to save changes HERE COMES THE ERROR
    + ”
    + ” // Make sure to close PPS170 (Avoid PPS913 when some orders are released)
    + ”;

    I get purchase order proposal number and line number on variables IN_1 and IN_2 respectively. Then I set sorting order where i can sort by those values, and finally enter on the first listed row on change mode.
    After entering new supplier number I press ENTER twice and get the mentioned error.

    I would be tremendously grateful if you could give me any idea here.
    Regards.
    Jacob.

    Reply
    1. Jacob Fierro

      var auto = new MFormsAutomation();
      auto.AddStep(ActionType.Run,”PPS170″);
      auto.AddStep(ActionType.Key,”ENTER”);
      auto.AddField(“WWQTTP”,sorting_order);
      auto.AddStep(ActionType.Key,”ENTER”);
      auto.AddField(“W1OBKV”,IN_1);
      auto.AddField(“W2OBKV”,IN_2);
      auto.AddField(“W3OBKV”,empty);
      auto.AddStep(ActionType.ListOption,”2″);
      auto.AddStep(ActionType.Key,”ENTER”);
      auto.AddField(“WESUNO”,valueSupplier);
      auto.AddStep(ActionType.Key,”ENTER”); //To accept Price/date validation
      auto.AddStep(ActionType.Key,”ENTER”); //HERE COMES THE ERROR
      auto.AddStep(ActionType.Key,”F3″);
      auto.AddStep(ActionType.Key,”F3″); //To avoid PPS913 when released proposals exists.

      var uri = auto.ToUri();
      DashboardTaskService.Manager.LaunchTask(new Task(uri));

      Reply
  46. Prabodha

    Hi
    I am developing SDK application in which I need get some data from iseries . There is no inbuilt APIs for retrieve that particular set of data . I cannot create new APIs since my customer wants to keep M3 as vanilla.
    Furthermore I cannot use web service as my query contains dynamic where clauses and query returns huge amount of data set .

    So I wrote a query and try to all that query using “IBM.Data.DB2.iSeries.dll” driver . This approach did not worked for me because , this required to install Iseries driver in client machines .

    What would be the best possible way to call iseries queries inside the SDK applications .

    Reply
    1. karinpb Post author

      Hi,
      Sorry I have never had to connect to a DB2 from .Net and this is not specific to Smart Office development. I would however recommend that you don’t add a connection string to a setting or profile value because it is NOT secure. The only scenario that would be secure is to ask the user for the DB user and password in a dialog and store it using Mango.Core.Security.CredentialStorage that will store it encrypted on the local machine.

      I suggest that you try with:
      Forum: .NET Development with DB2 and IDS

      Connect to IBM DB2 only using .dll reference

      Reply
  47. Angelos Arampatzis

    Hello! I am creating a script that should change a text box’ contents when the user selects a new value from a combo box (on MOS057/E). I do not know though how to assign a handler to the combo box’ OnSelectedIndexChanged event (or whatever event JScript has). In effect, I am looking for the corresponding of the Button’s add_Click method which assigns a handler to the button’s OnClick event.

    Thank you in advance for your time.

    Reply
      1. Angelos Arampatzis

        Thank you for your quick and to the point reply Karin! Indeed, there is a add_SelectionChanged method.

  48. Martin Stephens

    Hi,

    I have a script that validates an E panel in the OnRequesting event, then if something is invalid cancels the operation (e.Cancel). What I would like to do as well, is under some conditions, force the user to go to the F panel even if the F panel isn’t in the users panel sequence. Searching for examples, I can’t see a way of doing this. Is this possible?

    Regards,

    Martin

    Reply
    1. karinpb Post author

      Hi,
      The client can only change the panel sequence on the B panel. So no, that it not possible with script. The M3 program can tell the client to show a specific panel in a flow, but not the other way around.

      Reply
  49. Daniel Henningsver

    If I add a datepicker on a panel with script in Smart Office in order to store data into the custom defined fields, is it possible to include this field in the tab order somehow? At the moment this field is skipped when tabbing around the elements on the panel.

    Reply
  50. Bhumika Lekurwale

    Hi, I want to develope a JScript for Infor Smart office. First a button has created on OIS300 panel. Onclick of this button , want to show a form/window where need to write some data from M3 API transaction in the column and row form.
    Can someone help me in creating a form/window on click of button and write data in Column and row format, from where I should be able to read data again.

    Reply
    1. Lode Vlaeminck

      You might want to look into
      Mango.Services.IInstanceHost dialog;
      used like this:
      dialog = controller.Host.CreateDialog();
      dialog.Closed += dialog_Closed;

      //size of popUp
      dialog.Width = 450;
      dialog.Height = 400;

      dialog.HostContent = // Your content (a Grid/ Stackpanel/…)
      dialog.ShowDialog();
      This Code is written in C# but can be translated to Jscript.

      Or you can use: https://smartofficeblog.com/2015/11/05/creating-your-own-windows-with-jscript/

      Reply
  51. Bhumika Lekurwale

    Hi Lode Vlaeminck, Thanks for the answer.

    Just to clarify, I can now popup the modal window using the link you attached above. But May I know how to write the data received from M3 API transaction on this window in row and column format.

    Thanks,
    Bhumika

    Reply
    1. Lode Vlaeminck

      Just make sure the controls on the popup are accesible (declare them as private attributes of the class) and use the method that handles the response to update the controls.

      Reply
  52. Prabodha

    According to current set up in MMS100/E panel when user is pressed next button, Dialog box is being displayed with Yes, No and Cancel buttons and always Yes button is focused. This dialog box is from M3BE side validation .Not using a JScript .So I wanted to focus No button or Press the No or Cancel button of the Dialog box automatically when Dialog is emerged.
    . I tried with Key press tab and enter and It didn’t work. (To focus No and press Enter)

    Reply
    1. norpe

      First I should say that scripting of the M3 dialogs is not officially supported but technically possible. If you do script the dialogs it is probably easier to just call the PressKey method on the controller instead of setting focus to buttons etc.

      Example for cancel:
      controller.PressKey(“F12”);

      All keys for the confirm dialog:
      OK = “ENTER”
      Yes = “1”
      No = “0”
      Cancel = “F12”

      Reply
      1. Jacob Fierro

        Hi Norpe,

        I have the same problem on PPS170/E. Every time i change supplier on a planned Purchase order, a “pop-up” Windows shows up asking for a Price recalculate confirmation. I’m not able to handle this kind of message. Can you help me?

  53. Jonatan Stenbacka

    I know there’s a “controller.RenderEngine.ShowMessage” function to show a message in the “status bar” of a panel, but as far as I can tell there’s no way to check the message in the status bar.

    using “controller.RenderEngine.messageHistory” somehow works, but it only contains the latest shown message, and doesn’t mean that that message is shown any more.

    Am I missing something?

    Reply

Leave a Reply

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

WordPress.com Logo

You are commenting using your WordPress.com 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