Business Rules Examples

Learn more about commonly used business rules for data transformation.

Overview

Business rules are applied during data load to transform data based on defined conditions, allowing you to modify data to ensure accuracy and consistency. Understanding these transformations, and when to use them, will help you efficiently manage your event streams. For more information, seeManage event streams.

Business rules are categorized as follows:

  • Predefined business rules: These rules are built into the platform and already exist in Visier's internal rule library.
  • Formula business rules: These rules are created and defined using the Visier Business Rule Language (VBRL) to transform subject and event data within your event stream. For more information, see Formula business rules.

Predefined business rules

Predefined business rules are executed using the call tag.

Syntax

Copy
call RULENAME(
    ARG1, 
    ARG2, 
    …
)
  • call: Instructs Visier to call the predefined rule in the internal rule library.
  • RULENAME: Specifies the rule to use. Each rule executes different logic against the arguments in the formula.
  • ARG1, ARG2: Specifies the arguments, such as subjects or properties, to validate. Rules accept zero, one, or more arguments.

If a predefined rule has optional parameters, you must define parameters in the order listed in the rule syntax. For example, to declare a value for the optional2 parameter in the code below, you must present a value for optional1.

Copy
call predefinedRule(
    mandatory1, 
    mandatory2 [, optional1, optional2]

backfillChanges

Fills in missing values by adjusting the initial values of specific properties starting from a defined date. This adds information to the subject when existing values are not set. You can explicitly set the start date withstartDate. Otherwise, Visier infers the start date from the earliest recorded change in the specified properties.

Syntax

Copy
call backfillChanges(
    skipNone, 
    backfillPrimaryStreamOnly, 
    {properties} 
    [, startDate]
)
  • skipNone (optional, Boolean, default: false): A flag that determines whether properties with Nonevalues should be ignored during the rule application. When set totrue, it preventsNonevalues from being copied forward, but it does not remove or delete them from the source data.
  • backfillPrimaryStreamOnly (optional, Boolean, default: false): A flag to include the primary event stream in the rule and exclude the auxiliary event stream.
  • Properties: Specifies the properties to be adjusted in the backfill.
  • startDate: (optional): The assigned new date for the data to be backfilled to. If there is no declared startDate the rule sets the date of the first change in any of the specified properties. The format used in the rule is YYYY, MM, DD.

Examples

Say you want to backfill a property to a specific date with skipNone value set to true and the backfillPrimaryStreamOnly set to false. In this example, the First_Name property backfills using the preset values to the specified start date of January 1, 2015. This rule ignores all First_Name property values of None.

Copy
call backfillChanges(
    true
    false
    {First_Name}, 
    Date(2015, 01, 01)
)

The following table shows how the data is presented before the backfillChanges rule.

EmployeeID

Date

First_Name

ABCD1234

2016-01-31

None

ABCD1234

2016-06-01

John

The following table shows how the data is presented after the backfillChanges rule.

EmployeeID

Date

First_Name

ABCD1234

2016-01-31

John

ABCD1234

2016-06-01

John

If you want to backfill a specific property to a date with the skipNone flag set to the default false value. This example backfills the First_Name property using the specified start date and includes any First_Name property with value of None in the backfill. The backfillPrimaryStreamOnly flag is not specified, so the default value is false and the rule applies to both the primary and auxiliary event stream.

Copy
call backfillChanges(
    {First_Name}, 
    Date(2015, 01, 01)
)

You can backfill a property to a defined date with skipNone true, and only account for the primary stream when determining the startDate. In this example the rule fills in all values of the First_Name property to January 1, 2015 on the primary stream and ignores events in the auxiliary stream.

Copy
call backfillChanges(
    true
    true
    {First_Name}, 
    Date(2015, 01, 01)
)

You can backfill missing values for multiple attributes in a single application of the backfillChanges rule. In this example, you can call the backfillChanges rule on the First_Name, Last_Name, Pay_Level, and Birth_Date properties. As the startDate is not included, the backfillChanges rule resets the values in the specified properties to the value on the date of the earliest recorded change.

Copy
call backfillChanges(
    false
    {First_Name, Last_Name, Pay_Level, Birth_Date}
)

When dealing with several properties in the same rule, it makes sense to adjust all properties with a few exceptions. To define a set of properties to ignore when backfilling, use allPropertiesExcept. In this example you will learn how to backfill all properties except NonActive with the skipNone flag set to true. If no properties are specified in the allPropertiesExcept parameter (allPropertiesExcept({})), all properties defined before the rule are included in the backfill. Be aware that this may lead to unintended effects on time-sensitive properties like NonActive or Performance.

Copy
call backfillChanges(
    true
    allPropertiesExcept({NonActive})
)

groupAndPick

Picks a single event out of a set of events, and deletes all other events that remain in the set. This is useful for removing duplicate events, resolving inconsistencies between data sources, and handling multiple changes on the same timestamp.

Syntax

Copy
call groupAndPick(
    picker,      
    groupBy,    
    groupFilter 
)
  • picker: Defines how to select a single event from the grouped set. For more information, see Picker functions.
  • groupBy (optional): Groups events before passing them to the picker.
  • groupFilter (optional): Defines which events are considered by the rule. This parameter is used to limit the events deleted by groupAndPick.

To use groupAndPick:

  1. Select events that satisfy the eventFunction in the picker. The eventFunction specifies which events are considered for the picking strategy. For more information, see Picker functions.
  2. Filter these events using groupFilter. Those that satisfy the filter are candidates of being grouped while others are ignored.
  3. Group the filtered events according to the groupBy parameters.
  4. Filter the groups with the pickFilter parameter.
  5. For each group, select a single event using the picker. For example, pickEarliest or pickLatest.

Picker functions

A picker function in the groupAndPick rule limits the events picked after grouping, or extends the range of the picking strategy to more than one date.

Copy
pickEarliest(
eventFunction,
pickFilter,
interval,
startDate,
endDate
)
  • pickEarliest: Returns the earliest event out of a group.

  • eventFunction: Specifies which events are considered for the picking strategy. For example, FirstName or PayEvent.
  • pickFilter (optional): A filter function that is applied to events before a picking strategy is considered. This filter is used to restrict the events considered for picking.
  • interval (optional): The interval in which the picking strategy should be applied. For more information about the available options for this parameter, see Count functions.
  • startDate, endDate (optional): Parameters that determine the interval of the picker function applied. Events outside of this interval are ignored and remain as they are in the event stream.

For example, pickEarliest(Pay_Change, true, days(10)) will consider a ten day time span when picking a single event from a group.

Copy
pickLatest(
eventFunction,
pickFilter, 
interval, 
startDate, 
endDate
)
  • pickLatest: Returns the latest event out of a group. It accepts both a picking filter to limit the events that are considered to be picked and an interval that could extend the range of the picking strategy to more than one date.

  • eventFunction: Specifies which events are considered for the picking strategy. For example, FirstName or PayEvent.
  • pickFilter (optional): A filter function that is applied to events before a picking strategy is considered. This filter is used to restrict the events considered for picking.
  • interval (optional): The interval in which the picking strategy should be applied. For more information about the available options for this parameter, see Count functions.
  • startDate, endDate (optional): Parameters that determine the interval of the picker function applied. Events outside of this interval are ignored and remain as they are in the event stream.

For example, pickLatest(Pay_Change, true, days(10)) considers a ten day time span from the most recent event when picking a single event from a group.

Copy
concatenate(    
eventFunction,
resultProperty,
First_Name,
delimiter
)
  • concatenate: Combines groups of property changes to a single property change. This new property change updates the resultProperty, setting its value to the concatenated results returned by eventFunction. Concatenation is only applicable to string subject properties and not event properties.

  • eventFunction: Specifies which properties will be concatenated. For example, First_Name.
  • resultProperty: Where the concatenated result of the group are stored. This could be any string property, including one from eventFunction.
  • delimiter: A constant string used as the delimiter when concatenating values of a group. For example, ;

For example, call groupAndPick(concatenate(First_Name, First_Name, ";"), 1, First_Name != "Important" ) would concatenate the picker function to apply to First_Name properties where values equal to Important are excluded from groupAndPick operation.

Copy
pickByMax
valueFunction,
addFunction,
resetTrigger
)
  • pickByMax: Returns an event with the highest valueFunction value when addFunction is triggered. The maximum value resets when resetTrigger begins.

For example, pickByMax(PayEvent.PayAmount, PayEvent, last(PayEvent)) picks the PayEvent with the maximum PayAmount.

Copy
pickByMin
valueFunction,
addFunction,
resetTrigger
)
  • pickByMin: Returns an event with the lowest valueFunction value when addFunction is triggered. The minimum value resets when resetTrigger executes.

For example, pickByMin(PayEvent.PayAmount, PayEvent, last(PayEvent)) picks the PayEvent with the minimum PayAmount.

Count functions

The following table describes the time span function used in the pickAndGroup rule. A value of function() with no numeric count included in the brackets is equivalent to a single instance. For example, one day is day(), one month is month(), and one year is year().

Function Description

days(count)

Events that happen within the specified days of the initial member of a group are grouped together. For example, groupAndPick(pickEarliest(PayEvent, days(2)) groups events that occur within two days of the group's initial member and picks the earliest event.

months(count)

Events that happen within the specified months of the initial member of a group are grouped together. Starts from the first day of the month the initial member of a group appears. For example, groupAndPick(pickEarliest(PayEvent, months(2)) groups events that happen within two months from the first day of the month where the initial member of a group appears and picks the earliest one.

years(count)

Events that happen within the specified year of the initial member of a group are grouped together, starting from the first day of the year the initial member of a group appears. For example, groupAndPick(pickEarliest(PayEvent, years(2)) groups pay events that happen within two years from the first day of the year where the initial member of a group appears and picks the earliest.

Examples

This business rule example picks a single event out of all events on a date. This examines all Pay_Change regular events on a single date and picks the Pay_Change which either has the most recent timestamp value or whichever event is most recent.

Copy
call groupAndPick(
    pickLatest(Pay_Change)
)

In this example, the rule selects the first event on a given date, pay changes occurring within two days of the initial member are grouped together, and the earliest one is chosen.

Copy
call groupAndPick(
    pickEarliest(Pay_Change, true, days(2))
)

In this example, the groupAndPick rule selects a single event from all Pay_Change regular events on a date. This example will examine all Pay_Change regular events on a date and divides them into different categories based on their PayType value. Then, for each category, only the Pay_Change with the most recent event is picked.

Copy
call groupAndPick(
    pickLatest(Pay_Change), 
    Pay_Change.PayType
)

In this example, the groupAndPick rule deletes events that are not the Regular pay type.

Copy
call groupAndPick(
    pickEarliest(Pay_Change), 
    "A constant value"
    Pay_Change.PayType = "Regular"
)

In addition to groupFunction, there is another way to control the events that are picked by groupAndPick. The following example shows how pickEarliest and pickLatest have an optional parameter called pickFilter permitting finer control over picking operation. In this example, the rule excludes events with Amount less than or equal to fifty from the selection process.

Copy
call groupAndPick(
    pickEarliest(Compensation_Payout.Payout_Amount > 50), 
    Compensation_Payout.Payout_Type
)

augmentingMapping

Uses the values of a property to look up values in the target mapping file object and apply them to the properties in the current subject. This rule does not override existing property values, so it is good for adding data to empty properties or for filling in gaps or missing data.

Syntax

Copy
call augmentingMapping(
    mappingName, 
    mappingKey, 
    mappedProperties [, ifUnmapped, filter, ifOutputExist, ignoreIfNoValue]
)
  • mappingName: The object name of the mapping file.
  • mappingKey: The lookup key property in the current subject. This must be an existing property in the subject and should not be a subject ID like EmployeeID.
  • mappedProperties: The properties in the current subject that are mapped to strings corresponding to column names in the target mapping. The syntax is Map[Property -> String].
  • ifUnmapped (optional, useDefault() or ignore(), default: ignore()): Specifies behavior when no match is found in the target object.
  • useDefault() (optional): Inserts a default-valued event if no lookup value found.
  • ignore() (optional): Does nothing when lookup key does not exist in lookup stream.
  • filter (optional): Applies a filter to the lookup process.
  • ifOutputExist (optional, augmentAnyways() or noAugmentIfValueExist(), default: augmentAnyways()): Determines if augmentation occurs when values already exist.
  • augmentAnyways() (optional): Always augments the event stream with lookup events.
  • noAugmentIfValueExist() (optional): Does not augment the event stream if the stream contains existing property values.
  • ignoreIfNoValue (optional, Boolean, default: false): If true, it prevents event insertion when no lookup value is found.

Example

Let's say you want to use the values of a property to look up values in the target mapping file object and apply them to the properties in the current subject. This will augment a single mapping by adjusting the property values in the subject property. In this example, the rule assigns the lookup property CompMax to the Employee.Pay_Level_Compensation_Maximum property, and CompMin to the Employee.Pay_Level_Compensation_Minimum property. This rule only applies if the property is unmapped in the existing mapping and if the date of change is on or after January 1, 2018. This applies to values that already exist by adding the aumentAnyways(). Because ignoreIfNoValue is false, the rule allows event insertion when no lookup value is found. This example relies on the pay_levels_post_stg lookup existing in the data.

Copy
call augmentingMapping(
    "pay_levels_post_stg"
    Employee.JobPayLevelCode,
    {
    Employee.Pay_Level_Compensation_Maximum -> "CompMax"
    Employee.Pay_Level_Compensation_Minimum -> "CompMin" 
    },
    useDefault(),
    dateOf(changeIn(Employee.Pay_Level)) >= date(2018,1,1),  
    augmentAnyways(),
    false
)

augmentingMultipleMapping

The augmentingMultipleMapping rule is similar to the regular augmenting mapping rule. However, augmentingMultipleMapping accepts a mapping targetGroup instead of a single mapping name. By including a targetGroup, the business rule can be associated with all lookup mappings defined with the target group, and combine information from these mappings into the auxiliary stream.

Syntax

Copy
call augmentingMultipleMappings(
    targetGroup, 
    mappingKey, 
    mappedProperties, 
    ifUnmapped, 
    filter, 
    ifOutputExist, 
    ignoreIfNoValue
)
  • targetGroup: Includes supplemental data in a mapping that is considered separate from the main source. For more information, see Target group.

changeDates

Inserts a value for targetProperty based on the provided nameChangeDateProperties. The targetProperty value is the corresponding string for the property's namedChangeDateProperties. Use this rule if you want to insert different values based on different dates provided in the source.

Syntax

Copy
changeDates(
    targetProperty, 
    {namedChangeDateProperties},
    changeAll
)
  • targetProperty: The property changed by the rule application.
  • namedChangeDateProperties: A map of date properties to string values that would be inserted for targetProperty. The syntax is namedChangeDateProperties -> new string value. For example, Requisition.temp_CreatedDate -> "Created".
  • changeAll (optional, Boolean, default: false): If true an event is inserted at every timestamp for each nameChangeDateProperties profile change event. If false an event is inserted at the last timestamp for each nameChangeDateProperties profile change event.

Examples

The code samples below demonstrate how the changeDates rule is applied to the source data. In this example it is used to insert a value for the target property, Requisition.Requisition_Status, based on the provided nameChangeDateProperties.

Copy
call changeDates(
    Requisition.Requisition_Status, 
    {Requisition.temp_CreatedDate -> "Created",
    Requisition.temp_ApprovedDate -> "Approved",
    Requisition.temp_ClosedDate -> "Closed"}
)

The following table represents the source data stream before applying the rule. The data is presented in a wide format.

Requisition ID

Created

Approved

Closed

1

1-1-2019

2-1-2019

3-1-2019

The following table represents the resulting stream after the changeDates rule is applied. Because changeAll is true, the rule inserts an event at every timestamp for each nameChangeDateProperties profile change event.

Requisition ID

Event Date

Requisition Status

1

1-1-2019

Created

1

2-1-2019

Approved

1

3-1-2019

Closed

consolidateRegularEvents

Consolidates multiple regular events on the same date or over a range of dates into a single event. For example, running this rule sums all pay events that happen in the same month as designated by EventDate.

Syntax

Copy
call consolidateRegularEvents(
    regularEventSchema,     
    groupingProperty,       
    resolutionStrategies    
    filter,                 
)
  • regularEventSchema: The regular event to be consolidated. For example, PayEvent.
  • groupingProperty: The grouping property applied to the regular event. For example, PayEvent.PayType would group together all PayTypes in the PayEvent.
  • resolutionStrategies: Defines the consolidation method. Several strategies can exist in the same rule, but the groupingProperty should never be included in the application of resolutionStrategies. This parameter is required for all available properties except for the primary key and EventDate. The syntax for this parameter is PayEvent.Amount -> sum().
  • filter (optional): Provide exceptions to the above rule when consolidating events. For example, PayEvent.PayType != "Bonus" would exclude all values for pay labeled as Bonus.

Resolution strategies

The following strategies can be used as part of the resolutionStrategies parameter.

  • sum(): Sums the value of the given attribute for all regular events on the day. Can only be applied to attributes that are integers.
  • average(): Takes the average value of the given attribute for all regular events on the day. Only applies to attributes that are floating-point numbers, or numbers that have decimal points.
  • ignoreAttribute(): Ignores the attribute and sets it to None in the consolidated event.
  • max(): Takes the largest value of the attribute for all regular events on the day and stores it in the consolidated regular event.
  • min(): Take the smallest value of the attribute for all regular events on the day and stores it in the consolidated regular event.

Examples

Say you wanted to consolidate multiple regular events happening on the same date. The example below adds together all Amount values of each separate PayType (Labor or Dinner) occurring on the same EventDate.

Copy
call consolidateRegularEvents(
    PayEvent,
    PayEvent.PayType,
    { PayEvent.Amount -> sum(), 
    PayEvent.PayLevel -> sum() PayEvent.PaySystem -> ignoreAttribute() } 
)

The following table shows how the data is represented before the consolidateRegularEvents rule is applied.

EmployeeID

EventDate

PayType

Amount

Hours

PaySystem

ABCD1234

2018-06-04

Labor

100.00

10

ADT

ABCD1234

2018-06-04

Labor

100.00

10

kronos

ABCD1234

2018-06-04

Labor

100.00

10

Namely

ABCD1234

2018-06-04

Labor

100.00

10

ADT

ABCD1234

2018-06-04

Labor

100.00

10

ADT

ABCD1234

2018-06-04

Labor

-50.00

-5

kronos

ABCD1234

2018-06-04

Dinner

20.00

0

Namely

ABCD1234

2018-06-04

Dinner

20.00

0

Namely

ABCD1234

2018-06-04

Dinner

20.00

0

kronos

The following table shows how the data is represented after the consolidateRegularEvents rule is applied. Because the rule specifies PayEvent.PaySystem -> IgnoreAttribute (), the resulting data replaces PaySystem values with None.

EmployeeID

InvoiceDate

PayType

Amount

Hours

PaySystem

ABCD1234

2018-06-04

Labor

450.00

45

None

ABCD1234

2018-07-31

Dinner

40.00

0

None

Say you wanted to consolidate distinct events of different types in to separate groups using the EventDate attribute. These events would be over a span of days and the source data contains attributes that are not relevant to the grouping and should be ignored. In this example, the values for Amount of each PayType are added and grouped by the different dates.

Copy
call consolidateRegularEvents(
    PayEvent,
    PayEvent.PayType, 
    { PayEvent.Amount -> sum(), PayEvent.PayLevel -> sum() PayEvent.PaySystem -> ignoreAttribute() },
    month() 
)

The following table shows how the data is represented before the consolidateRegularEvents rule is applied.

EmployeeID

EventDate

PayType

Amount

Hours

PaySystem

ABCD1234

2018-06-10

Labor

100.00

10

ADT

ABCD1234

2018-06-11

Labor

100.00

10

kronos

ABCD1234

2018-06-15

Labor

100.00

10

Namely

ABCD1234

2018-06-16

Dinner

50.00

0

ADT

ABCD1234

2018-07-04

Labor

100.00

10

ADT

ABCD1234

2018-07-10

Labor

-50.00

-5

kronos

ABCD1234

2018-07-11

Dinner

20.00

0

Namely

ABCD1234

2018-07-30

Labor

100.00

10

Namely

ABCD1234

2018-07-31

Dinner

20.00

0

kronos

The following table shows how the data is represented after the consolidateRegularEvents rule is applied. Because the rule specifies that PayEvent.Amount -> sum(), PayEvent.PayLevel -> sum() PayEvent.PaySystem -> ignoreAttribute() } month(). The Amount for each PayType have been summed and filtered by month.

Note: The PaySystem attribute is ignored in the rule and is replaced by a None value in the data.

EmployeeID

InvoiceDate

PayType

Amount

Hours

PaySystem

ABCD1234

2018-06-30

Labor

300.00

30

None

ABCD1234

2018-06-30

Dinner

50.00

0

None

ABCD1234

2018-07-30

Labor

250.00

15

None

ABCD1234

2018-07-31

Dinner

40.00

0

None

addValidRanges

Adds valid ranges to profile change events and can apply to a single property or several properties in the same instance. These ranges may differ between file types, for example temporal versus transactional. For more information, see Data Load Types, Frequency, and Granularity. This rule will look for profile change events that have a property contained in targetProperties and will add a valid range if the following conditions are met.

  • The profile change event property exists in targetProperties.
  • The profile change events does not have a defined valid range.
  • Another profile change event with a defined valid range occurs at the same time as the targetProperties.

Syntax

Copy
call addValidRanges(
    targetProperties [, filter]
)
  • targetProperties : The properties to add valid ranges to.
  • filter (Optional): Controls which properties will be targeted by the rule.

Example

Say you want to add a valid range to an attribute called Employment_Status on the Employee subject. In this example, the rule would add a valid range to all None attributes to match the value of the Employment_Status attribute on the same date.

Note: How the profile change event on 2018-09-30 is not affected by this rule as there are no other profile events on that date.

Copy
call addValidRanges(
    { Employee.Employment_Status }
)

The following table shows how the data is presented before the addValidRanges rule is applied.

Date Attribute

Value

Valid Range

2018-06-30

Employment_Status

Active

None

2018-06-30

Employment_Type

Labor

2018-06-01 to 2018-06-30

2018-09-30

Employment_Status

Inactive

None

The following table shows how the data is presented after the addValidRanges rule is applied.

Date Attribute

Value

Valid Range

2018-06-30

Employment_Status

Active

2018-06-01 to 2018-06-30

2018-06-30

Employment_Type

Labor

2018-06-01 to 2018-06-30

2018-09-30

Employment_Status

Inactive

None

moveToStartOfDay

Adjusts all events in the event stream to align to 00:00:000 coordinated universal time (UTC). This rule is added when a subject is configured to be day granularity in the application, but the data has finer granularity. Employee data typically uses day-level granularity, where timestamps are uncommon. If new data includes timestamps, either the mapping formula can be updated to exclude them, or the rule can be added to remove the timestamps.

Syntax

Copy
call moveToStartOfDay()

dropProfileIfCondition

Looks for a condition in the existing data and removes all events when that condition is met. The condition is specified using conditionFunction and when satisfied marks all events pertaining to a subject ID for removal. Marked events are then deleted if cancelFunction is never fired using the default value false. When removing multiple IDs, due to duplication or the person is no longer employed with the company, the source data will include a column to explicitly state which employees should be removed. This column can be used as a parameter in the function.

Syntax

Copy
call dropProfileIfCondition(
    conditionFunction[, 
    cancelFunction, 
    endDate]
)
  • conditionFunction: Specifies all events, both profile and regular, for the current subject that will be marked for deletion.
  • cancelFunction (optional, default: false): If true cancels the effect of conditionFunction. Events will be marked for deletion but will not be deleted.
  • endDate (optional): The date specifying the range of the rule. Only events happening before or on the endDate will be deleted. The format is YYYY, MM, DD

Example

In this example, all conditionFunction values of First_Name equal to Test will be marked for deletion. The cancelFunction default value is false and as there is no endDate specified, all events to the current date will be deleted.

Copy
call dropProfileIfCondition(
    First_Name = "Test"
    endDate(2016, 01, 01)
)

replacementMapping

Replaces the values of a property with values in the target mapping file object. It can be considered an override where the lookup key is the mapping property.

Syntax

Copy
call replacementMapping(
    mappingName, 
    mappingKey, 
    targetColumn [, filter, useDefault, ignoreIfNoValue]
)
  • mappingName: Object name of the mapping file object.
  • mappingKey: The property used as the lookup key. This property must exist in the current subject for the rule to execute correctly.
  • targetColumn: A column name in the target mapping file object. If the lookup fails, the value of targetColumn is set to None.
  • filter (optional): A filter to apply to the mapping events.
  • useDefault (optional, Boolean, default: true): If true it will insert a default value for the attribute if no lookup is found. If false, it will do nothing to the mapping file object. This is only used when the lookup key does not exist in lookup stream.
  • ignoreIfNoValue (optional, Boolean, default: false): When true, the rule will not insert events when no lookup value is found.

Examples

In this example, the rule would replace the values in New_Location_Value with the values from Employee.Location.Location_3 in the Location_Lookup mapping file. As the lookup key exists in the lookup stream, useDefault is not necessary and the default value of ignoreIfNoValue is false.

Copy
call replacementMapping(
    "Location_Lookup"
    Employee.Location.Location_3, 
    "New_Location_Value"
)

In this example we will find and correct values in the New_Location_Value target column by setting the filter value as true and the useDefault as false. Setting useDefault to false means that any value not found will be replaced with Unknown and the rule will only provide values necessary for the changes.

Copy
call replacementMapping(
    "Location_Lookup"
    Employee.Location.Location_3, 
    "New_Location_Value", true, false
)

createSubjectMember

Inserts a new subject ID and associated properties if no subject member with the same ID is present in the data. This rule can be used to insert virtual members in dimensions or other placeholder subject members. For example, if you want an organization hierarchy for a subset of people to rollup into a different organization first. You can make this new organization using this rule, and adjust the mappings so the subset of people rollup into this new organization instead.

Syntax

Copy
call createSubjectMember(
    idProperty, 
    id [, otherPropertyAssignments, creationDate]
)
  • idProperty: Key property of the subject.
  • id: ID of the created subject member.
  • otherPropertyAssignments (optional): Extra map of properties to assign in the newly-created member. The mapping format is Map[Property → Value].
  • creationDate (optional): A date to create the subject member. If undeclared it defaults to the earliest possible date in the data.

Examples

Say you wanted to insert a new member in the Organization_Hierarchysubject. In this example, a new organizationAcme Corp, with the ID value of -1 is created. If a different ID is desired then it can be supplied as an optional second argument.

Copy
call createSubjectMember(
    Organization_ID, "-1"
    {Organization_Name -> "Acme Corp"}
)

When the idProperty value is not currently available you can insert an Unknown parent-child dimension member. This inserts a new member in the Organization_Hierarchy subject with the default Unknown value.

Copy
call createSubjectMember(
    Organization_ID, "-999"
    {Organization_Name -> "Unknown"
    Parent_Organization_ID -> "-1"}
)

Formula business rules

Formula business rules are created and defined using the Visier Business Rule Language (VBRL) and are written as a single expression that transforms records on a single entity’s event stream, processing events chronologically. Each rule consist of a trigger, optional conditions, and at least one action.

VBRL incorporates many standard programming functions, such as logical operators, comparisons operators, and string functions including case modification, concatenation, and substrings. Understanding these core functions is crucial for writing effective VBRL rules. For a detailed description of the Visier Business Rules Language syntax, seeVisier Business Rule Language (VBRL).

Trigger and conditions

Formula business rules are executed using a trigger, indicated by the when tag. The trigger is what initiates the rule and is often tied to an event or a change in an attribute's value.

For example, if you want to perform an action based on whether an employee's first name has been changed at least once in their record you would include atLeastOnce in your trigger. This function looks at the entire history of the event stream, not just the current state and returns true if the property has changed at least once, otherwise it returns false.

Copy
when atLeastOnce(changeIn(Employee.First_Name))

When writing your formula, you can also include conditions that do not directly trigger the rule, but must be met for it to proceed. These conditions might involve checking an attribute's current value, comparing a property to its previous value, or confirming that two attributes match.

Note: All events on the same timestamp are processed before trigger conditions are checked. The sort order of events with the same timestamp does not affect the rule's execution.

When you're establishing conditions, it's helpful to distinguish between filter conditions and conditional logic conditions. The key distinction here is whether the action changes based on the condition's outcome, or if no action is taken if the condition is false.

  • Filter conditions: These determine whether an action is taken or not. They are usually defined using and or or. If a filter condition is false, the rule will not perform an action.

  • Conditional logic conditions: These alter what action is taken, but do not prevent an action from occurring. They are usually defined using if and else.

Dates and timing

When forming your trigger and conditions you want to ensure you’re using the correct point in time. Understanding the nuances of currentValueOf, previousValueOf, and valueAsOf is critical for your rule's accuracy.

  • currentValueOf(property): Returns the value of the property from the most recent event.

  • previousValueOf(property): Returns the value of the property from before the most recent event.

  • valueAsOf(property, dateObject): Returns the value of a property at a specific date.

When your trigger is a change in a particular attribute, use valueAsOf for retrieving values of a property that did not change simultaneously with the trigger attribute. For example, to get the value of Employee.Job_Name from the day before the trigger event, the condition would be written as follows:

Copy
valueAsOf(Employee.Job_Name, shiftDays(dateOf(current(changeIn(<trigger condition attribute>))), -1))

Common date functions

Effectively managing and manipulating dates is essential for creating time-sensitive business rules. VBRL provides a comprehensive set of date functions to define, format, and extract information from date values. Below are the most commonly used date functions. For a detailed description of all date functions available, see Date functions.

  • date(yearNumber, monthNumber, dayNumber): Returns a date object based on the three integer parameters. This is the best way to create constant dates, often used when defining cut-off points for logic.

  • dateOf(current(changeIn(AttributeX))) or dateOf(Regular_Event) returns the date associated with an event. This can combine with the changeInAny function to get the date of the most recent change in any of the attributes mentioned.

  • shiftDays(dateObject, numberOfDays): Returns a date shifted by a number of days. You can specify a positive or negative value for the number of days. There are equivalent versions for many other time granularities from milliseconds to years.

  • daysBetween(dateValue, dateValue): Returns the number of complete days between two dates. This function returns a negative value if the first argument is less than the second argument. It's important to carefully consider the time granularity of the events themselves when building logic using these functions.

  • getYear(dateObject): Returns the year from a date as an integer.

  • firstOfYear(dateValue): Returns a date value shifted to the first day of the calendar year.

  • formatDate(dateFormatString, dateValue): Returns a date string in the specified format such as yyyy-MM-dd or yyyyMM.

Defining actions

Actions are the last component of a business rule and determine what your rule does once its trigger and all additional conditions are met. A business rule can have more than one action. Primary actions include add, update, and delete.

  • add: Adds a new regular event or a profile change event by overwriting any previously existing profile change events.

  • update: Updates an existing event or creates a new event if one doesn’t exist for that timestamp. Keep in mind that by default, update only affects one event per timestamp. To update multiple events on the same timestamp, use update all(filter) for profile change events or forEach <event> update(filter) for regular events.

  • delete: Deletes events. This is similar to update, where it typically only affects one event per timestamp unless you use the all function.

Updating effective dates

To update the effective date (or event date) of a profile change event, set the effectiveDate in addition to the attribute you’re modifying. If the intent is to move a profile change event from one date to another, the original change event must be deleted.

Update a regular event:

Copy
update current(Internal_Placement) (Internal_Placement.Placement_Type := "Promotion", effectiveDate := dateOf(changeIn(Employee.Career_Level)))

Change the date of a profile change event:

Copy
update First_Name := currentValueOf(First_Name), effectiveDate := shiftMonths(dateOf(current(changeIn(First_Name))), -1)

Move the profile change event from one date to another:

Copy
update First_Name := currentValueOf(First_Name), effectiveDate := shiftMonths(dateOf(current(changeIn(First_Name))), -1),
delete current(changeIn(First_Name))

Updating multiple events on the same timestamp

To update multiple events with the same timestamp, there are different options depending on the scenario.

  • Update all(filter) or delete all(filter): Affects all events in the timestamp matching the specified filter and applies the same function to each event. This is useful for deleting all events on a specific date, or updating all events with a single result regardless of the event’s attributes.

  • forEach: Updates multiple regular events that occur at the same time while processing the specified rule independently for each event. This allows you to apply conditional logic or update an attribute based on the value of another attribute.

For example to update a compensation payout amount based on an employee’s FTE factor, the formula would be written as follows:

Copy
forEach Compensation_Payout update (Compensation_Payout.Payout_Amount := Compensation_Payout.Payout_Amount * Employee.FTE_Factor)

Each Compensation_Payout event would have its individual payout amount adjusted by the FTE factor, unlike update all(filter), which would apply the same adjustment to all events based on the last event encountered.

You can also incorporate the while function to add filters or conditional logic specific to the events themselves. This is a variant of the above example that behaves differently based on the Payout_Type event.

Copy
`forEach Compensation_Payout update while(Compensation_Payout.Payout_Type = "Overtime")(Compensation_Payout.Payout_Amount := Compensation_Payout.Payout_Amount * 1.5),` `forEach Compensation_Payout update while(Compensation_Payout.Payout_Type = "Hourly")(Compensation_Payout.Payout_Amount := Compensation_Payout.Payout_Amount * 8),` `forEach Compensation_Payout update while(Compensation_Payout.Payout_Type = "Salary")(Compensation_Payout.Payout_Amount := Compensation_Payout.Payout_Amount * Employee.FTE_Factor)`

Logic based on the attributes of the regular event must be within the while function, however logic based on attributes belonging to the subject entity can be placed directly within the assignment.

Updating attributes on different dates

If you need to update attributes on different dates, use multiple update statements, each with its own effectiveDate assignment.

Copy
when changeIn(Employee.First_Name)
update Employee.Last_Name := "Smith", effectiveDate := shiftDays(dateOf(current(changeIn(Employee.First_Name))),1),
update Employee.Job_Name := "Developer", effectiveDate := dateOf(first(changeIn(Employee.EmployeeID)))

This rule triggers when a ProfileChangeEvent onFirst_Nameis seen.

It updates Last_Name to Smith the day after the First_Name change and sets Job_Name to Developer as of the date of the first change in EmployeeID.

Conditional logic and actions

A business rule can include multiple actions, however if you want to apply multiple actions based on conditional logic you have to nest the if statement within the := assignment, which sets the value of the attribute on the left to the result of the expression on the right.

For example, to update an attribute differently based on a condition, the formula would be written as follows:

Copy
when changeIn(Employee.First_Name) update Employee.Last_Name := if (Employee.First_Name = "Bob") "Smith" else "Farmer", update Employee.Gender := "Male"

This rule triggers when the first name changes. It updates the Employee.Gender to Male and sets Last_Name to Smith if First_Name is Bob, otherwise it sets Last_Name to Farmer. If you only wanted to change Last_Name if First_Name is Bob, the else statement would be else currentValueOf(Employee.Last_Name) which adds a profile change event setting the last name to its current value.

For conditional logic involving multiple attributes or options, the match syntax offers a compact alternative to nested if/else statements. It lets you perform multiple actions when values meet the specified criteria.

Note: The match syntax can only execute a single action statement, for example, updating multiple attributes in a single statement is possible but deleting changes simultaneously is not.

Copy
when changeInAny({Employee.Job_Name,Employee.Job_Family}) match(currentValueOf(Employee.Job_Family) + "_" + currentValueOf(Employee.Job_Name)) {
"Builder_Developer I" -> update Employee.FTE_Factor := 1.0, Employee.Exempt := "Exempt",
"Supporter_Accountant I" -> update Employee.Exempt := "Non Exempt",
else -> update Employee.Exempt := "Unknown", Employee.Job_Group := "Unknown"}

This rule triggers when Employee.Job_Name or Employee.Job_Family changes. It then combines the current values of Job_Family and Job_Name into a single string, for example, Builder_Developer I or Supporter_Accountant Iand updates different attributes depending on which case is matched.

Formula business rules examples

Create internal placement events

You may have a scenario where you want to add events based on specific conditions.

In the example below, the rule activates when Career_Level, Organization_ID, or both change. It then uses the current and previous day's values to determine the attributes for the new internal placement event.

Copy
when changeInAny({Employee.Career_Level,Employee.Organization_ID})
add Internal_Placement(
  Internal_Placement.EmployeeID := currentValueOf(Employee.EmployeeID),
  Internal_Placement.Placement_Type := if(currentValueOf(Employee.Career_Level) > valueAsOf(Employee.Career_Level,shiftDays(dateOf(changeInAny({Employee.Career_Level,Employee.Organization_ID})), -1)) "Promotion"
     else if(currentValueOf(Employee.Career_Level) < valueAsOf(Employee.Career_Level,shiftDays(dateOf(changeInAny({Employee.Career_Level,Employee.Organization_ID})), -1)) "Demotion"
     else "Lateral",
  Internal_Placement.Old_Organization_ID := valueAsOf(Employee.Organization_ID,shiftDays(dateOf(changeInAny({Employee.Career_Level,Employee.Organization_ID})), -1)),
  Internal_Placement.New_Organization_ID := currentValueOf(Employee.Organization_ID)

Keeping the first or last value

You may have a scenario where you only want to keep the first or last value of an attribute or event.

This rule will change First_Name to its original value every time it changes.

Copy
when changeIn(Employee.First_Name) update Employee.First_Name := firstValueOf(Employee.First_Name).

This rule will keep only the first Hire event.

Copy
when Hire and current(Hire) != first(Hire) delete current(Hire)

Moving date attribute changes to the value

Often, when a date attribute is updated, you want the change to reflect as if it occurred on the new date itself, rather than the date the change event was recorded.

In the example below, the rule moves all changes in Tenure_Start_Date to occur on the date being set. It does this by updating the attribute to its current value with the new effective date, then deleting the original profile change event.

Copy
when changeIn(Employee.Tenure_Start_Date)
update
  Employee.Tenure_Start_Date := currentValueOf(Employee.Tenure_Start_Date),
  effectiveDate := currentValueOf(Employee.Tenure_Start_Date),
delete current(changeIn(Employee.Tenure_Start_Date))