Beginner's guide to triggers and CRMScript

By Simen Mostuen Iversen, Updated on 6 Jun 2019
push_pin
star

Introduction

Triggers are a powerful way to enhance your SuperOffice solution; it may help you automate processes in smart ways, reduce the number of errors, and improve the data quality.

As is with powerful tools, it also requires some carefulness. Some small miscalculations or logical flaws may create problems with your data and possibly the entire solution. I advise you to always test out your triggers and scripts in a closed environment before putting it in production, and if you have no closed environment – test the code (or parts of the code) separately with some specific data to verify that what you’re trying to do works in the way you intended.

If you are new to CRMScript, I recommend going through my "Beginner's guide to ejScript" as well as it might give you a small push in the right direction.

 

What is a trigger?

A trigger in SuperOffice is something that happens after a specific event (e.g: person is created, sale is updated, ticket has changed status and so forth). You can create a script or a macro that runs every time this specific event happens.

There are also different kinds of triggers, some is activated by a user while other’s by system events.

 

Where can I create triggers?

You’ll need to have enough user rights before you can start. Only administrators can create and update scripts and macros.

There are two ways to find your way to the fun that is CRMScript:

  • In Sales, click the burger menu in the top right corner and click “Settings and maintenance”. Then in the left menu you can find CRMScript.
  • In Service, click the cogwheel in the top right corner, click “System design” and then CRMScript.

Nb! Creating scripts (not macros) will require the Expander Services license. This is an additional cost per site.

 

What kind of triggers can I create?

You can create a script or a macro. A script will allow you to do more while a macro is easier (and in some cases faster) to set up. Depending on your needs, you can use the “Before save” to stop a user from saving (often used for validating fields), or “After save” if what the user inputs should affect other parts of the system.

 

Creating a trigger :: Script

Regardless of which type of trigger you want to create, there’s one piece of code that you’ll need to know:

EventData ed = getEventData();

This code will allow you to fetch variables being used in the current context.

Let’s create a trigger that will stop the user from saving a company unless the organisation number is filled out.

 

Step 1

  • Click the “New trigger (script)” in the trigger pane and in the search box type “Before saving company” and click the trigger.

Step 2

  • The “Description” field should contain a short description of what your trigger is doing, in this case I’ll write “Validate OrgNr”.
  • If you want this trigger to be enabled, remember to click the toggle box on the right side.

Step 3

  • In the textbox below, we can write whatever we want, although if you insert code that is not supported by CRMScript, it will give you an error message when clicking the “Ok” button.

Step 4

  • The full code for preventing a save unless the organisation number is filled out, could look something like this:
// Get the variables in the current context
EventData ed = getEventData();

// Get's the input value from the current company
String orgNr = ed.getInputValue("ContactEntity.OrgNr");

// If the orgNr field is empty, block save with a message
if(orgNr.isEmpty())
{
  ed.setMessage("Please type in a Org.Nr");
  ed.setBlockExecution(true);
}

You will now receive an error message unless you enter something in the Org.nr field.

 

What if I don’t know the name of the input value I want to fetch?

My preferred way of finding out which fields I’ve got access to is by using the Trace function.

Step 1

  • Save your script by clicking “Ok” (Verify that you don’t get any error messages)

Step 2

  • In the button row above the script, click on the “Trace script” button.

Step 3

  • Verify that the “Description” field is not empty and the “Enabled” checkbox is checked, use the User filter if you want a user specific trace, and click “Ok”.

Now you’ve activated tracing on the script that you’ve just created, and this enables you to go through the script step-by-step to see which variables you’ve got access to. For easy access, keep this tab open for now.

 

In Sales (in a new tab), go to a company card, click “Edit” and then click “Save” so that the trigger will run the script.

Go back to the tab where you have the trace, and click “Refresh”. You should be able to find a new row in the trace of the trigger you’ve just created, click the row.

In the left side you’ve got the script, with a blue line displaying which row you’re tracing. The right side displays all available variables, with a … which you can click to expand.

If you have the “EventData ed = getEventData();” code you should be able to see a “ed …” in the right side, and if you click this you should be able to see “inputValues …” – expand this as well.

Now you can see all the various input values available for you in the current context.

In this scenario, we wanted to know the input value for the organisation number, which in SuperOffice is called OrgNr: ContactEntity.OrgNr

Click “Return” in the button row, and then click “Trigger” to go back to the script that you’ve started and click “Edit”.

 

Creating a trigger :: Macro

We'll create the exact same trigger, just by using macro instead.

Step 1

  • Click the “New trigger (macro)” in the trigger pane and in the search box type “Before saving company” and click the trigger.

Step 2

  • The “Description” field should contain a short description of what your trigger is doing, in this case I’ll write “Validate OrgNr”.
  • If you want this trigger to be enabled, remember to click the toggle box on the right side.

Step 3

  • Click "Trigger response"

Step 4

  • In the "If" section, select "All conditions are true"
  • In the list box below, select "Real-time values from the trigger" and search for "Org. number"
  • In the field to the right, select "Is empty"

Step 5

  • In the "Then" section, the "Trigger response" part, check "Block save" and check "Show message dialog" and insert a text to the right (e.g: Please type in a Org.Nr)

 

What if I want to specify what to validate?

In this example, I will only write a script as macro is falling a bit short when you need more specific validation.

Let's use the organisation number validation example and build upon that.

We want it to only contain numbers, and it has to be 9 digits. The code we will write will be something like this:

// Get the variables in the current context
EventData ed = getEventData();

// Get's the input value from the current company
String orgNr = ed.getInputValue("ContactEntity.OrgNr");
Bool blockExecution = false;

// If the orgNr field is empty, block save with a message
if(orgNr.isEmpty())
{
  ed.setMessage("Please type in a Org.Nr");
  blockExecution = true;
}// If the orgNr field has letters or is not 9 digits
else if(!orgNr.isDigit() || orgNr.getLength() != 9)
{
  ed.setMessage("Please type in a valid Org.Nr (9 digits)");
  blockExecution = true;
}
ed.setBlockExecution(blockExecution);

Now we will first check if it is empty, then check if it consists of 9 digits, the script can give two different messages based on which case it hits.

 

Update values

If you want to update some values in the "Before save" function, you can use the "setOutputValue" function:

ed.setOutputValue("ContactEntity.OrgNr", newOrgNr);

Where "newOrgNr" is a String value. No extra code is required to update a field.

An example here is to summarize all sales connected to a project, then update a userdefined field on the current project.

EventData ed = getEventData();

// Fetch the current Project ID
String projectId = ed.getInputValue("ProjectEntity.ProjectId");

/* 
  Use the SearchEngine class to summarize all the sales connected to the current project
  
  If you expect a larger amount of rows in return, please add a limit so that you won't stress the application/database too much. Doing several queries where you return 50 000 rows would lower the performance of your solution.

  An example is to set a limit to 1000 rows: 
  se.setLimit(1000);

*/
SearchEngine se;
se.bypassNetServer(true);
se.addField("sale.amount", "sum");
se.addCriteria("sale.project_id", "Equals", projectId);
if(se.select() > 0)
{
  // In this case, the "Total Sum" field has Prog ID: SuperOffice:1
  ed.setOutputValue("ProjectEntity.UserDefinedFields.SuperOffice:1", "[F:" + se.getField(0) + "]");
}

In this scenario, the script will update the current project with the amount of all sales connected to it. It will not disregard lost sales, so maybe adding a few criterias is a wise choice.

You might also want to create a trigger on "After saving Sale" to update the project.

Nb! Also, it might be a smart to trace the values to see what SuperOffice expects in return, here I have created a userdefined field of the type Decimal, which then expects [F:value] while fields of the type Integers expects [I:value]. You might save yourself some frustrating debugging hours by learning the correct formats.

Conclusion

Macros is a simpler way of creating automations and validations, although it has some restrictions that can only be done by scripting. And unless you are cautious, scripting could potentially damage the data in your system - so I advice you to test a lot before enabling the trigger for everyone.

With some minor tweaks you can get better data quality by forcing the user input values that helps out your day-to-day activities, and you will be able to automate some of the processes and calculations which could save you huge amounts of time.

We often advice the customers to use as much standard functionality as possible, but there are certain things that you'd want to customize - and luckily, we have triggers for that.

Elsa, please create a forumpost when you have questions, it's a lot easier to have a discussion there.
Frode Lillerud 23 Jan 2020
How to apply the same when is a user defined field? Someone could help?
Elsa Jimenez Baile 23 Jan 2020
Great stuff :)
Hans Wilhelmsen 10 Jun 2019
Wow! Great article, Simen!