Validation rules don't always mean "Stop!"

2 minute read time.
I was asked recently about how to create a log of when data was changed within a particular screen. Now the requirement was focussed on the screen and not on the the record. If we had been interested in whenever data in the record changed then of course we could use an Update event function within a TableLevel script. But here the requirement is just when a certain screen is used.

When I suggested using a Validation script to provide the screen based logging my correspondent was surprised. It seems that they had not realised that Validation scripts do not necessarily result in an interrupted commit.

It is true that if the script contains

Valid= false;
ErrorStr = "An error has occurred"

then the error message will be written to the screen and the commit process stopped and the whole screen returned in edit mode.



An example Validation script that can ensure that Cases are not created for companies that lack a SLA could be expressed as:

if (!CRM.GetContextInfo("company","comp_slaid"))
{
Valid = false;
ErrorStr = CRM.GetTrans("customErrors","NoCompanySLAID");
}

It seems that it is not an uncommon assumption that Validation scripts can only be used to stop inserts. But in fact Validation scripts can quite happily fire and be designed never to 'fail' or return a Valid = false.

So we can use the Validation scripts to carry out automatic logging and other "behind the scenes" tasks. The example below has been written to log the changes that are taking place to the different fields of the company screen. When a field in the main company screen (CompanyBoxLong) is edited the Validation script detects the change in the field value and writes an audit into the log file.

The change of data in a field can be detected by comparing old value of the field with the new value.
e.g.

if(CRM.GetContextInfo("company","comp_name")!=Values("comp_name"))
{
//Change has occured
}

The example below only needs to log which fields have changed not every field in the screen so we first need to know what fields are in the screen and then examine each field in turn. To do this I've used the fact that the screen object (EntryGroup block) is an enumerable object.

Example Validation Log Script


var ForReading = 1, ForWriting = 2, ForAppending = 8;
var TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0;
var mySystemObject = new ActiveXObject("Scripting.FileSystemObject");
var myFile = mySystemObject.GetFile("c:/customlogs/TEST.TXT");

var myFileTextStream = myFile.OpenAsTextStream(ForAppending, TristateUseDefault);
var oldName = "";
var myBlock = CRM.GetBlock("CompanyBoxLong");
var myE = new Enumerator(myBlock);
while (!myE.atEnd())
{
oldName = CRM.GetContextInfo("company",myE.item());
if (oldName != Values(myE.item()))
{
myFileTextStream.WriteLine(oldName +"/"+Values(myE.item())+" changed by "+CurrentUser.user_logon);
}
myE.moveNext();
}

myFileTextStream.Close();