Inforum in New York

We built our headquarters in the center of New York’s Silicon Alley —to let the city shape us, just like we help shape the companies that do business not just here but everywhere. Come see for yourself at Inforum 2016 on July 10-13 in New York City. http://www.inforum2016.com/

Inforum

Wow… New York. Sweden and Stockholm can’t compare. I know a few colleagues that are traveling and I hope that you all can enjoy this great event. If you like me are unable to go to New York you can still follow online:

The Infor Blog

youtube

Smart Office SDK unable to run project

The last week I’ve got two questions from Smart Office Developers in the partner network desperately trying to run the Smart Office SDK but as soon as they log in to Smart Office they are presented with “Infor Smart Office has encountered a problem”, “We are sorry for the inconvenience. Please tell Infor about this problem and provide the log file and information of the steps leading up to it. Press the Support button to save the log file at a location of your choice.”.

restartdialog

What to do?

When you are having an issue always check the log file. when developing the log file is located in a location similar to this example from Windows 10:

C:\Users\username\AppData\Local\Infor\Mango Client

This generic “catch-all” is only shown when there is an unhandled exception on a background thread. When developing always make sure that you have try-catch on code that is executed on a background thread. If you are developing and get this error the issue is probably in your code. But not in this case.

The log

In this case the log file had the following log at the bottom:

2016-06-30 16:07:25,519 [20] FATAL Mango.UI.Client.MangoApplication.OnUnhandledExceptionCurrentDomain – Fatal shutdown caused by unhandled exception on background thread.
2016-06-30 16:07:25,520 [9] FATAL Mango.UI.Client.MangoApplication.OnUnhandledExceptionCurrentDomain – [MUI0040] Unhandled exception from AppDomain. IsTerminating=True.
System.IO.FileNotFoundException: Could not load file or assembly ‘System.Data.SqlServerCe, Version=3.5.1.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91’ or one of its dependencies. The system cannot find the file specified.
File name: ‘System.Data.SqlServerCe, Version=3.5.1.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91’

Server stack trace:
at Mango.Core.Persistance.Statistics.GetRecentlyUsed(Int32 returnCount)
at Mango.UI.Services.ApplicationUsageService.RecentlyUsed(Int32 returnCount)
at Mango.UI.Services.HistoryDS.LoadRecent()
at Mango.UI.Services.HistoryDS.Execute()
at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)

Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.EndInvokeHelper(Message reqMsg, Boolean bProxyCase)

The solution

SQL Server Compact Edition is a requirement for SDK development. Usually you don’t need to install it – it just works. But if you have any issues then please download Microsoft SQL Server Compact 3.5 Service Pack 2 for Windows Desktop from Microsoft and install it. On a 64-bit computer install both 32-bit and 64-bit versions.

I hope that this post will find it’s way to any SDK developer that encounter this issue.

Field validation using JScript in OIS100/A

In this post I’ll give an example of how you can validate a field in OIS100 using JScript. The scenario is as follows: All orders with order type “E50” has to be from faclity “FC5”. How can you validate input in OIS100/A? This was the question from one of our readers. The script is pretty straightforward as you have all the data that you need to check on the panel so I created a small example to illustrate the use of OnRequesting. Please note that you could make this script better by using script arguments.

The scripts illustrates the following:

  • Cancelling navigation to the next panel
  • How to set a field value
  • How to read a field value
  • How to show a message (in the status bar or dialog depending on setting)
  • How to log to the client log file
  • How do disconnect the event handler

If the order type and the facility does not match the required condition the facility is updated and a message is displayed.

OIS100A

Below is the script:

import System;
import System.Windows;
import System.Windows.Controls;
import MForms;
import Mango.UI.Services;
import Mango.Core.Util;

package MForms.JScript {
  class FieldValidation {
    var logger : log4net.ILog = Mango.Core.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType)
      var controller,
    debug,
    content;
    var checkOrderType = "E50"; // Should be a parameter
    var mandatoryFacility = "FC5" // Should be a parameter

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

      // Attach event handlers to be able to detach event handlers and list to page down requests.
      controller.add_Requesting(OnRequesting);
    }

    public function OnRequesting(sender : Object, e : CancelRequestEventArgs) {
      try {
        LogDebug("onrequesting " + e.CommandType + " " + e.CommandValue);
        if (e.CommandType == "KEY" && e.CommandValue == "ENTER") {
          // Do not disconnect events on page down.
          var orderType = GetValue("OAORTP");
          LogDebug("Order type: " + orderType);

          if (orderType != null && orderType == checkOrderType) {
            var facilityElement = ScriptUtil.FindChild(content, "OAFACI");
            if (facilityElement != null) {
              var value = MFormsUtil.GetControlValue(facilityElement);
              LogDebug("Facility " + value);
              if (value != mandatoryFacility) {
                LogDebug("Set facilty to " + mandatoryFacility);
                facilityElement.Text = mandatoryFacility;
                e.Cancel = true;
                // Here we could show a dialog as well
                var message = "When using order type " + checkOrderType + " you must use facility " + mandatoryFacility;
                controller.RenderEngine.ShowMessage(message);
                // Return so we don't disconnect since we cancelled the request
                return
              }

            }
          }
          
        }
      } catch (ex) {
        LogDebug(ex);
      }
      controller.remove_Requesting(OnRequesting);
    }

    private function GetValue(fieldName) {
      var element = ScriptUtil.FindChild(content, fieldName);
      if (element != null) {
        var value = MFormsUtil.GetControlValue(element);
        return value;
      }
      debug.WriteLine("Could not find a field named " + fieldName + " on the current panel");
      return null;
    }

    private function LogDebug(message : String) {
      if (message != null) {
        logger.Debug(message);
        if (debug) {
          debug.WriteLine(message);
        }
      }
    }
  }
}

MIPanel enhancements for the Mashup Designer

Smart Office Hot Fix 12 was just released (10.2.0.88). We have some new features and in this post I’ll cover a changes to the MIPanel that will make it easier to chain calls together. The new features for the MIPanel are:

  • New events: CompletedSuccessfully and CompletedWithError
  • New properties: ShowMessagesInDialog and ShowMessagesInStatusBar
  • New result property that you can bind to: MIPanel.ErrorInfo. This property will contain error information from the first failed transaction. It has ErrorMessage, ErrorCode, ErrorField, Transaction and Program.

Properties

For those of you who have use conditions on events you can now consider using the new events. An example scenario would be updating item information and if that transaction is successful you would like to run another transaction. In that case you can trigger the second update based on CompletedSuccessfully instead of UpdateCompleted.

Item update

Please note that I have some hard coded values in the example. I did have to configure MandatoryInputFields since I’m not changing the item number as the behavior of the MIPanel is to only send updated data to an MITransaction. The use of the event is pretty straight forward. For numeric input I used the NumericTextBox. You will not find it in the Designer UI but it is part of Smart Office so you can use it if you edit the XAML. Here is the XAML:

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:Mango.UI.Controls;assembly=Mango.UI" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI" xmlns:m3="clr-namespace:MForms.Mashup;assembly=MForms">
	<Grid.ColumnDefinitions>
		<ColumnDefinition Width="1*" />
	</Grid.ColumnDefinitions>
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto" />
		<RowDefinition Height="1*" />
		<RowDefinition Height="Auto" />
		<RowDefinition Height="Auto" />
	</Grid.RowDefinitions>
	<m3:MIPanel Name="ItemDetail" Grid.Row="0" Margin="0,15,0,0">
		<m3:MIPanel.Events>
			<mashup:Events>
				<mashup:Event SourceEventName="Startup" TargetEventName="Get">
					<mashup:Parameter TargetKey="ITNO" Value="AC-001" />
					<mashup:Parameter TargetKey="FACI" Value="010" />
				</mashup:Event>
			</mashup:Events>
		</m3:MIPanel.Events>
		<Grid>
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="Auto" />
				<ColumnDefinition Width="10" />
				<ColumnDefinition Width="200" />
				<ColumnDefinition Width="15" />
				<ColumnDefinition Width="*" />
			</Grid.ColumnDefinitions>
			<Grid.RowDefinitions>
				<RowDefinition Height="Auto" />
				<RowDefinition Height="5" />
				<RowDefinition Height="Auto" />
				<RowDefinition Height="5" />
				<RowDefinition Height="Auto" />
				<RowDefinition Height="5" />
				<RowDefinition Height="Auto" />
				<RowDefinition Height="10" />
				<RowDefinition Height="Auto" />
			</Grid.RowDefinitions>
			<Label Content="Item number:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<TextBox MaxLength="15" Text="{Binding [ITNO]}" IsEnabled="false" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Label Content="Name:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<TextBox MaxLength="30" Text="{Binding [ITDS]}" Grid.Row="2" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Label Content="Description 2:" Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<TextBox MaxLength="60" Text="{Binding [FUDS]}" Grid.Row="4" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Label Content="Avergage cost:" Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0" Padding="0" />
			<ui:NumericTextBox MaxLength="10" Name="inputAPPR" Text="{Binding [APPR]}" Grid.Row="6" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" />
			<Button Name="SaveButton" Content="Update" Grid.Row="8" Grid.Column="2" HorizontalAlignment="Right">
				<Button.CommandParameter>
					<mashup:Events>
						<mashup:Event TargetName="ItemDetail" SourceEventName="Click" TargetEventName="Update" Debug="True">
							<mashup:Parameter TargetKey="ITNO" Value="{Binding [ITNO]}" />
							<mashup:Parameter TargetKey="FUDS" Value="{Binding [FUDS]}" />
							<mashup:Parameter TargetKey="ITDS" Value="{Binding [ITDS]}" />
						</mashup:Event>
					</mashup:Events>
				</Button.CommandParameter>
			</Button>
		</Grid>
		<m3:MIPanel.DataSources>
			<m3:MIDataSourceList>
				<m3:MIDataSource Program="MMS200MI" Transaction="Get" Type="Get" InputFields="ITNO" OutputFields="ITNO,ITDS,FUDS" />
				<m3:MIDataSource Program="MMS200MI" Transaction="GetItmFac" Type="Get" InputFields="FACI,ITNO" OutputFields="APPR" />
				<m3:MIDataSource Program="MMS200MI" Transaction="UpdItmBasic" Type="Update" InputFields="ITNO,ITDS,FUDS" MandatoryInputFields="ITNO" />
			</m3:MIDataSourceList>
		</m3:MIPanel.DataSources>
	</m3:MIPanel>
	<m3:MIPanel Name="SecondUpdatePanel">
		<m3:MIPanel.Events>
			<mashup:Events>
				<mashup:Event SourceName="ItemDetail" SourceEventName="CompletedSuccessfully" TargetEventName="Update" Debug="True">
					<mashup:Event.Conditions>
						<mashup:Conditions>
							<mashup:Condition SourceValue="{Binding ElementName=inputAPPR, Path=Text}" TargetValue="{Binding ElementName=ItemDetail, Path=[MMS200MI.GetItemFac.APPR]}" Operator="NotEqual" />
						</mashup:Conditions>
					</mashup:Event.Conditions>
					<mashup:Parameter SourceKey="ITNO" />
					<mashup:Parameter TargetKey="FACI" Value="010" />
					<mashup:Parameter SourceKey="APPR" />
				</mashup:Event>
			</mashup:Events>
		</m3:MIPanel.Events>
		<m3:MIPanel.DataSource>
			<m3:MIDataSource Program="MMS200MI" Transaction="UpdItmFac" Type="Update" InputFields="FACI,ITNO,APPR" />
		</m3:MIPanel.DataSource>
	</m3:MIPanel>

	<ui:StatusBar Name="StatusBar" Grid.Row="3" Grid.Column="0" />
</Grid>

Unfortunately the Documentation in the Mashup Designer is not updated with the new properties etc as there has been no update to the Mashup Designer. You can always find the latest API documentation in the Smart Office SDK.

For a full listing of changes made on this release, refer to Lawson KB 1626878 / M3 KB 1623430.

Creating your own windows with JScript

When working with JScript you might want to open a new window. There are a few different ways that this can be done and today I’ll share how to create a new window that is visible in the taskbar and how to open a modal window. Modal means that you cannot access any other Smart Office functionality such as the QuickNote widget or data in a form as the modal window is the only currently active window placed above all other windows. A modal window is a graphical control element subordinate to an application’s main window which creates a mode where the main window can’t be used. The modal window is a child window that requires users to interact with it before it can return to operating the parent application, thus preventing the workflow on the application main window. This is great for some cases but can also be frustrating.

Background

Some of the concepts when working with windows in Smart Office is IInstanceHost – which represents the contract to an application host window. Then if a window is visible in the TaskBar it has to have a Runner – a handle to a task running on the Canvas. A Task is an item that can be launched on the Canvas. A task can only be launched if there is a registered application that supports the task. The scheme part of the task URI is used to locate an application that can launch a specific task, form example mforms://mms001. All these interfaces and classes can be found in the Smart Office SDK API and some of them in the API Documentation under Help in the Mashup Designer. When writing JScripts you should be familiar with the Smart Office core programming concepts.

There are new overloads of LaunchTask that can open a window in different ways. If the code does not work on your version of Smart Office it is possible that the method used does not exist in your version.

Opening a new window

Below is an example from Norpe on how to create a non modal and a modal window with JScript. Enjoy.

If you don’t want to have modality to the new window you can create a window that shows up in the task bar using an overload of the LaunchTask method. The script below shows examples of how to launch a modal window and a non-modal window.

DialogWindow

import System;
import System.Windows;
import System.Windows.Controls;
import MForms;
import Mango.UI.Core;
import Mango.Services;
import Mango.UI.Services;

package MForms.JScript {
   class NewWindowTest {
      var controller, content, debug, host;
      var buttonOpen, buttomOpenModal, buttonClose;
        
      public function Init(element: Object, args: Object, controller : Object, debug : Object) {         
         this.controller = controller;
         this.debug = debug;
         var content : Object = controller.RenderEngine.Content;

         var stackPanel = new StackPanel();
         stackPanel.VerticalAlignment = VerticalAlignment.Center;
         stackPanel.HorizontalAlignment = HorizontalAlignment.Center;

         buttonOpen = new Button();
         buttonOpen.Content = "Open New Window";
         buttonOpen.Width = "160";
         stackPanel.Children.Add(buttonOpen);
         
         buttomOpenModal = new Button();
         buttomOpenModal.Content = "Open New Modal Window";
         buttomOpenModal.Width = "160";
         buttomOpenModal.Margin = new Thickness(0,8,0,0);
         stackPanel.Children.Add(buttomOpenModal);
         
         Grid.SetRowSpan(stackPanel, 100);         
         Grid.SetColumnSpan(stackPanel, 100);
         content.Children.Add(stackPanel);

         buttonOpen.add_Click(OnClickOpen);
         buttomOpenModal.add_Click(OnClickOpenModal);
         controller.add_Requested(OnRequested);                  
      }
      
      public function OnClickOpen(sender: Object, e: RoutedEventArgs) {         
         try {
            var title = "New Window Test";
            var task = new Task(new Uri("notused://")); // The uri is not important (but must be valid) when shortcut are not allowed
            task.AllowAsShortcut = false;
            task.VisibleName = title;
            task.ToolTipInfo = title;
            task.UseVisibleShortName = false;
            
            var runner = DashboardTaskService.Current.LaunchTask(task, HostType.Default);
            host = runner.Host;
            
            host.HostContent = CreateWindowContent("Window Content");  
            
            host.HostTitle = title;
            host.Width = 640;
            host.Height = 480;
            runner.Status = RunnerStatus.Running;
            host.Show();
         } catch(ex) {
            Log(ex);         
         }
      }
      
      public function OnClickOpenModal(sender: Object, e: RoutedEventArgs) {         
         try {
            var content = CreateWindowContent("Modal Window Content");  
            content.Width = 640;
            content.Height = 480;
            
            var title = "New Modal Window Test";
            host = new HostWindow(true);
            host.HostContent = content;
            host.HostTitle = title;
            DashboardService.Current.ShowDialog(host); // Use DashboardService to get modal "shake".
         } catch(ex) {
            Log(ex);         
         }
      }
      
      public function CreateWindowContent(text : String)
      {
         var grid = new Grid();
         var textBlock = new TextBlock();
         textBlock.Text = text;
         textBlock.VerticalAlignment = VerticalAlignment.Center;
         textBlock.HorizontalAlignment = HorizontalAlignment.Center;
         textBlock.FontSize = 48;
         grid.Children.Add(textBlock);
         
         buttonClose = new Button();
         buttonClose.Content = "Close";
         buttonClose.Width = "120";
         buttonClose.VerticalAlignment = VerticalAlignment.Bottom;
         buttonClose.HorizontalAlignment = HorizontalAlignment.Right;
         buttonClose.Margin = new Thickness(0,0,8,8);
         buttonClose.add_Click(OnClickClose);
         grid.Children.Add(buttonClose);
         
         return grid;
      }
      
      public function OnClickClose(sender: Object, e: RoutedEventArgs) {         
         if(host != null) {
            host.Close();
            host = null;
         }
      }
      
      public function OnRequested(sender: Object, e: RequestEventArgs) {
         buttonOpen.remove_Click(OnClickOpen);
         buttomOpenModal.remove_Click(OnClickOpenModal);
         controller.remove_Requested(OnRequested);
         if(buttonClose != null) {
            buttonClose.remove_Click(OnClickClose);
         }
      }
      
      function Log(text : String)
      {
         debug.WriteLine(text);
      }
   }
}

Smart Office 10.2.1 Hot Fix 6 is released

Last week we released update 6 for Smart Office Build 10.2.1.0.54. It has some nice new features that you should know about, especially for Lawson customers but also general performance improvements. You will notice performance improvements if you are running large Mashups but also in both Lawson and M3 Forms.

I’ve also added a new link to a new blog from iStone that you might find interesting, M3 Usability Blog.

Special thanks to Vince for the Lawson update below. For more Smart Office and Lawson related information be sure to follow the Infor Lawson Technology blog.

For additional information regarding Infor Smart Office Hot Fix 6 (Build 10.2.1.0.54) and a list of bug fixes and enhancements see KB article 1626878 on Infor Xtreme.

Lawson Import / Export tool

There are a few different tools for exporting and importing. There is a stand alone tool called Mango Admin that we have written about before – but it has it’s limitation as for example M3 and Lawson has other user related data as well and the Mango Admin only exports data on the Smart Office server. There is the export / import manager in Smart Office for settings and predefined widgets (with meta-data for Lawson widgets). But there are also other types of user data such as scripts and personlization files and for M3 and Lawson those files are located on the MUA / Lawson application server. M3 has the Personalizations tool and a Files tool that can export scripts and personlization files separately.  As of 10.2.1.0.54 Lawson has a new great  tool that allows administrators or anyone granted access via their Role to export to a zip file of the various personalization files stored on the Lawson application server. Once exported, this file can then be used to import the files to another server.

ImportExportLawson

Because many personalization files are associated with a Data Area and often the Data Area on the target server will be named differently than the Data Area on the source server, a dialog for ‘mapping’ the names and specifying which Data Areas to process is also provided.

DataArea

Smart Office LSF Administration Tools

Beginning with HF 6 of 10.2.1 Smart Office, a number of LSF Administration tools are made available.  These are the same tools available in Lawson/Ming.le.  The tools available are dependent on the version of LSF.

LSF 9.0.1.14

  • Language Definition
  • Printer Definition
  • Printer Group Definition

LSF 10.0.6

  • Job Queue Definition
  • Language Definition
  • Locale Definition
  • Printer Definition
  • Printer Group Definition

LSF 10.0.7

  • Distribution Group Definition
  • Job Queue Definition
  • Job Queue Group Definition
  • Language Definition
  • Locale Definition
  • Printer Definition
  • Printer Group Definition

LSF 10.0.8

  • Distribution Group Definition
  • Distribution List Group Definition
  • Job Queue Definition
  • Job Queue Group Definition
  • Language Definition
  • Locale Definition
  • Printer Definition
  • Printer Group Definition

Controlling Access

Users with PortalAdmin access will be able to access any of the tools that are available without any need for additional configuration.  Navigator widget links will be available under a new branch of Infor Lawson, LSF Administration Tools, for any user with access to one or more tools.

Navigator

For non-Admin users, access to the tools can be granted on the Administration tab in Role Manager.

RoleXml

Distribution Group Definition

DistributionGroup

Distribution List Group Definition

ListGroup

Job Queue Definition

QueueDef

Job Queue Group Definition

QueueGroupDef

Language Definition

LangDef

Locale Definition

LocaleDefinition

Printer Definition

printerDef

Printer Group Definition

printerGroupDef

Language Translation

For Languages other than English, a Translation Maintenance screen with several tabs is available to translate various phrases and messages defined in the system.  A page size can be selected to set the number of records returned. And columns with a filter field can be filtered much like filters work elsewhere within Lawson screens.

translation

To edit a phrase or message simply click on the Edit icon or the text under Translation:

editTranslation

When done editing on a particular tab, click the Save toolbar button to save changes for that tab. No reminder to save changes will be presented, but the Save button is only enabled if there are pending changes and each line with a pending change will be highlighted with a yellow icon on the left edge.

Phrases Translation

Phrases

Column Phrases Translation

ColumnPhrases

Titles Translation

titles

Value Lists Translation

values

Universe Message Translation

message

Application Messages Translation

appMessage