Formula expressions

You define formula expressions using JavaScript, and Intacct executes the formula on the server side. Almost all JavaScript functionality is available to you when writing formulas.

Do you want more help with your development work? Explore and get answers from other users by visiting the Sage Intacct Developers Club. Sign in to learn more, or create an account now.

About formula expressions

When creating a formula expression, you use merge fields to extract data from object records and related records. Place merge fields anywhere in a formula to use as a placeholder for data. When the formula executes, field values replace the merge fields.

Merge field syntax includes an object name, a period, and the field name inside exclamation marks and curly braces.

The following example contains the merge field {!contact.city!} in a formula. The formula returns a different value, depending on whether the record value for {!contact.city!} is equal to New York:

Copy
Example 1
var rate = 6.5
if ("{!contact.city!}" == "New York"
rate = 8.5
return rate;

When this formula executes for a city field with a value of San Francisco, the formula translates to the following code before Intacct executes it:

Copy

Example 2

var rate = 6.5
if ("San Francisco" == "New York"
rate = 8.5
return rate; 

San Francisco does not equal New York, so the result of the formula expression is 6.5.

For objects with the workflow attribute, formula expressions define workflow action conditions that return true or false. When all conditions are met, the returned true value tells Intacct to execute the action. Formula expressions can also change the value of a field when you use a Change field value action. In this case, the formula expression returns the new value to use in the target field.

Templates versus formulas

Formulas and templates both use merge fields to extract data from records. The difference is that templates only embed data into preformatted text, while formulas invoke a JavaScript engine to compute results.

Formulas treat merge fields the same way templates do. For example, to concatenate two merge fields in a formula expression, you can write:

Copy

Example 3

"{!contact.lastName!}, {!contact.firstName!}"

You do not need to use a JavaScript concatenation:

Copy

Example 4

"{!contact.lastName!}"+", "+"{!contact.firstName!}"

However, to avoid an unnecessary comma when the firstName field is empty, you can use conditional operators:

Copy

Example 5

("{!contact.firstName!}"==""
"{!contact.lastName!}"
"{!contact.lastName!}, 
{!contact.firstName!}")

Best practices

Keep your formulas as simple as possible to make your applications maintainable and to improve application performance. The following tips can help you simplify formulas:

  • Avoid using the return clause for one-line formulas without internal variables.
  • Avoid unnecessary concatenation using the + symbol.
  • Use conditional operators (X?A:B) instead of the if() function. The conditional operators (X?A:B) translate to if X is true, then return A; otherwise return B.

Process errors

When defining a formula expression, a Check for errors link displays below the formula text area. Use this link to check whether the formula is valid before saving your changes. The Check for errors option finds syntactical errors in your JavaScript.

Runtime errors can still occur even if your formula is valid. For example, division by zero cannot always be predicted. In the event of a runtime error, Intacct evaluates the formula to zero.

Debug formulas

After you define and validate your formula expression, you can easily debug it. To debug a formula, select the magnifying glass icon to select a record, then execute the formula against the record. When Intacct executes the formula, a debug page shows the original formula, the parsed version of the formula, and the final result.

Use JavaScript

Because formula expressions are defined using JavaScript, you have much flexibility. To take full advantage of this capability, familiarity with JavaScript is recommended though not necessary.

For example, you can include:

  • Logical operations such as if, else, and switch.
  • Standard JavaScript objects and their methods such as String, Date, Math, and so on.
  • Standard functions available in any JavaScript capable environment.
  • Merge fields from both base records and all related records.

JavaScript limitations

Given the broad capabilities of JavaScript, it's possible to perform complex calculations and create powerful formula expressions. However, to ensure proper performance for all customers on the Intacct platform, the length of formula expression cannot exceed 1,000 characters. Despite this limitation, formulas offer a powerful way to automate your custom applications.

You might find that the complexity of your work regularly challenges this limit. If so, you can consider a process that includes handing off portions of a script to formula fields in the same object. You can also call external code and write values back through the Intacct Web Services API.

Formula fields

Formula fields allow you to create dynamically generated fields associated with any of your objects. For example, formula fields can present the average, sum, minimum, or maximum of several other fields. Likewise, you can perform calculations or string concatenations based on multiple other fields. Intacct does not store formula field values in the database; rather, they are calculated each time the field is displayed in the user interface. This approach means that formula field values are always changing in response to changes in the underlying data. Let's say that you set a formula field to return the sum of all sales orders in a month. That field will continue to change in response to the growing number of sales orders throughout the month.

Formula return types

Formula fields support the following return types:

  • Decimal
  • Currency
  • Integer
  • String
  • Boolean
  • Date

If a formula field returns a value that does not match the specified return type, Intacct ignores the value.

Examples of simple formula expressions include:

Copy

Numeric

"{!contact.city!}".length
Copy

String

"{!contact.city!}".toUpperCase()
Copy
Boolean
"{!contact.city!}" == "Houston"
Copy

Date

(new Date("{!contact.createdAt!}")).getTime()+7*24*60*60*1000

Formula field types

Type of formula field Details
Merge fields

When defining formula expressions and templates, Intacct provides a series of picklists to help with the selection of appropriate merge fields:

  • Select field type lists the object, its related objects, and standard helper merge fields such as date, current user, and so on.
  • Select field lists fields to insert into your formula and also predefined functions to work with related records and placeholders for looping through a specific set of related records.
  • Copy merge field displays the selected merge field, function, or placeholder. You simply copy and paste it into your formula expression as needed.
  • Select field value lists picklist values where the selected field is a picklist field or related record ID for use in a formula expression.

The following example returns true if a user record has the administrator role, where 90 is the ID of the administrator role and {!department.role!} is the role of the user in scope:

Copy
{!department.role!}==90
Integration names

One common pattern in platform solutions is a property called Integration name for every object, field, and relationship. Intacct uses this integration name as a unique reference for the component. In particular, Intacct uses integration names in merge fields that can be used in formulas and templates.

For example if you create a field called Account name in the Account object, then Account name is the display name for this field, and by default, Intacct sets the integration name to account.account_name. When you want to use this field in a formula expression, you reference it using the merge field format as follows:

Copy
{!account.account_name!}
Dates

Date merge fields use a standard mm/dd/yyyy format. This format is great for portraying a readable version of the date in a document or email template. However, if you want to write formulas that compare date values, you need to be more creative.

For example, you might have a formula that compares the date field value with the current date. To make this work in JavaScript, you need to set each date to the JavaScript native date format. Use the JavaScript Date() function to assign the native format to variables. Then, you compare the variables. Because the JavaScript Date() function returns date in milliseconds, you might need to adjust or round values.

Copy
var currentDate = new Date();
currentDate = Math.floor(currentDate / 86400000); // round to day value (24*60*60*1000 = 86400000)
var thisDate = new Date("{!task.due_date!}");
thisDate = Math.floor(thisDate / 86400000);
if(thisDate == currentDate){
     return "Due Today";

When returning a date value from a formula, the expression must return the results of a date instance using the getTime() method. For example, maybe you have a workflow action called reset on a task object that changes a date field to the current date. In this case, you need to use the getTime() function to properly output the date.

Copy
var today = new Date();
return today.getTime();
Image and shared image

Each image or shared image field has two merge fields associated with it:

  • {!object.fieldname#html!} Use the image html merge field to include the full html code for an image in your formula. Intacct replaces the merge field with a full html IMG tag.
    When working with image html merge fields in formulas, wrap them in quotes to avoid errors. For example: return "{!task.greenImage#html!}"; is the correct way to return an image to be displayed as a formula result.
  • {!object.fieldname#url!} Use the image URL merge field to only include the URL for an image in your formula. Intacct replaces this merge field with a full path to the image. This option is useful when building custom IMG tags that include more information, such as a unique identifier, JavaScript event handlers, and so on.
Nested

You can use formula fields within other formula expressions, creating nested formulas. However, the order of execution cannot be guaranteed, and the maximum level of recursion cannot exceed ten.

Group functions in formulas

You can define relationships between any number of objects and perform simple and complex calculations among related objects in formula expressions. You can also use these group functions in templates, such as email and document templates, and in template fields. The following group functions are available:

Copy
Example 6
#FUNC_SUM
#FUNC_COUNT
#FUNC_MAX
#FUNC_MIN
#FUNC_SUM, #FUNC_MAX, #FUNC_MIN require a numerical parameter, while #FUNC_COUNT does not take any parameters. Each of these functions iterates through a relationship between the current record and all of its related records.
Group function Details
#FUNC_SUM

Consider an object called Property that's related to an object called Product component. The relationship has the integration name RB188912. Product component has a price field with integration name line_amount. To calculate the sum of all product component prices associated with a product record, you write:

Copy
#FUNC_SUM.RB188912( {!RB188912.line_amount!} )

As an alternative to using the integration name of a relationship, you can use the lookup field name on the current object preceded by a caret (^). For example, assume the lookup field name on Property is product_component. The first example can be written as:

Copy
#FUNC_SUM.^product_component( {!^product_component.line_amount!} )

You can calculate the number of related product component records for this product using the group function:

Copy
#FUNC_SUM.RB188912(1)

To combine multiple SUM calls to calculate the average amount, you write:

Copy
#FUNC_SUM.RB188912( {!RB188912.line_amount!} ) / #FUNC_SUM.RB188912(1)
#FUNC_COUNT

To count the number of related product component records for a product, you write:

Copy
#FUNC_COUNT.RB188912()
#FUNC_MAX

To calculate the maximum value of the price field across all related product component records, you write:

Copy
#FUNC_MAX.RB188912( {!RB188912.price!} )

Loop through related records

Formulas can be helpful in aggregating data from related records. For example, in a CRM, you might want a Lead object to calculate the revenue value of all the related Opportunities and display this in a Total Value formula field. You can use special loop merge fields to accomplish this. These fields instructIntacct to look at all the related records to the record in scope. Assuming that the integration name of the relationship is R11002, the formula for Total value can look something like this:

Copy
Example 7
var total = 0;
{!#LOOP_BEGIN.R11002!}
total += {!R11002.revenue_value!};
     {!#LOOP_END.R11002!}
return total;

Alternatively, you can use the Lead object's lookup field preceded by a caret (^) instead of the integration name of the relationship:

Copy

Example 8

var total = 0;
{!#LOOP_BEGIN.^opportunities!}
     total += {!^opportunities.revenue_value!};
     {!#LOOP_END.^opportunities!}
return total; 

Loop through unrelated records

You might find occasions where you need to loop through records in an object that's not related to the object in scope. You do this by looping through a list view for the unrelated object. By looping through a list view, you can set filters on the view to control what records your formula will loop through. To do this, you need to first obtain the list view's Original ID or the unrelated object's Integration name for the list view of the unrelated object.

To find a view's Original ID or Integration Name:

  1. Go to the Object Definition page for the object that contains the desired view.
    • Find the Integration name in the Object properties section.
    • Find the Original ID in the System Information section.
  2. Copy the Integration name or Original ID for the view you want to access.
  3. In your formula, point the LOOP function at the Integration name or Original ID.

The following formula loops through all the records in the view with Original ID 116802@10083 and appends the record names in a single string:

Copy

Example 9

var buff = '';
{!#LOOP_BEGIN.all#116802@10083!}
     buff += '{!name#text!}';
{!#LOOP_END.all!}
return buff;  
When the system parses this formula, it creates JavaScript code for each loop or record that the view shows. Processing long lists of records can cause your JavaScript to time out. You can avoid this by tightly filtering the view to reduce the number of records or by setting a loop limit in your script. You set a loop limit in parentheses following the ID pointer. The following formula will loop through the first 20 records in a given view.
Copy

Example 10

var buff = '';
{!#LOOP_BEGIN.all#116802@10083(20)!}
     buff += '{!name#text!}';
{!#LOOP_END.all!}
return buff;

Here's an example of using the object integration name instead of an original ID for specifying a view. The view used by this syntax is the first view of the object, meaning the view with the lowest Order No in the object view page.

Copy

Example 11

var total = 0;
{!#LOOP_BEGIN.all#class!}
    total += {!class.recordno!};
{!#LOOP_END.all!}
return total;

Access record from a loop

You can access a record from a loop using LOOP_REC. In the following example, the loop prevents the creation of a duplicate vendor.

Copy

Example 12

var recordNo = "{!vendor.recordno!}";
{!#LOOP_BEGIN.all#vendor@name@=@vendor.name!}
  if ("{!#LOOP_REC.recordno!}" != recordNo) {
        return "This name is already used by the vendor with the id - {!vendorid#text!}";
  }
{!#LOOP_END.all!}

 

Add conditions to a loop

You can add condition parameters in your JavaScript code, which add restrictions to records you loop through and allows your script to loop more efficiently.

Syntax Description Example
@ (delimiter)

Add condition parameters using @ for the delimiter, so that when you loop through a view, Intacct executes an action only if a condition is met.

The view can be specified with three extra parameters (or 2 for the ISNULL/ !ISNULL operators) separated by @ in the following order to add a condition:

  • Field name

  • Operator

  • Value

Copy
Condition parameters syntax
var total = 0;
{!#LOOP_BEGIN.all#CLASS@name@=@12345!}
    total += {!class.recordno!};
{!#LOOP_END.all!}
return total;
"" (quotation marks)

Surround a value with "" (quotation marks) to avoid syntax translation from the interpreter.

In the example, the email address is surrounded by quotation marks to prevent the interpreter from translating the email address as a parameter.

Copy

"Do not interpret" syntax

var total = 0;
{!#LOOP_BEGIN.all#CONTACT@email@=@"john.smith@example.com"!}
    total += {!udd2.recordno!};
{!#LOOP_END.all!}
return total;
<object>.<field>

Special merge fields: Use special merge fields to make the loop not dependent on the hard-coded values. Exclude the curly braces and exclamation points to extract object values outside the current record.

Copy

Special merge field syntax

contact.city