FAQ - Business Rules

Business Rules have several quirky behaviors that will be addressed in a future release. Please read and understand these points before writing your first business rule. 

Why do I need a local variable for certain cases?

There are rules scenarios where you can't use a frevvo control directly in a rule expression and you are forced to define a local variable, perform the computation using the local variable and assign the value to the control at the conclusion of the computation.

For instance, assume a form that calculates a total from a list of subtotals. The total is a control T and subtotals are represented as a repeat of controls S. In other words, T holds the total of adding all values in S. You could write the rules as:

T.value = 0; 
for (var i = 0; i < S.value.length; i++) {   
    T.value = T.value + S[i].value; 
} 

The code above makes logical sense but it just won't work. In a nutshell, this particularity of the frevvo implementation can be explained this way:

The right-hand side of an assignment expression resolves to the value of a frevvo control passed to a rule when it is invoked. The left-hand side uses a reference to the control'.

Let's work with a concrete example to understand the concept. Assume that there are two subtotals in the form, 12 and 14 and the total is correctly set to 26. Now, you add 50 as a third subtotal, and the rule fires as a consequence. The values of the controls involved in the rule are passed as parameters to the rule: the subtotals 12,14 and 50 and the current total (value of T), 26. The core of the matter is in the expression:

T.value = T.value + S[i].value; 

The expression will be evaluated three times (since there are three subtotals) but for every iteration, the T.value operand on the right-hand side will always evaluate to 26 which is not the desired behavior and will lead to an incorrect result. Again, this happens because the right-hand side of that expression is resolved based on the values initially passed to the rule as parameters.

frevvo explicitly imposes this restriction for the sake of efficiency and there would be a significant impact on performance if the limitation was not in place. Let's rewrite the rule using a local variable:

var tot = 0; 
for (var i = 0; i < S.value.length; i++) {   
    tot = tot + S[i].value; 
} 
T.value = tot; 

This rule will produce the expected result. 

Note that the Visual Rule Builder will handle local variables for you. Let's look at another example. If you used the following rule code, you would see that at run-time number control displays NaN (not a number) because, as you saw above, the control update will happen after the rule executes, so the new value is not yet available inside the same rule.

if(trigger.clicked){
  string.value = "33";
  number.value =  parseInt(string.value);
}	

Try the same concept using the Visual Rule Builder.

Click Rule Code to see the code generated by the Visual Rule Builder. Notice that the VRB adds the local variable "ref_string_value", and uses that to set the control values similar to the rule code example above.


Variables in rules must be unique. Having duplicate variables in the same rule will cause the rule to fail but you may not get an error message.

My rule does not set control values as expected, but there are no errors. What happened?

This can happen because the logic purposely ignores setting value properties that happen in a workflow during form state initialization. Here are some examples:

Example 1

Let's say you have a two-step workflow that contains the following rules:

Rule 1: When step 1 of the workflow is executed, the form loads, and the Sales Planner Status control displays "Not Ready for Review".

Sales Planner Status:
if (form.load) { 
   SalesPlannerStatus.value = "Not Ready for Review"; 
}

Rule 2: When CP Value is Yes, set Sales Planner Status to "Ready for Review." When CP Value is No, set Sales Planner Status to "Not Ready for Review".

CP Status:
if (CP.value == "Yes") { 
  SalesPlannerStatus.value = "Ready for Review";
} else if (CP.value == "No") { 
  SalesPlannerStatus.value = "Not Ready for Review";
}	

On Step 1, if the user clicks Yes in the CP field, the Sales Planner Status control correctly displays "Ready for Review".

When you click Continue to advance to the next step of the workflow, the value of the Sales Planner Status is re-set to "Not Ready for Review" even though the value of CP is still Yes.

This is as designed. The logic purposely ignores setting value properties that happen in a workflow during form state initialization. This is what happens in the second step of this workflow using linked activities. Note that changes to attributes other than value are not ignored during initialization. The designer will see a message in the log and the debug console output that says the set of the property value is ignored.

Adding if (_data.getParameter('flow.activity.name') == "Step 1") to the Sales Planner Status rule, gives the expected results:

Example 2

You have a form that may be preloaded with data. For example, the Invoice Number is loaded from the URL and a rule sets another control's value if the preloaded control has a value. For example,

var x;
    if (InvoiceNumber.value.length> 0) {
        eval ('x=' + http.get('<query url>' + InvoiceNumber.value));
        if (x.resultSet[0]) {
           if(x.resultSet[0].invoice_description) {
              InvoiceDescription.value = x.resultSet[0].invoice_description;
           } else {
             InvoiceDescription.value = '';
           }
        }

The workflow may load with the value of Invoice Number visible, but the dependent controls do not pick up a correct value unless you click and re-select the Invoice Number. Here also, the logic purposely ignores setting value properties that happen in a workflow during form state initialization. The debug console will show "Set of InvoiceDescription.value ignored." Simply adding

var event = form.load;			

to your rule will correct the issue.

What causes an "Invalid signature detected. Data may have been tampered with" error?

This error message usually displays in multi-step workflows when there is a rule on a subsequent step that executes at form load and updates values inside a signed section in a previous step. Here are some examples and solutions:

Checkbox with Custom Options in a locked Signed Section

Imagine a two-step workflow designed with Linked Steps where Step 1 contains a Checkbox control inside a section that the user is required to sign. The checkbox has only one option defined in the Workflow Designer. A Business rule is executed when Step 1 loads to dynamically populate the checkbox with additional options.

The image shows this scenario in use mode after the rule has executed. Notice there are three options for the checkbox now. The user selects all three options, signs and then clicks continue.

The workflow is routed to Tasks Lists of users who fulfill the requirements for the next step. When Step 2 loads, the rule is executed again. This combination results in data tampered error.

Solution:

This situation can be avoided by always setting more than one option in the Workflow Designer for any checkbox that will be dynamically populated with a rule.

Changing the Value of Controls in a Signed Section

Business rules that change the values of controls inside a signed section may result in the "Invalid signature detected. Data may have been tampered with." error. Rules that "tamper with the data" and invalidate a signature once a section has been signed are no longer allowed. Refer to this topic for the details.

Why does the information for the logged in user change when I navigate forward/backwards in my workflow?

Designers can use a Business Rule  to initialize fields in the first step of a workflow with information about the logged-in user. If your workflow navigates to a different user/role for subsequent steps, and the user navigates back to step 1, the rule executes again when Step 1 loads, overwriting the information in step 1 with the information of the user performing the subsequent step. This is an important consideration whether your workflow is designed using individual or Linked Steps or when using the View My Task icon to see a read-only version of the workflow. 

You can improve your rule to account for this. For example, let's say you have a two-step workflow. Step 1 executes this rule to fill in the firstName, lastName, managerId, email, and date fields with the logged-in user's info and current date. Note this rule executes when Step 1 loads.

var event = form.load;
if (frevvo.step.on('_8fzQkAH7Ee2qIulkhGaygQ')) {
  firstName.value = _data.getParameter('subject.first.name');
  lastName.value = _data.getParameter('subject.last.name');
  managerId.value = _data.getParameter('subject.reports.to');
  email.value = _data.getParameter('subject.email');
  date.value = frevvo.currentDate();
  employeeInfo.enabled = true;
} else {
  employeeInfo.enabled = false;
}

When user Michael Stewart executes the first step of the workflow, here is what you see:

Michael clicks continue and the workflow progresses to Step 2 which is designed to be performed by a user with the Manager role, Jerry. Jerry logs in, and access the task from his Task List. Jerry sees Michael Stewarts' information from Step 1.

However, if Jerry navigates back to Step 1, the rule executes again when Step 1 loads and overwrites Michael's information with Jerry's.

To prevent initialized fields from being overwritten if users navigate to a previous step in a workflow, you must add a condition to your rule to only initialize the fields if they have not already been initialized when the step loads. Adding the second line to the rule used in this example ensures that initialized fields will not be overwritten. See this business rule example.

var event = form.load;
if ((frevvo.step.on('_8fzQkAH7Ee2qIulkhGaygQ')) && (!(firstName.value))) {
  firstName.value = _data.getParameter('subject.first.name');
  lastName.value = _data.getParameter('subject.last.name');
  managerId.value = _data.getParameter('subject.reports.to');
  email.value = _data.getParameter('subject.email');
  date.value = frevvo.currentDate();
  employeeInfo.enabled = true;
} else {
  employeeInfo.enabled = false;
}

The image shows what Jerry sees when he navigates back to Step 1 with the modified rule in place:

You can adapt the conditional statement in this example to fit your rule.

Another option if it is important to perform data initialization actions based on a step, is to use the "defaults to" operation in the Visual Rule Builder action wizard. This will check if the control has been initialized already and only set a value if it's empty.


Rule code for the "defaults to" option
var event = form.load;
if (frevvo.step.on('_8fzQkAH7Ee2qIulkhGaygQ')) {
  if (!(firstName.value)) {
    firstName.value = _data.getParameter('subject.first.name');
  }
  if (!(lastName.value)) {
    lastName.value = _data.getParameter('subject.last.name');
  }
  if (!(managerId.value)) {
    managerId.value = _data.getParameter('subject.reports.to');
  }
  if (!(email.value)) {
    email.value = _data.getParameter('subject.email');
  }
  if (!(date.value)) {
    date.value = frevvo.currentDate();
  }
  employeeInfo.enabled = true;
} else {
  employeeInfo.enabled = false;
}


Why can't I set a T/F Control to "Required" or "Optional"?

T/F (True/False) controls are automatically required by nature, because they must be either checked (true) or blank (false.) When setting conditions for a T/F Control, you will not see "as Required" or "as Optional." If you need this function, consider using a checkbox control with a single option instead.