2.3.1. Formula Fields

Say your business practice is to take 10% of the budget as an advance. You could use a currency field which managers will fill when creating or modifying projects. The problem is that managers must manually calculate the advance from the budget and remember to change it every time the budget changes. This is error prone. To make things a bit more complicated, assume that the policy is to take an advance of 10% for projects with budget upto $1000 and 15% above that. This increases the chances of errors. This is where formula fields come to the rescue. You would create advance amount as a formula field with the formula ${project.budget <= $1000 ? project.budget * .10 : project.budget * .15}. For a project with a budget of $500, the advance amount will show $50 (10% of $500) while that for a budget of $5000 will show $750 (15% of $5000). This brings many benefits. The value of this field is auto-calculated from the formula and is not entered by the user avoiding errors. The amount will be automatically updated when the budget changes. Most importantly, if the policy changes all you need to do is update the formula. The advance amount for all projects will automatically reflect the new value.

Formula fields, like other custom fields, are available as individual columns in reports. You can also filter, sort and group reports using them.

Variables

Depending on whether the formula field is attached to Project, Task or Process, different variables are accessible in the formula. For example, for a project field, the variable "project" is available. The table below shows the fields and their scope.

Table 2.1. Variables for project custom fields
Variable Description Type
id Unique ID of the project Integer
name Name of the project String
start Start date of the project Date
deadline Deadline of the project Date
finish The max finish date of this projects tasks Date
projectedFinish Projected finish date of the project based on % complete of its tasks Date
percentComplete Percent complete of the project Integer
budget Budget Double
fixedPrice Fixed Price Double
estimatedHours Estimated Hours of this project Double
actualHours Actual Hours. This is the sum of all time approved for this project. Double
actualCost Actual Cost for this project so far. Double
projectedCost Projected Cost for this project based on the % complete so far Double
spi Schedule Performance Index Double
cpi Cost Performance Index Double
acwp Actual Cost of Work Performed Double
bcwp Budgeted Cost of Work Performed Double
bcws Budgeted Cost of Work Scheduled Double

Table 2.2. Variables for task custom fields
Variable Description Type
id Unique ID of the task Integer
name Name of the task String
start Start date of the task Date
finish Finish date of the task Date
actualStart The actual start date of this task Date
actualFinish The actual finish date of this task Date
milestone Is this task a milestone Boolean
assigned Is any resource assigned to this task Boolean
projectedFinish tasked finish date of the task based on % complete of its tasks Date
percentComplete Percent complete of the task Integer
budget Budget Double
estimatedHours Estimated Hours of this task Double
actualHours Actual Hours. This is the sum of all time approved for this task.s Double
actualCost Actual Cost for this task so far. Double
projectedCost Projected Cost for this task based on the % complete so far Double
spi Schedule Performance Index Double
cpi Cost Performance Index Double
acwp Actual Cost of Work Performed Double
bcwp Budgeted Cost of Work Performed Double
bcws Budgeted Cost of Work Scheduled Double
project The project for this task. You must refer to a sub-property of the project. For example, task.project.name will be the name of the project and task.project.start will be start date of the project. Same as the type of the project variable
Using custom fields created by you

You can use custom fields created by you in formulas as well. The syntax to refer to them is slightly different. For example, project custom fields would be referred to as ${project.custom['45634']}. The numeric number is the unique identifier for the custom field. The reason we refer to them with the unique id instead of their name is that if the names change, you do not need to change formulas that refer to them. For convenience, the custom fields with their names and unique ids are shown when creating formula fields.

Syntax

Forumla fields can either be expressions as in ${project.budget * 0.10}, or contain a mix of expression and textas in <a href="http://mywikiserver/project/${project.id}>Wiki Link</a>. As you will notice, anything enclosed in ${..} is treated as an expression and evaluated. Everything outside it is copied to the output verbatim. Conditional logic can also be performed as we will see later.

Operators

In addition to the . and [] operators discussed in Variables, the expression language provides the following operators:

  • Arithmetic: +, - (binary), *, / and div, % and mod, - (unary)

  • Logical: and, &&, or, ||, not, !

  • Relational: ==, eq, !=, ne, <, lt, >, gt, <=, ge, >=, le. Comparisons can be made against other values, or against boolean, string, integer, or floating point literals.

  • Empty: The empty operator is a prefix operation that can be used to determine whether a value is null or empty.

  • Conditional: A ? B : C. Evaluate B or C, depending on the result of the evaluation of A.

The precedence of operators highest to lowest, left to right is as follows:

  • [] .

  • () - Used to change the precedence of operators.

  • - (unary) not ! empty

  • * / div % mod

  • + - (binary)

  • < > <= >= lt gt le ge

  • == != eq ne

  • && and

  • || or

  • ? :

Table 2.3. Examples
Formula Output
${5 + 3} 8
${5 - 3} 2
${5 / 3} 1.67
${5 * 3} 15
${5 % 3} 2
${5 > 3} or ${5 gt 3} Yes
${5 >= 5} or ${5 >= 5} Yes
${5 < 3} or ${5 lt 3} No
${5 <= 5} or or ${5 le 3} Yes
[Note]Note

The > and < operators can also be used in conditional expressions as explained below. In that case the conditions are evaluated.

Literals

The JSP expression language defines the following literals:

  • Boolean: true and false. For example, ${task.critical == true}.

  • String: with single and double quotes; " is escaped as \", ' is escaped as \', and \ is escaped as \\.

  • Null: null

Functions

A few predefined functions are also available. The purpose of these will be obvious as stated below.

Table 2.4. Functions
Variable Usage Description
formatDate ${formatDate(project.start)} Prints a date as per the format specified in the user's profile. Note that "user" here refers to the one viewing the data. This is useful when you have users in different time zones and using different styles for viewing dates.
formatDateTime ${formatDateTime(project.start)} Prints date and time as per user's profile
formatCurrency ${formatCurrency(project.budget)} Prints a currency field prefixed with the currency symbol as specified in the company profile.

Conditional Logic

You can perform conditional logic in the formulas. This is done using the syntax ${Some boolean condition ? If true, do this : Else, do this}. Boolean condition means any condition that evaluates to true or false. The question mark (?) indicates the end of the condition. If the condition is true, expressions to left of the (:) are evaluated. If the condition is false, the condition to the right of the colon are evaluated. You could nest the conditions. This means that the If true and If false blocks could themselves be conditions.

The formula ${project.actualCost > (project.estCost * .9) ? Cost Alert! : Cost OK} would check if the actual cost of a project exceeds 90% of its estimated cost and would print Cost Alert! if it is and Cost OK if it is not.

Error handling

If the formula has a syntax error it is reported while adding/editing the formula fields. However, other errors cannot be determined until runtime and hence you will see ERR! while viewing the fields in reports and other places. You can move your mouse over the icon to see the exact error message. Then edit and fix your formula.

More Examples

Assume that we have a project with the following data.

Table 2.5. Sample Project Data
Field Data
id 1234
name Sample Project: Setting up office space
start June 10, 2009
finish Dec 10, 2009
manager Mark Duncan
budget 5000
estimatedCost 4000
actualCost 3800

Based on this data, the table below shows sample formulas, the output of that formula and also provides an explanation.

Table 2.6. Examples
Formula Output (In Browser) Explanation
${project.id * 10} 12340 Id is multiplied by 10.
project.id * 10 project.id * 10 Not enclosed in ${} and hence copied to the output verbatim.
${10* 10} 100 Formulas need not use variables.
<b>${project.name}</b> Test Project You can use html tags.
${project.name + 100} ERR! Cannot perform arithmetic on String type.
<a href="http://mywikiserver/${task.id}">Wiki Link</a> Wiki Link If you use a Wiki, you can create hyperlinks to pages in your Wiki. Notice that we have simply used the HTML Anchor tag to generate a hyperlink.
${project.abcd} ERR! Formula contains error. No variable project.abcd exists.
${formatDate:(project.start)} Jan 10, 2009 Formats the start date as per the user's date format style.
${project.actualCost > (project.estimatedCost * .9) ? 'Cost Alert!' : 'Cost Ok'} Cost Alert!
${formatCurrency(project.budget)} $ 5,000 Assuming your currency symbol is $