Condition
A condition is a tree-shaped expression that is evaluated against a set of Harmoney data points. It is used in many parts of the configuration, for example in Validations, Actions, Providers, Flow Definitions and Form Definitions.
Every node of a condition tree must contain exactly one of the properties listed below: either a logical operator (not, and, or) that nests further conditions, or a comparison that targets a data point through a fieldPath.
A wrong operator never raises a configuration error: the condition simply evaluates to false (or, for a negated
operator, to true). Check Choosing an operator before configuring one.
Logical operatorsβ
Logical operators do not have a fieldPath of their own. They combine other conditions.
andβ
A list of nested conditions; all of them must evaluate to true. Use it for "X and Y", and to guard a condition
with isNotNull (see Unanswered questions).
{
"and": [
{ "equals": { "fieldPath": "type", "value": "KNOW_YOUR_CUSTOMER" } },
{ "equals": { "fieldPath": "client.partyType", "value": "COMPANY" } }
]
}
orβ
A list of nested conditions; at least one of them must evaluate to true. Use it when the alternatives target
different field paths, or to combine several contains on a list. For several values of the same
single-value field, prefer in.
{
"or": [
{ "equals": { "fieldPath": "metadata.HIGH_RISK", "value": true } },
{ "equals": { "fieldPath": "metadata.PEP", "value": true } }
]
}
notβ
A single nested condition that must evaluate to false. Prefer the dedicated negated operator when there is one
(notEquals, notIn, notContains, notLike, isNotNull, isNotInList); use not to invert a combination.
{
"not": {
"and": [
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SALARY" } },
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SAVINGS" } }
]
}
}
{
"and": [
{ "equals": { "fieldPath": "type", "value": "KNOW_YOUR_CUSTOMER" } },
{ "not": { "equals": { "fieldPath": "status", "value": "CLOSED" } } },
{ "or": [
{ "equals": { "fieldPath": "metadata.HIGH_RISK", "value": true } },
{ "equals": { "fieldPath": "metadata.PEP", "value": true } }
]}
]
}
Comparison conditionsβ
All comparisons take a fieldPath that points to a data point. The available field paths depend on the context in which the condition is used (see Field path below).
Each operator below states whether it works on a single value or on a list (for example a MULTIPLESELECT answer).
equals / notEqualsβ
Works on: a single value. The data point must (not) be equal to value.
equalscompares text representations, so"true"matches a boolean and"COMPANY"matches an enum value.- For a decimal number, write the value with its decimals (
25.0), otherwise25does not match25.0. - On a list,
equalsis nevertrueandnotEqualsis alwaystrue.
{ "equals": { "fieldPath": "client.partyType", "value": "COMPANY" } }
{ "equals": { "fieldPath": "dossier.questions.IS_PEP", "value": true } }
{ "notEquals": { "fieldPath": "status", "value": "CLOSED" } }
in / notInβ
Works on: a single value. The data point must (not) be equal to one of the strings in values. Shorter than
an or of equals on the same field.
- On a list,
inis nevertrueandnotInis alwaystrue.
{ "in": { "fieldPath": "dossier.questions.SOURCE_OF_FUNDS", "values": ["SALARY", "PENSION"] } }
{ "notIn": { "fieldPath": "type", "values": ["BYLAWS", "ID_CARD"] } }
contains / notContainsβ
Works on: a list. The data point must be a collection that does (not) contain value. This is the operator
for MULTIPLESELECT, MULTI_AUTOCOMPLETE and MULTI_COUNTRY answers.
- On a single value,
containsis nevertrueandnotContainsis alwaystrue. - Combine several
containswithor(any of the options) orand(all of the options).
containsA MULTIPLESELECT answer is a list, even when only one option is selected. equals, in and isInList never
match it; notEquals, notIn and isNotInList always do; like and notLike match against the text of the
whole list. Use contains / notContains.
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SALARY" } }
{
"or": [
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "INHERITANCE" } },
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "DONATION" } }
]
}
{
"and": [
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SALARY" } },
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SAVINGS" } }
]
}
{ "notContains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SAVINGS" } }
like / notLikeβ
Works on: a single text value. The data point must (not) match the regex in value; the whole text must
match, and % is interpreted as .*.
- On a list, the result is unreliable: the pattern is matched against the text of the whole list.
{ "like": { "fieldPath": "name", "value": "ACME%" } }
{ "notLike": { "fieldPath": "name", "value": "TEST%" } }
greaterThan / smallerThanβ
Works on: a single number, or a date compared with a relative date-time.
Both comparisons are strict; for "at least", combine with equals in an or.
{ "greaterThan": { "fieldPath": "ubo.percentage", "value": 25 } }
{ "smallerThan": { "fieldPath": "dossier.questions.YEARLY_INCOME", "value": 30000 } }
{
"or": [
{ "greaterThan": { "fieldPath": "ubo.percentage", "value": 25 } },
{ "equals": { "fieldPath": "ubo.percentage", "value": 25 } }
]
}
isNull / isNotNullβ
Works on: a single value and a list. isNull matches a missing value, a blank text or an empty list;
isNotNull matches the opposite. Use them to check whether a question is answered.
{ "isNull": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS" } }
{ "isNotNull": { "fieldPath": "client.documents[?(@.type == 'BYLAWS')]" } }
isInList / isNotInListβ
Works on: a single value. Checks the data point against a list defined on the organization. listIdentifier
selects the list. listFilterValue is optional:
- With
listFilterValue: the list is treated as a keyβvalue map. The condition matches when the entry keyed by the data point carries a value equal tolistFilterValue. - Without
listFilterValue(blank or omitted): a pure membership check.isInListmatches when the data point exists as an entry (identifier) in the list, regardless of any value stored against it;isNotInListmatches when it does not. Use this for plain membership lists that have no per-entry values. - On a list,
isInListis nevertrueandisNotInListis alwaystrueonce the value is filled in.
{
"isInList": {
"fieldPath": "client.country",
"listIdentifier": "HIGH_RISK_COUNTRIES",
"listFilterValue": "HIGH"
}
}
{
"isNotInList": {
"fieldPath": "party.individual.nationality",
"listIdentifier": "EU_COUNTRIES"
}
}
Choosing an operatorβ
Single value or list?β
The answer type of a question decides how its answer is stored in the data point
(dossier.questions.<QUESTION_ID>, party.questions.<QUESTION_ID>).
| Answer type | Value in the data point | Example value |
|---|---|---|
TEXT, TEXT_AREA, RICH_TEXT, PHONE, AUTOCOMPLETE, COUNTRY, SINGLESELECT, SINGLEDROPDOWN | a single text | "SALARY" |
NUMBER | a single number | 25000 |
DATE | a single date | "2024-12-31" |
BOOLEAN_RADIO, BOOLEAN_TOGGLE, BOOLEAN_CHECKBOX | true or false | true |
MULTIPLESELECT, MULTI_AUTOCOMPLETE, MULTI_COUNTRY | a list of texts, even when only one option is selected | ["SALARY", "SAVINGS"] |
For a select question, compare with the option's stored value (case-sensitive), not its translated label.
Outside questions, a field path that ends on a collection (for example documents) is a list. A wildcard path
that continues after the collection (for example documents[*].type) is different: the operator is evaluated on
the single value of each element, and all elements must match. To check that at least one element
matches, filter the collection and use isNotNull:
{ "isNotNull": { "fieldPath": "documents[?(@.type == 'PASSPORT')]" } }
{ "equals": { "fieldPath": "documents[*].type", "value": "PASSPORT" } }
Which operator for which checkβ
| You want to check thatβ¦ | Single value | List (MULTIPLESELECT, β¦) |
|---|---|---|
| the answer is exactly X | equals | β |
| the answer is X or Y | in | or of two contains |
| the answer includes X | β | contains |
| the answer includes X and Y | β | and of two contains |
| the answer is not X | notEquals | notContains |
| the answer is none of X, Y | notIn | and of two notContains |
| the answer is (not) in an organization list | isInList / isNotInList | β |
| the answer matches a pattern | like / notLike | β |
| the answer is above / below a number or date | greaterThan / smallerThan | β |
| the question is answered | isNotNull | isNotNull |
| the question is not answered | isNull | isNull |
A β means the operator does not work on that kind of value: the condition evaluates, but never gives the
intended result.
Unanswered questionsβ
An unanswered question has no value. Positive operators (equals, in, contains, like, greaterThan,
smallerThan, isInList) then evaluate to false, but negated operators (notEquals, notIn, notContains,
notLike) evaluate to true. isNotInList is the exception: it evaluates to false on an unanswered question.
When a negated operator must not match an unanswered question, guard it with isNotNull:
{
"and": [
{ "isNotNull": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS" } },
{ "notContains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SAVINGS" } }
]
}
Field pathβ
A fieldPath selects a data point by name, using dot notation to descend into nested objects (for example client.individual.maritalStatus). For collection-valued data points, JSON-path style filters and wildcards are supported, for example dossier.client.documents[*].assessment.assessment or documents[?(@.type == 'BYLAWS')].
isNotNullWhen using JSON-path wildcards ([*]) on a collection β for example dossier.client.documents[*].assessment.assessment β always wrap the expression in an and condition whose first clause is an isNotNull check on the parent collection (e.g. dossier.client.additionalTaxInformation).
Without this guard, if the parent collection is null or empty, every operator (in, contains, equals, β¦) that traverses it will evaluate to true instead of false, producing incorrect results.
{
"and": [
{
"isNotNull": {
"fieldPath": "dossier.client.additionalTaxInformation"
}
},
{
"in": {
"fieldPath": "dossier.client.additionalTaxInformation[*].countryCode",
"values": ["IN", "US"]
}
}
]
}
Which paths are valid depends on the data point source bound to the condition by the consuming configuration. Each consumer of the condition decides which source applies. Sources currently in use:
PartyDataPoint(alsoPartyExternalDataPoint)IdentityDataPointDossierDataPoint(alsoDossierExternalDataPoint)DocumentDataPointRbaDataPointUboDataPointRelatedPartyDataPointSignatoryDataPointDueDiligenceSubjectDataPointDueDiligenceProviderInput
The Harmoney UI offers field path autocomplete based on the source of the surrounding configuration, so a condition embedded in a dossier-scoped setting will only show dossier paths, etc.
Examplesβ
{
"and": [
{ "equals": { "fieldPath": "type", "value": "KNOW_YOUR_CUSTOMER" } },
{ "equals": { "fieldPath": "metadata.HIGH_RISK", "value": true } },
{ "notEquals": { "fieldPath": "status", "value": "CLOSED" } }
]
}
{
"and": [
{ "equals": { "fieldPath": "client.partyType", "value": "COMPANY" } },
{ "isNotNull": { "fieldPath": "dossier.documents[?(@.type == 'BYLAWS')]" } }
]
}
{
"and": [
{ "greaterThan": { "fieldPath": "percentage", "value": 25 } },
{ "isInList": {
"fieldPath": "party.individual.nationality",
"listIdentifier": "SANCTIONED_COUNTRIES",
"listFilterValue": "code"
}}
]
}
{
"cards": {
"PAYSLIP": {
"requiredWhen": {
"contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "SALARY" }
}
},
"PROOF_OF_INHERITANCE": {
"requiredWhen": {
"or": [
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "INHERITANCE" } },
{ "contains": { "fieldPath": "dossier.questions.SOURCES_OF_FUNDS", "value": "DONATION" } }
]
}
},
"COMPANY_REGISTRATION": {
"optionalWhen": {
"in": { "fieldPath": "dossier.questions.EMPLOYMENT_STATUS", "values": ["SELF_EMPLOYED", "COMPANY_DIRECTOR"] }
}
}
}
}