Scripts

Introduction to Scripts

Scripts are used in many places in PYXI. These include:

  • Action Scripts – these result in actions taking place e.g. updating a record, adding records, sending emails etc. They are the backbone of Rules and, optionally, Steps and App Steps
  • Form Scripts – these are used to set out a Form for user input, and can used in Steps and App Steps. A Form Script is typically paired with an Action Script that describes what to do with the information entered on the Form. Steps and App Steps usually have both a Form Script and an Action Script working in tandem
  • Template Scripts – these are used to set out information for display. They are the backbone of Pages, and are also used for purposes such as defining the exact information displayed by each record in a Column View, or for adding customised information to other views such as the Funnel View
  • View Scripts – these are used to define a View. Views (such as Column and Funnel views) require various parameters to be set, depending on the particular view. These are set as variables within a script. This gives you the flexibility to build logic into any of the settings of such Views

Scripts are usually evaluated in the context of a specific record. This means that all Calculations performed within the Script are evaluated in the context of that record, so Fields of that record are available as variables in the Calculation.

Script Syntax

The following section describes the standard syntax which applies to all scripts. Any script lines that are not described below will be processed in accordance with the specific script type e.g. for Template Scripts, all other lines become the template output; Action Scripts have additional commands for saving data to records, adding records, sending emails etc., and Form Scripts have a specific format to describe fields and sections within the form to be displayed.

Scripts are evaluated line-by-line. Blank lines are ignored, and white space (spaces or tabs) at the beginning of lines is also ignored. Some script commands described below may affect whether a line is processed (e.g. if it is within an IF…ELSE structure), or whether a line is processed repeatedly (e.g. within an EACH structure where the same script line may be processed for multiple records).

The PYXI script syntax is designed to be as easy to use and flexible as possible, but we do recommend a few points of best practice which, whilst not compulsory, will make your development, understanding and maintenance of your scripts easier:

  • Documentation – you can add as many commentary lines to your scripts as you like. As with any programming, it is a very good idea to write commentary about what your script is for, what it does, and how it does it. In particular, describe each variable used and especially note any unusual or non-obvious logic. Remember that commentary is not just for someone else, but also for you in six-months time – you will thank your earlier self for good documentation!
  • Indentation – it is a good idea to indent script lines for structures such as IF…ELSE…ENDIF. We recommend using four spaces per indentation. You will see this approach in all our examples and published Blueprints
  • Capitalisation and Naming Conventions Almost everything within PYXI scripts is case-insensitive – technically it doesn’t matter if you write ENDIF, endif or eNDif – but consistency is good. We recommend that all commands such as SET, IF, ENDIF etc. are capitalised; names of record Fields are in proper case (e.g. Name, Address), and variable names start with a lower-case ‘v’ for variable or ‘r’ for record followed by proper case e.g. vCount or rPerson. If you follow this convention, variables will be colour-coded automatically within the script editors, further assisting in making your scripts readable.

Comments

All lines whose first character is # are ignored, so can be used to provide useful commentary on the script as a whole or individual items within it (variables, sections of logic etc.).

Comment lines can (and should) be indented with the lines to which they relate.

Examples:

######################################### # This script updates a Person record # # Written by A N Other, 2/5/20 #########################################
# Variable holds the count of People records SET vPeopleCount = countOf('Person')

SET – Variables

Variables are an important concept in scripts. A variable is a temporary ‘bucket’ into which you can place any value. The variable has a name which, by convention, is a lower-case ‘v’ followed by a Proper case description of the variable. As a special case, and again, by convention only, any variable which contains a record as its value is named with an initial lower-case ‘r’.

Variables are temporary. They only exist while the script is being evaluated. They are not saved or stored in any way ready for the next time the script is run. If you want the value of a variable saved, you have to do it explicitly e.g. by saving it to a Field of the current record, using it as a value in adding a record, or saving it as an account-level configuration setting.

The values of all variables are made available at the end of a script evaluation. Depending on what the script is for, this can be important. For example, if an Action Script is called by an API call, then the value of all variables is passed back as part of the API response. More commonly, scripts used to define specific items within PYXI, such as Forms, Views or Charts, rely on setting values in pre-defined variable names (which, by the way, don’t need to conform to the previous naming convention). See the specific pages on each of these script types for further details and examples.

Variables are available within calculations in the same script. Simply refer to the variable name in the calculation in the same way that you would a Field name of a record. Note that if you name a variable the same as a Field of the record for which the script is being evaluated, the variable name takes precedence over the record value in the calculation. This is generally not considered good practice as it may make your script hard to understand. You are usually better off explicitly naming the variable distinct from the Field name, and showing the logic that decides which to use later in the script.

The standard syntax for setting a variable is

SET vVariableName = calculation

Note that everything to the right of the equals sign is treated as a calculation. If you just put some text there, it will be treated as a variable name or Field name. If you mean the text itself, you must enclose it in quotation marks.

Examples:

SET vMyVariable = 1 SET vMyTextVariable = "This is my text" SET vRecordName = Name SET vDescription = concat(vRecordName, " ", Address) SET rOrg = getrecord('Organisation', 'HMRC')

There is a special syntax for dealing with multi-line variables, such as Instructions. Every line between the — START and — END lines of the named variable will be added to the variable value, preserving each as a separate line in the final value.

— START Instructions This is the instructions that go on top of the form — END Instructions

You can get creative with the content of a multi-line variable using coding logic. If you start the same variable name again, the next lines are simply appended to the previous content.

— START Instructions This is the instructions that go on top of the form. — END Instructions IF currentUserInGroup('SupportStaff') — START Instructions This is additional instructions that only get shown for users in the SupportStaff group — END Instructions ENDIF

IF / ELSE

You can conditionally include lines of the script by including them within an IF structure. This takes one of the following forms:

IF calculation … evaluate these lines if calculation is TRUE … … ENDIF
IF calculation … evaluate these lines if calculation is TRUE … … ELSE … evaluate these lines if calculation is FALSE … … ENDIF
IF calculation1 … evaluate these lines if calculation1 is TRUE … … ELSE IF calculation2 … evaluate these lines if calculation1 was not TRUE but calculation2 is TRUE … … [optional further ELSE IF calculations] ELSE … evaluate these lines if none of the previous calculations was true … … END IF

You can, of course, nest such structures to any depth needed. If you do this, you’ll find being very disciplined with your indentation is essential to ensure that you correctly END all your structures and avoid getting into a logical mess (not to mention a script that might fail to evaluate at all)

IF dayOfWeek(today()) = 5 SET vDayDescription = "It's Friday :)" ENDIF
IF dayOfWeek(today()) = 5 # These lines are only processed on a Friday SET vDayDescription = "Friday – weekend tomorrow :)" ELSE # These lines are only processed if it is NOT Friday SET vDayDescription = "Today is not Friday" ENDIF
SET vDayOfWeek = dayOfWeek(today()) IF vDayOfWeek = 6 # These lines are only processed on a Saturday SET vDayDescription = "Saturday today" ELSE IF vDayOfWeek = 7 # These lines are only processed if it is Sunday SET vDayDescription = "Sunday today" ELSE # It must be a weekday SET vDayDescription = "Some day during the week" ENDIF
IF dayOfWeek(today()) = 6 IF day(today()) <= 7 SET vDayDescription = "First Saturday of month" ELSE SET vDayDescription = "A later Saturday in the month" ENDIF ELSE SET vDayDescription = "Not a Saturday" ENDIF

EACH – Process Multiple Records (defined by a Filter)

The following syntax repeats the enclosed script lines for multiple records defined by a Record Type and an optional Filter.

EACH recordType AS rVariableName FILTER filtertext … These lines repeat for each record … … Variable rVariableName is set to the current record … END

This pattern is commonly used in Template Scripts to display a table of records. For example, the following code generates a list of all people named Smith, with their address and mobile numbers. For a full discussion of how to reference Fields of a record using the colon, see the Calculations page.

{displayTableStart("Name","Address","Mobile")} EACH Person AS rPerson FILTER Smith {displayTableRow(rPerson:Link, rPerson:Address, rPerson:MobilePhone)} END {displayTableEnd()}

EACH OF – Process Each Record in a List Field

You can make use of an existing list Field Name on a record by using EACH OF followed by the listFieldName. This is instead of specifying the record type and a filter. Now, this alternative loops through each record in the list of records defined as that list Field.

Typically, any link between two record types results in a ‘list’ Field of the ‘parent’ record. These are either predefined (such as People as a Field of Organisation), or are generated as a result of a Field that holds a reference to another (‘linked’) record. See the LinkedRecord… fields of Field for full details.

Similar to the EACH structure, the chosen variable is set to each record in turn, enabling it to be referenced in calculations inside the loop structure.

EACH OF listFieldName AS rVariableName … These lines repeat for each record … … Variable rVariableName is set to the current record … END

A Template Script example, assuming this is part of a script evaluated on an Organisation record:

{displayTableStart("Name","Mobile")} EACH OF People AS rPerson {displayTableRow(rPerson:Link, rPerson:MobilePhone)} END {displayTableEnd()}

Note that People is a built-in listField on Organisation. In general, this gives exactly the same result as if you used EACH but specified the filter on just those child records which belong to the current ‘parent’ record. It is just easier to benefit from the built-in filtering that the list fieldName provides.

FOR EACH LINE OF – Process each line of a multi-line value

You can take a multi-line value in a variable and split it to be processed in a loop, line by line. Each line is parsed and split by comma-separation into one or more variables. You can then perform any script processing on those variable values as normal. This could include a multi-line display in a template, or perhaps processing multiple records in an ActionScript.

The basic syntax of the section is:

FOR EACH LINE OF vMultiLineText AS vVar1, vVar2 … END

For example, you might set-up a form requesting a user to type in multiple people names, with their first and last names separated by a comma, one on each line. You could then process the result in an ActionScript as follows:

FOR EACH LINE OF vPeopleInput AS vFirstName, vLastName ADD Person FirstName=vFirstName LastName = vLastName END END

Of course, a real-life example would almost certainly need to do some validation checking, including checking for existing records first. The example below is taken from a simple Assets module with a multi-line Form input requesting a list of devices and their serial numbers separated by a comma.

FOR EACH LINE OF vDevices AS vDeviceName, vSerialNumber IF and(notempty(vDeviceName), empty(searchForRecord('Asset', if(empty(vSerialNumber),vDeviceName,vSerialNumber)))) ADD RECORD Asset Name=vDeviceName SerialNumber=vSerialNumber END END END

For each line, there is a test to ensure that the device name is not empty, and to search for any existing record matching the device name or serial number, before adding any genuinely new records.

FINISH

The command FINISH on a line by itself results in the script evaluation ending immediately. No further lines of the script are processed, even if the FINISH statement is inside a loop or IF…ELSE structure.

Example:

IF day(today()) <= 7 FINISH ENDIF #Rest of this script only gets processed if we are not in the first week of the month …

Get Started