I’m waiting for a database export when it occurred to me that I haven’t discussed the Customer Extension table which is really terrible as I’ve been using it for quite a while and it is awesome!
The customer extension table APIs allow us to store data within M3 that M3 doesn’t have fields with. There are some fantastic examples in the net change reports where it is combined with the native M3 events to populate data based on different events automatically, and of-course we can use them through the APIs to store additional data. We can also incorporate these values in to the new style ListViews without any code!
The APIs provided are quick and easy to use.
This post is to provide a Jscript which allows you to add a TextBox to a panel and it will store the data from the TextBox in the customer extension table – how often do people want to do that? 🙂
Figure 1 – example of incorporating data from the customer extension table without coding around the ListView
Figure 2 – comboboxes that store additional data for the csutomer in the customer extension table (this has a Jscript to provide the fields)
The script I’m posting today is designed around being generic so if you want to add a single field, it’s pretty easy to use just by specifying some arguments to the script. And it provides a starting point to customising to your needs.
The script will do some checks to make sure we have a minimum number of arguments before adding a Label and a TextBox to the panel and will also look at an existing TextBox on the panel to determine if we should allow the user to edit our TextBox or if we should only display our value.
It will check to see if there is a matching value in the customer extension table and if there is populate our TextBox.
We will then wait for a Next event, if this occurs we will retrieve the values from our Key TextBoxes and our custom TextBox and write the data to the customer extension table.
Pretty simple really!
Arguments are as follows:
,,,,,,,,[PK02],[PK03],[PK04],[PK05],[PK06],[PK07],[PK08]
The yellow highlighted arguments relate to the UI, the green highlighted relate back to the database.
Label Text the Text we display in the label for our TextBox
Label Column the grid column placement for the label
Label Width the width of the label (we will automatically calculate the column span)
Column the column for the TextBox
Width the width of the TextBox
Row the Grid Row we will set for the Label and TextBox
Read Only Key Field this is the TextBox that we will check to see if we are in display or edit mode
CUG File the F1FILE name we will use – this is one of the search keys so should be unique and meaningful
PK01 the name of a TextBox we will use as part of our key for lookup, stored in F1PK01
Optional fields
[PK02..PK08] up to 7 additional TextBoxes we can use as keys – typically these should not be changeable by the user and will be used for our record lookup. They are stored in F1PK02 – F1PK08
So what does it look like?
Using the script with the following arguments:
My Label,40,100,51,100,1,MMITNE,SACTEST,WEITNO
Yields this.
Figure 3 – Script loaded when the panel is in edit mode
We use the Ext item Number TextBox to determine if we are in display, so when it is read only we set our TextBox to read only (technically we just change the style)
Figure 4 – script loaded when we are in display mode
Now if we take a look at the database…SACTEST was what we assigned the CUG File (F1FILE) so we were search on that
F1FILE = SACTEST
F1PK01 = our item number
F1A030 = our stored value
We can also see the F1PK01 – F1PK08 fields, these are indexed and the script allows all 8 to be used as our ‘uniqueness’ values.
And now the script itself.
/* ** Name: AddControl.js ** ** Description: ** Adds a textbox to a panel the contents of which will be read from/saved to the customer extension tables ** Uniqiness is defined by the PKxx keys which must be associated with textboxes ** We also handle situations where we are in display mode by keying off an existing textbox which changes from ** read only to editable depending on display/edit ** ** Notes: ** we get the keys from the UI at the point we save, this means that if the key textboxes are changable, we may get ** not have the expected results, however this may be the expected result 🙂 ** ** If the user enters a blank value in to our textbox we don't delete the record, we just save the A030 as blank ** ** Don't use comments in the label text! ** ** Arguments: ** ** <label text>,<label column>,<label width>,<column>,<width>,<row>,<read only key field>,<CUG File>,<PK01>,[PK02],[PK03],[PK04],[PK05],[PK06],[PK07],[PK08] ** ** Eg on MMS001/E ** My Label,40,100,51,100,1,MMITNE,SACTEST,WEITNO ** - My Label = the label we will put next to the textbox ** - 40 = the grid column the label goes ** - 100 = with width of the label ** - 51 = the grid column of the textbox ** - 100 = width of the textbox ** - 1 = the row we will use for the label and textbox ** - MMITNE = the TextBox that will change from being read only and editable depending on whether we display/edit ** - SACTEST = the F1FILE field that we will store against in the Customer Extension table (CUGEX1) ** - WEITNO = this will be the first and only of our keys ** In the CUGEX1 table we will have ** F1FILE = SACTEST ** F1PK01 = <item number> ** F1A030 = <the value of our textbox> ** ** Written By: scott.campbell@potatoit.kiwi ** ** */ import System; import System.Windows; import System.Windows.Controls; import MForms; import Mango.UI.Core; import Lawson.M3.MI; package MForms.JScript { class AddControl { var gDebug = null; var gController = null; var gContent = null; var gTextBox : TextBox = new TextBox(); // this is the control that we will use to determine if // we should be read only var gReadOnlyControl = null; var gReadOnlyControlName = null; var gControlColumn = -1; var gControlRow = -1; var gControlWidth = -1; var gLabelColumn = -1; var gLabelWidth = -1; var gLabelContent = null; var gCUGFile = null; // store our TextBoxes here var gKeyField1 = null; var gKeyField2 = null; var gKeyField3 = null; var gKeyField4 = null; var gKeyField5 = null; var gKeyField6 = null; var gKeyField7 = null; var gKeyField8 = null; // have we finished retrieving our value? var gRetrieveValue = false; public function Init(element: Object, args: Object, controller : Object, debug : Object) { gController = controller; gContent = controller.RenderEngine.Content; gDebug = debug; try { if(null != args) { var argumentArray = args.split(","); if(null != argumentArray) { if(argumentArray.length > 8) { for(var i = 0; i < argumentArray.length; i++) { var currentArgument = argumentArray[i]; if(false == String.IsNullOrWhiteSpace(currentArgument)) { switch(i) { case 0: gLabelContent = currentArgument; break; case 1: gLabelColumn = currentArgument; break; case 2: gLabelWidth = currentArgument; break; case 3: gControlColumn = currentArgument; break; case 4: gControlWidth = currentArgument; break; case 5: gControlRow = currentArgument; break; case 6: gReadOnlyControlName = currentArgument; break; case 7: gCUGFile = currentArgument; break; case 8: gKeyField1 = getTextBox(currentArgument); break; case 9: gKeyField2 = getTextBox(currentArgument); break; case 10: gKeyField3 = getTextBox(currentArgument); break; case 11: gKeyField4 = getTextBox(currentArgument); break; case 12: gKeyField5 = getTextBox(currentArgument); break; case 13: gKeyField6 = getTextBox(currentArgument); break; case 14: gKeyField7 = getTextBox(currentArgument); break; case 15: gKeyField8 = getTextBox(currentArgument); break; } } } if(true == doWeHaveEnoughParameters()) { gReadOnlyControl = ScriptUtil.FindChild(gContent, gReadOnlyControlName); if(null != gReadOnlyControl) { // we have passed our preliminary checks, add the controls to the panel addControls(); // subscribe to the events so we can capture the next event subscribeToEvents(); // if we are in display, we should set our control to read only if(true == areWeReadOnly(gReadOnlyControl)) { gTextBox.Style = gReadOnlyControl.Style; } // attempt to retrieve the value we will populate the TextBox with // from the customer extension table var request = CUSEXTMI_GetFieldValue(gCUGFile, safeGetTextBoxValue(gKeyField1), safeGetTextBoxValue(gKeyField2), safeGetTextBoxValue(gKeyField3), safeGetTextBoxValue(gKeyField4), safeGetTextBoxValue(gKeyField5), safeGetTextBoxValue(gKeyField6), safeGetTextBoxValue(gKeyField7), safeGetTextBoxValue(gKeyField8)); MIWorker.Run(request, OnGetFieldValueRunComplete); } else { gDebug.Error("Failed to locate the read only control (" + gReadOnlyControlName + "), exiting"); } } else { gDebug.Error("We don't have enough parameters"); } } else { gDebug.Error("Not enough parameters"); } } } } catch(ex) { debug.Error(ex); } } private function getTextBox(aName) { var result = null; if(false == String.IsNullOrWhiteSpace(aName)) { result = ScriptUtil.FindChild(gContent, aName); if(null == result) { gDebug.Error("Failed to locate TextBox: " + aName); } } return(result); } // a safe retrieval of the TextBox Text field private function safeGetTextBoxValue(aTextBox) { var result = null; if(null != aTextBox) { result = aTextBox.Text; } return(result); } // check to see if we have enough valid values to continue private function doWeHaveEnoughParameters() { var result = false; if( null != gLabelContent && -1 != gLabelColumn && -1 != gLabelWidth && -1 != gControlColumn && -1 != gControlWidth && -1 != gControlRow && false == String.IsNullOrWhiteSpace(gReadOnlyControlName) && false == String.IsNullOrWhiteSpace(gCUGFile) && false == String.IsNullOrWhiteSpace(gKeyField1) ) { result = true; } return(result); } public function OnGetFieldValueRunComplete(response : MIResponse) { if(null != response) { if(false == response.HasError) { if(null != gTextBox && response.Item != null) { gTextBox.Text = response.Item.GetString("A030"); gRetrieveValue = true; } } } } public function OnRequested(sender : Object, e : RequestEventArgs) { if(MNEProtocol.CommandTypeKey == e.CommandType && MNEProtocol.KeyEnter == e.CommandValue) { var request : MIRequest = null; if(true == gRetrieveValue) { request = CUSEXTMI_ChgFieldValue(gCUGFile, safeGetTextBoxValue(gKeyField1), safeGetTextBoxValue(gKeyField2), safeGetTextBoxValue(gKeyField3), safeGetTextBoxValue(gKeyField4), safeGetTextBoxValue(gKeyField5), safeGetTextBoxValue(gKeyField6), safeGetTextBoxValue(gKeyField7), safeGetTextBoxValue(gKeyField8), safeGetTextBoxValue(gTextBox)); gDebug.Debug(request.Record.ToLogString()); } else { request = CUSEXTMI_AddFieldValue(gCUGFile, safeGetTextBoxValue(gKeyField1), safeGetTextBoxValue(gKeyField2), safeGetTextBoxValue(gKeyField3), safeGetTextBoxValue(gKeyField4), safeGetTextBoxValue(gKeyField5), safeGetTextBoxValue(gKeyField6), safeGetTextBoxValue(gKeyField7), safeGetTextBoxValue(gKeyField8), safeGetTextBoxValue(gTextBox)); } // fire and forget MIWorker.Run(request, OnSaveRunCompleted); } if(MNEProtocol.CommandTypePage != e.CommandType) { unsubscribeFromEvents(); } } public function OnSaveRunCompleted(response : MIResponse) { // } private function subscribeToEvents() { gDebug.Debug("Subscribing to events"); gController.add_Requested(OnRequested); } private function unsubscribeFromEvents() { gDebug.Debug("Unsubscribing from events"); gController.remove_Requested(OnRequested); } private function areWeReadOnly(aReadControl) { var result = false; if(null != aReadControl) { if(StyleManager.StyleTextBoxDisabled == aReadControl.Style) { result = true; } } return(result); } private function addControls() { var label = new Label(); label.Content = gLabelContent; label.Width = gLabelWidth; setPosition(label, gLabelColumn, gControlRow); gContent.Children.Add(label); var gridColumnWidth = calculateGridColumnWidth(gContent); var labeltextBoxColumnSpan = 0; var textBoxColumnSpan = 0; if(0 != gridColumnWidth) { textBoxColumnSpan = gControlWidth / gridColumnWidth; labeltextBoxColumnSpan = gLabelWidth / gridColumnWidth; if(0 === gControlWidth % gridColumnWidth) { textBoxColumnSpan += 1; } if(0 === gLabelWidth % gridColumnWidth) { labeltextBoxColumnSpan += 1; } Grid.SetColumnSpan(gTextBox, textBoxColumnSpan); Grid.SetColumnSpan(label, labeltextBoxColumnSpan); } gTextBox.Height = Configuration.ControlHeight; gTextBox.Margin = Configuration.ControlMargin; gTextBox.Padding = Configuration.ControlPadding; gTextBox.Width = gControlWidth; gTextBox.MaxLength = 30; setPosition(gTextBox, gControlColumn, gControlRow); gContent.Children.Add(gTextBox); } private function calculateGridColumnWidth(aContent) { var result = 0; if(null != aContent && null != aContent.ColumnDefinitions && aContent.ColumnDefinitions.Count > 0) { result = aContent.ColumnDefinitions[0].ActualWidth; } return(result); } private function setPosition(aControl, aColumn, aRow) { if(null != aControl) { gDebug.Debug("Set Controls Position"); gDebug.Debug(" +-- Control: " + aControl.Name); gDebug.Debug(" +---- Column: " + aColumn); gDebug.Debug(" +---- Row: " + aRow); Grid.SetColumn(aControl, aColumn); Grid.SetRow(aControl, aRow); } } private function CUSEXTMI_GetFieldValue(aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08) { var request = new MIRequest(); var inRecord = new MIRecord(); inRecord["FILE"] = aFile; inRecord["PK01"] = aPK01; if(null != aPK02) inRecord["PK02"] = aPK02; if(null != aPK03) inRecord["PK03"] = aPK03; if(null != aPK04) inRecord["PK04"] = aPK04; if(null != aPK05) inRecord["PK05"] = aPK05; if(null != aPK06) inRecord["PK06"] = aPK06; if(null != aPK07) inRecord["PK07"] = aPK07; if(null != aPK08) inRecord["PK08"] = aPK08; // if(false == String.IsNullOrWhiteSpace(aPK02)) inRecord["PK02"] = aPK02; // if(false == String.IsNullOrWhiteSpace(aPK03)) inRecord["PK03"] = aPK03; // if(false == String.IsNullOrWhiteSpace(aPK04)) inRecord["PK04"] = aPK04; // if(false == String.IsNullOrWhiteSpace(aPK05)) inRecord["PK05"] = aPK05; // if(false == String.IsNullOrWhiteSpace(aPK06)) inRecord["PK06"] = aPK06; // if(false == String.IsNullOrWhiteSpace(aPK07)) inRecord["PK07"] = aPK07; // if(false == String.IsNullOrWhiteSpace(aPK08)) inRecord["PK08"] = aPK08; request.Record = inRecord; var parameters = new MIParameters(); var outFields : String[] = new String[1]; outFields[0] = "A030"; parameters.OutputFields = outFields; request.Program = "CUSEXTMI"; request.Transaction = "GetFieldValue"; return(request); } private function CUSEXTMI_Save(aTransaction, aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aA030) { var request = new MIRequest(); var inRecord = new MIRecord(); inRecord["FILE"] = aFile; inRecord["PK01"] = aPK01; if(null != aPK02 && false == String.IsNullOrWhiteSpace(aPK02)) inRecord["PK02"] = aPK02; if(null != aPK03 && false == String.IsNullOrWhiteSpace(aPK03)) inRecord["PK03"] = aPK03; if(null != aPK04 && false == String.IsNullOrWhiteSpace(aPK04)) inRecord["PK04"] = aPK04; if(null != aPK05 && false == String.IsNullOrWhiteSpace(aPK05)) inRecord["PK05"] = aPK05; if(null != aPK06 && false == String.IsNullOrWhiteSpace(aPK06)) inRecord["PK06"] = aPK06; if(null != aPK07 && false == String.IsNullOrWhiteSpace(aPK07)) inRecord["PK07"] = aPK07; if(null != aPK08 && false == String.IsNullOrWhiteSpace(aPK08)) inRecord["PK08"] = aPK08; // if(false == String.IsNullOrWhiteSpace(aPK02)) inRecord["PK02"] = aPK02; // if(false == String.IsNullOrWhiteSpace(aPK03)) inRecord["PK03"] = aPK03; // if(false == String.IsNullOrWhiteSpace(aPK04)) inRecord["PK04"] = aPK04; // if(false == String.IsNullOrWhiteSpace(aPK05)) inRecord["PK05"] = aPK05; // if(false == String.IsNullOrWhiteSpace(aPK06)) inRecord["PK06"] = aPK06; // if(false == String.IsNullOrWhiteSpace(aPK07)) inRecord["PK07"] = aPK07; // if(false == String.IsNullOrWhiteSpace(aPK08)) inRecord["PK08"] = aPK08; inRecord["A030"] = aA030; request.Record = inRecord; request.Program = "CUSEXTMI"; request.Transaction = aTransaction; return(request); } private function CUSEXTMI_ChgFieldValue(aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aA030) { return(CUSEXTMI_Save("ChgFieldValue", aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aA030)); } private function CUSEXTMI_AddFieldValue(aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aA030) { return(CUSEXTMI_Save("AddFieldValue", aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aA030)); } } }
Enjoy,
Scott
In which scenario would you advice to use this solution vs a database extension?
A database extension? If you mean changing the M3 database tables / adding new tables to the M3 database, then I would council against doing that very strongly – it will come back to bite you.
The customer extension tables have been provided for the purpose of storing additional data to prevent changes to the structure of the M3 database – though this script only takes advantage of a single field, there are multiple alpha fields, multiple numeric fields which are available in a single record / API call.
If a record was storing very large numbers of fields for a record then you can split it in to multiple records or you could consider creating your own database outside of M3 and using MWS webservices to manipulate the record.
I meant adding extra tables using MAK (M3 adaptation Kit). For instance creating ZITMAS that has the same index as MITMAS but holds additional item master data.
Infor created the extension tables to get away from people modifying M3 via MAK. I strongly recommend that people work to get rid of modifications and get to standard M3, it makes support and upgrades far quicker and easier. If people are considering modifications, I will do my best to convince them that this is not the route to go – I’ve seen far too many companies regret their modifications come upgrade or even patch time.
Infor, like most ERP vendors is moving towards hosting and though Infor have a product where you can bring your mods in to the cloud, it will become harder and more expensive as they push everyone towards standard multi-tentanted solutions.
Cheers,
Scott
Oké that’s clear, Thanks!
Please note that in 13.4 there is a Metadata function added to the customer extension fields (CDF). The function is called CMS080 and through that name, description, type etc are maintained for each CDF. Please also note that from 13.4 the metadata entry is mandatory to be able to use the CDF´s
Thanks Magnus,
I gather that this metadata is mandatory if you are using the native M3 functionality to access the data?
Is there any implications from an upgrade perspective where customers are using the extended toolboxes to display data from the customer extension tables?
And for peoples reference, you can read about CMS080 in KB: 1824822 and document ID 49129 entitled
“M3 13.4 – Business Engine Net Change Overview – What s new in detail”
Both the API (CUSEXTMI) and the usage in configurable lists requires a corresponding metadata record in CMS080 in order for it to be possible to use the CDF´s. It is a one time activity to add the records into CMS080 at an upgrade so it is not a bit task but you need to be aware. Secondly it gives a number of advantages like field descriptions, validation of values etc. Through the usage of the text (classic F6) in CMS080 you can also get into a sort of user defined help text through the script (text ID is included in the CMS080MI transaction).
Thank you for the explanation Magnus.
Hi, good post.
I have an error when launching the script
DEBUG: Set Controls Position
DEBUG: +– Control:
DEBUG: +—- Column: 50
DEBUG: +—- Row: 6
ERROR: TypeError: Type mismatch
an idea please
Thank
Hi Yvon,
check the script arguments, things like the label column, widths etc have to be numbers – if you’ve missed a field or a comma then you’ll probably get a similar message.
The other thing that may do it is the “read only key field”, it must be a TextBox and it should be a TextBox that will toggle between enabled and disabled depending on whether the user is changing or displaying the data in the panel.
Cheers,
Scott
Hi Scott,
I dont understand, I have a copy paste of your arguments and on the MMS001 / E:
My Label, 40,100,51,100.1, MMITNE, SACTEST, WEITNO
I dont understand the second problem you. What should I do please
thank you
Cheers
Yvon
In the arguments you’ve pasted, you have
My Label, 40,100,51,100.1, MMITNE, SACTEST, WEITNO
The arguments in my article are different
My Label,40,100,51,100,1,MMITNE,SACTEST,WEITNO
Note that you have
100.1, MMITNE
rather than
100,1,MMITNE
Cheers,
Scott
I’m sorry,
In fact I have
My Label,40,100,51,100,1,MMITNE,SACTEST,WEITNO
the message is :
DEBUG: Set Controls Position
DEBUG: +– Control:
DEBUG: +—- Column: 40
DEBUG: +—- Row: 1
ERROR: TypeError: Type mismatch
I have that letter M that appears
Help thank
Using those arguments on MMS001/E works without error in my environment.
Are you using those arguments on MMS001/E?
What version of Smart Office (including the build)?
Cheers,
Scott
Hi Yvon,
I had the same error, and i turned out to be related to localisations due to some users having their PC set as Decimal Comma instead of Decimal points and the calculation below caused a fractional value with a decimal point that fails on some machines.
textBoxColumnSpan = gControlWidth / gridColumnWidth;
labeltextBoxColumnSpan = gLabelWidth / gridColumnWidth;
….
Grid.SetColumnSpan(gTextBox, textBoxColumnSpan);
Grid.SetColumnSpan(label, labeltextBoxColumnSpan);
Solution was to change the calculation like this (to round up to next Integer):
textBoxColumnSpan = Math.ceil(gControlWidth / gridColumnWidth);
labeltextBoxColumnSpan = Math.ceil(gLabelWidth / gridColumnWidth);
Hope this helps.
Rene
Thank you I will watch when I have a moment.
This is really helpful.When setting the Grid.SetColumnSpan(gTextBox, textBoxColumnSpan) value getting type cast issue. After applying the fix it’s working fine.
(textBoxColumnSpan should be int value.)
Yes in MMS001/E
Version : 10.2.1.0.200
BE 15.1.4 MCP1 – 1514 – 05
Cheers
Yvon
Hi Yvon,
please see the comments from Magnus on this article. He mentions that there needs to be a CMS080 entry for the field you’re adding.
When I get some free time with a 13.4 environment, I’ll take a look at modifying this script so it can automatically generated the info or documenting what needs to be done.
Cheers,
Scott
Hi Scott,
thank you for your reply. I will look at the CMS080
Cheers
Yvon
I have created a “numeric” version of this script as well including field length and decimal point control if someone is interested.
Also changed the delimiter to “Pipe” to ensure international compatibility.
/*
** Name: AddControl_Num.js
**
** Description:
** Adds a Numeric field to a panel the contents of which will be read from/saved to the customer extension tables
** Uniqiness is defined by the Nxxx keys which must be associated with numeric textboxes
** We also handle situations where we are in display mode by keying off an existing textbox which changes from
** read only to editable depending on display/edit
**
** Notes:
** we get the keys from the UI at the point we save, this means that if the key textboxes are changable, we may get
** not have the expected results, however this may be the expected result
**
** If the user enters a blank value in to our textbox we don’t delete the record, we just save the N096 as 0.0
**
** Don’t use comments in the label text!
**
** Arguments:
**
** ||||||||||||[PK02]|[PK03]|[PK04]|[PK05]|[PK06]|[PK07]|[PK08]
**
** Eg on MMS002/E
** My Label|40|100|51|50|1|5|0|MBRESP|SACTEST|N096|WEWHLO|WEITNO
** – My Label = the label we will put next to the textbox
** – 40 = the grid column the label goes
** – 100 = with width of the label
** – 51 = the grid column of the textbox
** – 100 = width of the textbox
** – 1 = the row we will use for the label and textbox
** – 10 = Max length of Text
** – 0 = Decimals (If 0 then integer), maximum 6 decimals
** – MBRESP = the TextBox that will change from being read only and editable depending on whether we display/edit
** – SACTEST = the F1FILE field that we will store against in the Customer Extension table (CUGEX1)
** – WEITNO = this will be the first and only of our keys
** In the CUGEX1 table we will have
** F1FILE = SACTEST
** F1PK01 =
** F1N096 =
**
** Written By: scott.campbell@potatoit.kiwi
** Co-Author: Rene Bottern (Based on AddControl.js)
**
*/
// Default Operation for MMS002/E
// Label Text, Label Column, Label Width, Column, Width, Row, MaxLen, Decimals, ReadOnly FieldRef, CMS080 File, CMS080 Field4
// Operation|0|80|14|40|10|5|0|MBRESP|MITBAL|N196|WEWHLO|WEITNO
import System;
import System.Windows;
import System.Windows.Controls;
import MForms;
import Mango.UI.Core;
import Lawson.M3.MI;
package MForms.JScript
{
class AddControl_Num
{
var gDebug = null;
var gController = null;
var gContent = null;
var gTextBox : TextBox = new TextBox();
// this is the control that we will use to determine if
// we should be read only
var gReadOnlyControl = null;
var gReadOnlyControlName = null;
var gControlColumn = -1;
var gControlRow = -1;
var gControlWidth = -1;
var gControlMaxLength = -1;
var gControlDecimals = -1;
var gLabelColumn = -1;
var gLabelWidth = -1;
var gLabelContent = null;
var gCUGFile = null;
var gCUGField4 = null;
// store our TextBoxes here
var gKeyField1 = null;
var gKeyField2 = null;
var gKeyField3 = null;
var gKeyField4 = null;
var gKeyField5 = null;
var gKeyField6 = null;
var gKeyField7 = null;
var gKeyField8 = null;
// have we finished retrieving our value?
var gRetrieveValue = false;
public function Init(element: Object, args: Object, controller : Object, debug : Object)
{
gController = controller;
gContent = controller.RenderEngine.Content;
gDebug = debug;
try
{
if(null != args)
{
var argumentArray = args.split(“|”);
if(null != argumentArray)
{
if(argumentArray.length > 10)
{
for(var i = 0; i Comma using regex characters to replace ALL instances
// labeltextBoxColumnSpan = labeltextBoxColumnSpan.replace(“.”,”,”)
//}
Grid.SetColumnSpan(gTextBox, textBoxColumnSpan);
Grid.SetColumnSpan(label, labeltextBoxColumnSpan);
}
gTextBox.Height = Configuration.ControlHeight;
gTextBox.Margin = Configuration.ControlMargin;
gTextBox.Padding = Configuration.ControlPadding;
gTextBox.Width = gControlWidth;
gTextBox.MaxLength = gControlMaxLength;
setPosition(gTextBox, gControlColumn, gControlRow);
gContent.Children.Add(gTextBox);
gTextBox.add_TextChanged(OnTextChanged); //Check for entry of only numeric value
}
function OnTextChanged(sender: Object, e: TextChangedEventArgs) {
if (sender.Text /*validation expression here*/) {
//gDebug.Debug(gTextBox.Text);
if(isNumber(gTextBox.Text.substr(gTextBox.Text.length-1)) == false ) gTextBox.Text = gTextBox.Text.substr(0, gTextBox.Text.length – 1);
} else {
// invalid
}
}
function isNumber(evt) {
var charCode = evt.charCodeAt(0);
//gDebug.Debug(evt.charCodeAt(0));
if ((charCode >= 48 && charCode 0)
{
result = aContent.ColumnDefinitions[0].ActualWidth;
}
return(result);
}
private function setPosition(aControl, aColumn, aRow)
{
if(null != aControl)
{
//gDebug.Debug(“Set Controls Position”);
//gDebug.Debug(” +– Control: ” + aControl.Name);
//gDebug.Debug(” +—- Column: ” + aColumn);
//gDebug.Debug(” +—- Row: ” + aRow);
Grid.SetColumn(aControl, aColumn);
Grid.SetRow(aControl, aRow);
}
}
private function CUSEXTMI_GetFieldValue(aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08)
{
var request = new MIRequest();
var inRecord = new MIRecord();
inRecord[“FILE”] = aFile;
inRecord[“PK01”] = aPK01;
if(null != aPK02) inRecord[“PK02”] = aPK02;
if(null != aPK03) inRecord[“PK03”] = aPK03;
if(null != aPK04) inRecord[“PK04”] = aPK04;
if(null != aPK05) inRecord[“PK05”] = aPK05;
if(null != aPK06) inRecord[“PK06”] = aPK06;
if(null != aPK07) inRecord[“PK07”] = aPK07;
if(null != aPK08) inRecord[“PK08”] = aPK08;
request.Record = inRecord;
var parameters = new MIParameters();
var outFields : String[] = new String[1];
outFields[0] = gCUGField4;
parameters.OutputFields = outFields;
request.Program = “CUSEXTMI”;
request.Transaction = “GetFieldValue”;
return(request);
}
private function CUSEXTMI_Save(aTransaction, aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aNum)
{
try
{
var request = new MIRequest();
var inRecord = new MIRecord();
inRecord[“FILE”] = aFile;
inRecord[“PK01”] = aPK01;
if(null != aPK02 && false == String.IsNullOrWhiteSpace(aPK02)) inRecord[“PK02”] = aPK02;
if(null != aPK03 && false == String.IsNullOrWhiteSpace(aPK03)) inRecord[“PK03”] = aPK03;
if(null != aPK04 && false == String.IsNullOrWhiteSpace(aPK04)) inRecord[“PK04”] = aPK04;
if(null != aPK05 && false == String.IsNullOrWhiteSpace(aPK05)) inRecord[“PK05”] = aPK05;
if(null != aPK06 && false == String.IsNullOrWhiteSpace(aPK06)) inRecord[“PK06”] = aPK06;
if(null != aPK07 && false == String.IsNullOrWhiteSpace(aPK07)) inRecord[“PK07”] = aPK07;
if(null != aPK08 && false == String.IsNullOrWhiteSpace(aPK08)) inRecord[“PK08”] = aPK08;
//gDebug.Debug(“aNum: ” + float(aNum));
//gDebug.Debug(“gCUGField4: ” + gCUGField4);
//inRecord[gCUGField4] = aNum.Number;
inRecord[gCUGField4] = float(aNum).toFixed(gControlDecimals);
request.Record = inRecord;
request.Program = “CUSEXTMI”;
request.Transaction = aTransaction;
return(request);
}
catch(ex)
{
gDebug.Error(ex);
}
}
private function CUSEXTMI_ChgFieldValue(aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aNum)
{
return(CUSEXTMI_Save(“ChgFieldValue”, aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aNum));
}
private function CUSEXTMI_AddFieldValue(aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aNum)
{
return(CUSEXTMI_Save(“AddFieldValue”, aFile, aPK01, aPK02, aPK03, aPK04, aPK05, aPK06, aPK07, aPK08, aNum));
}
}
}
And for peoples reference, you can read about CMS080 in KB: 1824822 and document ID 49129 entitled
“M3 13.4 – Business Engine Net Change Overview – What s new in detail” I’m sorry,
In fact I have
My Label,40,100,51,100,1,MMITNE,SACTEST,WEITNO
the message is :
DEBUG: Set Controls Position
DEBUG: +– Control:
DEBUG: +—- Column: 40
DEBUG: +—- Row: 1
ERROR: TypeError: Type mismatch
I have that letter M that appears
Help thank
And for peoples reference, you can read about CMS080 in KB: 1824822 and document ID 49129 entitled
“M3 13.4 – Business Engine Net Change Overview – What s new in detail” I’m sorry,
In fact I have
My Label,40,100,51,100,1,MMITNE,SACTEST,WEITNO
the message is :
DEBUG: Set Controls Position
DEBUG: +– Control:
DEBUG: +—- Column: 40
DEBUG: +—- Row: 1
ERROR: TypeError: Type mismatch
I have that letter M that appears
Help thank I’m sorry,
In fact I have
My Label,40,100,51,100,1,MMITNE,SACTEST,WEITNO
the message is :
DEBUG: Set Controls Position
DEBUG: +– Control:
DEBUG: +—- Column: 40
DEBUG: +—- Row: 1
ERROR: TypeError: Type mismatch
I have that letter M that appears
Help thank
I’ve been playing around with this today and have it working in the script editor and it shows on the MMS001 panel. When I am not in the script editor it does not seem to run. I have attached the script using a personalization but it does not seem to run on its own. What might I be missing? I am using 13.4.
Mike
Hi Mike,
My guess is it is a naming issue.
The name of the class needs that has the Init() method needs to be the same name as the script and the personalisation.
So if your script is
foobar.js
the class needs to be foobar
and the personalisation should be foobar (foobar.js will also work)
Eg.
import MForms;
package MForms.JScript
{
class foobar
{
If you take a look at the Smart Office logs on the Smart Office client you should see it complaining that something is wrong. I also recommend changing the Smart Office clients logging to debug.
Cheers,
Scott
Thanks for the quick reply Scott. I took a look at the log and this is what I see:
2/6/2018 10:05:15 AM [Mango.Main] ERROR Mango.UI.Script.ScriptManager.LoadScript MUI0005 – Failed to compile script http://xxx.yyy.com:21107/mne/jscript/AddControl.js
C:\Users\mwolfe\AppData\Local\Temp\1gctn0ke.0.js(157,37) : error JS1014: Invalid character
The code does work in the jScript editor, just not in ISO.
Hi Mike,
that’s rather odd.
The message indicates there is an issue with line 157, I’d check it for any odd characters. Did you copy and paste some of the code from elsewhere?
Maybe take a look in Notepad or even a hex editor to look for anything anomalous.
Cheers,
Scott
Scott, definitely something I could not see. RIght now ISO does not consider tab order for these fields. So I have to mouse into them to get there…same thing in H5 though.
Thanks for all your help.
Mike
Hi, thanks for this usefull script. Any idea on how to add, instead of a text box, either a date field (with calendar check) or a combo box with predefined list of values
Thanks in advance
The script can be used as a template to add whichever WPF controls you want – be that a ComboBox, DatePicker, CheckBox. One of the nice things about WPF is there is consistency on the field names so it shouldn’t require too much adapting.