InforCRM client-side validation
Posted By: nicocrm on August 24th, 2015 in General
No Gravatar

In most case I try to do the validation for InforCRM form input on the server side. This is generally easier to implement (sometimes a lot easier), more reliable, and the performance is usually close (sometimes even better, if there are a lot of queries involved, as each one requires an sdata round trip when performed from the client side!) Reporting an error to the user and interrupting processing is very easy, all that is required is throwing an instance of a Sage.Platform.Application.ValidationException object:

throw new ValidationException("No way!");

However sometimes the server-side validation is not enough. The best example is when you need to ask confirmation from the user. This always requires some javascript to do the actual prompt – you can still drive the process from the server side by using hidden buttons triggered from the script but it can get cumbersome very quickly. Client-side validation can also result in a more responsive interface, especially when it can be performed synchronously (without an sdata query).

Here is a simple example that gives the user a confirmation prompt if they have not selected enough products on a new opportunity:


    String script = String.Format(@"
require(['dojo/ready', 'dojo/on', 'dojo/dom', 'dijit/registry'], function(ready, on, dom, registry) {{
    function onSaveClick(e) {{
        var grid = registry.byId('OpportunityProductsgrdOppProducts');
        var prodCount = grid.store.dataCacheToArray().length;
        if(prodCount <= 1){{
            if(!confirm('Are you sure you wish to submit this opportunity with less than 2 products?')) {{
                e.preventDefault();
            }}
        }}
    }}

    ready(function() {{
        on(dom.byId('{0}'), 'click', onSaveClick);
        on(dom.byId('{1}'), 'click', onSaveClick);
    }});
}});
", cmdSave.ClientID, cmdSaveNew.ClientID);
ScriptManager.RegisterStartupScript(Page, GetType(), "ProductValidation", script, true);

If you need an asynchronous validation this is a little bit more complex because you need to interrupt the normal flow of the button then resume it if the validation succeeds. You can use __doPostBack to that effect. Here is the same validation, using an asynchronous dialog. Keep in mind raiseQueryDialog will return immediately and note the e.preventDefault() that is invoked before the dialog actually returns a result.

    String script = String.Format(@"
require(['dojo/ready', 'dojo/on', 'dojo/dom', 'dijit/registry'], function(ready, on, dom, registry) {{
    function onSaveClick(e) {{
        var grid = registry.byId('OpportunityProductsgrdOppProducts');
        var prodCount = grid.store.dataCacheToArray().length;
        if(prodCount <= 1){{
            Sage.UI.Dialogs.raiseQueryDialog('Not enough products', 
                'Are you sure you wish to submit this opportunity with less than 2 products?', 
                function(result) {{                    
                    if(result) {{
                        __doPostBack(e.target.name, '');
                    }}
                }}, 'OK', 'Cancel');
            e.preventDefault();            
        }}
    }}

    ready(function() {{
        on(dom.byId('{0}'), 'click', onSaveClick);
        on(dom.byId('{1}'), 'click', onSaveClick);
    }});
}});
", cmdSave.ClientID, cmdSaveNew.ClientID);
ScriptManager.RegisterStartupScript(Page, GetType(), "ProductValidation", script, true);

Accessing InforCRM control values from Javascript
Posted By: nicocrm on July 1st, 2015 in General, Saleslogix
No Gravatar

Often when one needs to access the value set in an HTML control from the client side script it is tempting to reach into the DOM object and retrieve it directly, using something like this for example:

var c = document.getElementById('TabControl_element_AccountOpportunities_element_view_AccountOpportunities_AccountOpportunities_InactiveTotal_InputCurrency_CurrencyTextBox');
// this will retrieve the value as a string - still needs to be parsed as a number!
var value = c.value;

Then to set the value something like:

// need to implement "formatValue" somehow!
c.value = formatValue(value);

The hard-coded id is not great of course but the main problem with the approach in my opinion is the fact that you’ll bypass the localization logic and have to parse / format the numbers yourself. Another potential issue is that because the logic of the “dijit” (the client-side widget used to render and control the currency textbox) is bypassed it will cause its internal state to be inconsistent. Often it is more reliable to access the dijit instead, using code such as:

var c = dijit.byId('TabControl_element_AccountOpportunities_element_view_AccountOpportunities_AccountOpportunities_InactiveTotal_InputCurrency_CurrencyTextBox');
// this will retrieve the "parsed" value as a number
var value = c.get('value');

And to set it:

c.set('value', 3000);

If you have some good examples of accessing the controls from client side script please share them in the comments!


Unspecified Error logging into Infor CRM / SalesLogix
Posted By: anoshwadia on June 29th, 2015 in Saleslogix
No Gravatar

If you’ve worked with Infor CRM / SalesLogix for a while, you’ve probably run into the issue where you enter your username and password (correctly!) and all you get is an Unspecified error! Very descriptive, isn’t it?

Cause: Essentially what the error means is that the application is unable to connect successfully with the SQL server database. There are several reasons for this, hence many possible fixes.

 

1) Correct Native Client Installed – the most common issue (and this affects Windows Client users or any web user who has any of the Windows based tools installed) is that the correct SQL Native Client is not installed.

The SQL Native client is like a “driver”, you can install multiple versions on the same machine (for example SQL 2005 Native Client, SQL 2008 R2 Native Client and SQL 2012 Native Client) without any adverse effects.

However you do need to verify you have the CORRECT one installed. The correct one is the one being used on the Infor CRM / SalesLogix server in the Saleslogix Connection Manager. In the example below you’ll notice that the EVAL81 database is using SQLNCLI10.1

ConnectionManager

 

Here’s how the various versions of SQL Native client show up as in the Data Link Properties:

NativeClients

 

Version Number Product Version
9.x SQL 2005
10.x SQL 2008 (or 2008 R2)
11.x SQL 2012
12.x SQL 2014

 

 

 

So based on the above, this tells us that the database connection is being made using a SQL 2008 (R2) Native client and that’s the version that should be installed to ensure connectivity.

Note that the version of the SQL Native client doesn’t necessarily have to match the version of SQL Server being used, technically a SQL 2005 Native Client could be used to connect to a database on a SQL 2008 platform. However it is recommended that the same version as SQL server is used. Using the wrong version of the SQL Native client causes issues with SQL 2012 databases in particular.

 

2) Saleslogix Connection Manager – Often the Saleslogix connection manager has not been setup correctly. A quick way to test this is to try connecting from another client machine or from the server itself. Check to ensure that the connection to the database has been setup correctly and for SQL 2008 Native Client and higher, ensure that you click on the Advanced Settings and set the following:

  • Integrated Security  – Click the Reset Button
  • Persist Security Info – Set to True

 

3) SQL Server Network Access – If none of the clients can connect, you may have an issue with the SQL server itself. By default SQL Express instances do not have TCP/IP protocol enabled so they are accessible via the local machine only. Check the settings in the SQL Server Configuration Manager to ensure TCP/IP protocol is enabled for your SQL instance.

 

4) Firewall and Network Connectivity – Even though the client connects via the Saleslogix Application Server, it still needs direct access to the SQL server as well. See if you can ping the SQL server from the client machine. You can also try to Telnet to the SQL server at port 1433.

 

5) Corrupt Connection Settings – occasionally you run into a client machine that has corrupt SalesLogix Connection settings, even though they appear to be correct and pass the connection test. Its recommended that the client connection be deleted and re-created. You may also have to delete all subkeys under:

HKCU\Software\SalesLogix\ADOLogin

 

6) Reboot – When all else fails, maybe all that’s needed is a reboot! Sometimes SQL settings don’t take effect until a reboot is done.

 

Hope this brings some clarity to this very vague error message! If you need further assistance, call our support line at 1-877-777-9779 and we’ll be happy to help you!


Logging into the Infor CRM Mobile Client with an iPhone / iPad
Posted By: anoshwadia on June 29th, 2015 in Saleslogix, SLX Mobile
No Gravatar

We’re often asked, why can’t I login to the Infor CRM (SalesLogix) mobile client using my iPhone / iPad?

Here are some common things to check on your device:

1) Click on Settings   unnamed

 

2) Click on Safari –> Under Privacy and Security –> Block Cookies –> Always Allow

Capture

 

3) Go one step back…now scroll down and click on Advanced –> Make sure Javascript is set to ON.

Capture

 

4) Clear your Safari cache. This is done in 2 steps:

a) Click on “Clear History and Website Data”. Tap the Clear button when prompted.

Capture         clear-safari-history-and-website-data

b) Click on Advanced –> Website Data –> Remove All Website Data

open-website-data

Usually these steps should let you login to the mobile client if you try again.

 

Assuming the above does not resolve your issue, here are some additional things to try:

a) Try logging into the Mobile client using your regular desktop browser on your computer (Chrome / Firefox). If you cannot login there, it indicates either an issue with either the version of the Mobile client being incompatible with your version of iOS, or an issue with your login.

b) Verify your login works by logging into the Infor CRM web client using your credentials. Often a concurrent user is locked out of the system due to several invalid login attempts and is not made aware of this when they login to the mobile client.

 

If you need further assistance, call our CRM support line at 1-877-777-9779 and we’ll be happy to help you!


Conditional styling of InforCRM grid row with onStyleRow
Posted By: nicocrm on June 12th, 2015 in Saleslogix
No Gravatar

This is a very common request – the customer wants to see some rows highlighted in the data grid based on the data.  For example, they might want to see opportunities with a sales potential above $1M highlighted in green.  How might we achieve that in InforCRM?

There is no mechanism “out of the box” for it, but it is definitely possible to leverage the underlying capabilities of the dojo grid (see grid row styling) to achieve the look. The challenge becomes then converting the dojo documentation into something that we can use in Saleslogix.

First step: convert the code from declarative style to procedural style (we won’t be able to use the declarative style from InforCRM since the grid is instantiated via code):

grid.on('StyleRow', function (gridRow) {
    var item = grid.getItem(gridRow.index);
    var pot = grid.store.getValue(item, "SalesPotential");
    if (pot > 1000000) {
        gridRow.customStyles += "color: red;";
    }
});

Second step: how do we get that code to run inside of InforCRM?? Unfortunately the grid is created inside of an anonymous function that runs via a setTimeout call, so it’s pretty hard to
hook into it directly. But we know the grid’s id (it’s hardcoded in the javascript file) so we can just register a script to run at a short interval until the grid is available, then add our style code to it.
For good measure we’ll add a call to resize() – this forces the grid to repaint its rows, applying our styles, in the unlikely event that it already got the rows built by the time our function runs.

ScriptManager.RegisterStartupScript(this, GetType(), "StyleGridRows", @"
require(['dijit/registry'], function(registry) {
    var i = setInterval(function() {
        var grid = registry.byId('AccountOpportunitiesgrdOpportunities');
        if(grid) {
            clearInterval(i);
            grid.on('StyleRow', function (gridRow) {
                var item = grid.getItem(gridRow.index);
                var pot = grid.store.getValue(item, 'SalesPotential');
                if (pot > 1000000) {
                    gridRow.customStyles += 'color: red;';
                }
            });
            grid.resize();
        }
    }, 250);    
});
", true);

I hard coded the id, but that’s OK, because it’s hard coded in the AccountOpportunities.js script also. Search for “id:” in that file, or use the Chrome developer tool, to find out what the id is.
Be sure to get the grid’s id and not the “gridNodeId” (which will end in _Grid) – that one is the container and does not have the style functions.

Here is the end result… obviously you can get “customStyles” as fancy as you want, you can also use “customClasses” to use a custom CSS class:

Although the example is simplistic this is a powerful visualization aid and I think once it is prettied up a little bit the users will like it. Leave a comment if you have an interesting use of the onStyleRow event!