Rule support with built-in functions
In the rule file, you can use the following prebuilt functions defined in the RulesUtils.java and CsvCacheHelper.java classes. Rule samples are available in the custom_rules_sample.drl and rules_v1.drl files.
Resolve and Escalate decisions
The functions used in every rule inside the then section to define a fired decision are as follows:
resolve("comment", rulesDecision, score)makes aRESOLVEdecision.escalate("comment", rulesDecision, score)makes aNO_DECISIONdecision.rule "blacklist_country_strong"
activation-group "default"
salience 1700
when
eval (countryMatch.blackListed != null && countryMatch.blackListed == true && StringUtils.isNoneBlank(countryMatch.blackListedStr))
eval (countryMatch.blacklistedSource == BlacklistedSource.COUNTRY)
then
RulesUtils.escalate("Blacklisted country strong. Found \"" + countryMatch.blackListedStr + "\" blacklisted country.", rulesDecision);
end
Field validation
isValidStr(String value)checks if a string value is valid.isValidMap(Map<String, String> valueMap)checks if a map is valid.isHieroglyphsChars(String text)returnstrueif the given string does not contain hieroglyph characters.assertTrue(isHieroglyphsChars("Some test"));
assertTrue(isHieroglyphsChars("eli wool"));
assertTrue(isHieroglyphsChars("Günter"));
assertTrue(isHieroglyphsChars("İbrahim Bıçakçı"));
assertFalse(isHieroglyphsChars("李"));
assertFalse(isHieroglyphsChars("γλύφω"));
assertFalse(isHieroglyphsChars("日本人の氏名"));
assertFalse(isHieroglyphsChars("اسم"));isLatinChars(String text)returnstrueif the given string contains only Latin characters.assertTrue(isLatinChars("Some test"));
assertTrue(isLatinChars("eli wool"));
assertFalse(isLatinChars("Günter"));
assertFalse(isLatinChars("İbrahim Bıçakçı"));
assertFalse(isLatinChars("李"));
assertFalse(isLatinChars("γλύφω"));
assertFalse(isLatinChars("日本人の氏名"));
assertFalse(isLatinChars("اسم"));
Text normalization
String prepareConcatValue(String value)returns text in uppercase, without spaces and punctuation.Assertions.assertEquals("MONKEYONTHETREE", RulesUtils.prepareConcatValue(" Monkey:- on\n the tree"));String prepareValue(String value)returns text in uppercase, with trimmed spaces and no punctuation. Punctuation marks are replaced with spaces.Assertions.assertEquals("MONKEY ON THE TREE", RulesUtils.prepareValue(" {Monkey]:- on\n the, tree!"));
Text manipulation
transliterate(String text)transliterates a given string to Latin characters.Assertions.assertEquals("Some test", transliterate("Some test"));
Assertions.assertEquals("Gunter", transliterate("Günter"));
Assertions.assertEquals("Ibrahim Bıcakcı", transliterate("İbrahim Bıçakçı"));
Assertions.assertEquals("li", transliterate("李"));
Assertions.assertEquals("glypho", transliterate("γλύφω"));
Assertions.assertEquals("ri ben renno shi ming", transliterate("日本人の氏名"));
Assertions.assertEquals("asm", transliterate("اسم"));
Assertions.assertEquals("samy alghamdy", transliterate("سامي الغامدي"));
Assertions.assertEquals("some data\nOOO 'RIH'", transliterate("some data\nООО 'РИХ'"));
Assertions.assertEquals(StringUtils.EMPTY, transliterate(null));
Assertions.assertEquals(StringUtils.EMPTY, transliterate(StringUtils.EMPTY));
Text search
textContainsValue(String text, String value)checks if text contains a value, usingprepareConcatValueas a normalizer.assertFalse(RulesUtils.textContainsValue(" Monkey:- on\n the tree", ""));
assertFalse(RulesUtils.textContainsValue(" Monkey:- on\n the tree", "tree on"));
assertTrue(RulesUtils.textContainsValue(" Monkey:- on\n the tree", "[the tree]"));
assertTrue(RulesUtils.textContainsValue(" Monkey:- on\n the tree", "key"));
assertTrue(RulesUtils.textContainsValue("HBUKGB4BXXX", "GB"));isNameInText(String text, String name, boolean tokensOnly)returnstrueif all name tokens are found in the text. ThetokensOnlyflag is considered when the name is a single token. UsesprepareValueas a normalizer.assertFalse(RulesUtils.isNameInText("", "", true));
assertFalse(RulesUtils.isNameInText("", "", false));
assertFalse(RulesUtils.isNameInText(null, null, true));
assertFalse(RulesUtils.isNameInText(null, null, false));
assertFalse(RulesUtils.isNameInText("MIRANDA INVESTMENT BANK", "IRAN", false));
assertFalse(RulesUtils.isNameInText("IRA,NOVA,TABLE", "IRAN", false));
assertFalse(RulesUtils.isNameInText("WORLD #1, BEST BANK OF IRAN", "IRAN REPUBLIC", false));
assertFalse(RulesUtils.isNameInText("WORLD #1, BEST BANK OF IRAN", "IR", false));
assertFalse(RulesUtils.isNameInText("WORLD #1, BEST BANK OF IRAN", "IRN", false));
assertFalse(RulesUtils.isNameInText("WORLD #1, BEST BANK OF IRAN", "IRN", true));
assertFalse(RulesUtils.isNameInText("Anna \nIranova", "IRAN", true));
assertTrue(RulesUtils.isNameInText("WORLD BANK OF /IRAN", "IRAN", false));
assertTrue(RulesUtils.isNameInText("WORLD BANK IR", "IR", false));
assertTrue(RulesUtils.isNameInText("WORLD BANK IRN", "IRN", false));
assertTrue(RulesUtils.isNameInText("WORLD #1, BEST BANK OF [IRAN]", "IRAN BANK", false));
assertTrue(RulesUtils.isNameInText("WORLD #1, BEST BANK OF IRAN", "best Of Iran", false));
assertTrue(RulesUtils.isNameInText("FIRST IRANIAN BANK", "IRAN", false));
assertTrue(RulesUtils.isNameInText("Anna \nIranova", "IRAN", false));
assertTrue(RulesUtils.isNameInText("WORLD BANK\r\n OF CUBA", "cuba", false));
assertTrue(RulesUtils.isNameInText("best CUBAN cigars", "cuba", false));isNamesInText(String text, List<String> names, boolean tokensOnly)returnstrueif all tokens of any name in the list are found in the text. Each name is processed by theisNameInTextfunction above.hasMultipleTokens(String value)returnstrueif a string has multiple tokens separated by spaces or punctuation.assertTrue(hasMultipleTokens("One two three, four"));
assertFalse(hasMultipleTokens("OnlyOne"));hasNTokens(String value, int n)returnstrueif a string is more than N tokens separated by spaces or punctuation.assertTrue(hasNTokens("One two three, four", 1));
assertFalse(hasNTokens("One two three, four", 6));textMatchRegex(String text, String regex, boolean fullMatch)checks whether the given text fully matches or contains a regular expression pattern, with support for thePattern.DOTALL,Pattern.CASE_INSENSITIVE, andPattern.MULTILINEflags.text = "[TRANSACT ] FREE_FORMAT\n[CURRENCY ] GBP\nSomeValue\nAnother Line";
//Exact match (full string)
assertTrue(RulesUtils.textMatchRegex(text, ".*\\[TRANSACT\\s+\\]\\sFREE_FORMAT.*", true));
//Substring match (find a FREE_FORMAT line)
assertTrue(RulesUtils.textMatchRegex(text, "\\[TRANSACT\\s+\\]\\sFREE_FORMAT", false));
//Match case-insensitively
assertTrue(RulesUtils.textMatchRegex(text, "free_format", false));
//Match with anchors (start of line, multiline)
assertTrue(RulesUtils.textMatchRegex(text, "^SomeValue$", false));
//Match with DOTALL to span across newlines
assertTrue(RulesUtils.textMatchRegex("Start\nMiddle\nEnd", "Start.*End", true));
//Use character classes
assertTrue(RulesUtils.textMatchRegex("Price: $99.99", "\\$\\d+\\.\\d{2}", false));
Name match (token-based)
isNameInclusive(String one, String two, boolean bidirectional)checks if one name token is fully contained within another name token. The boolean parameter controls whether name inclusion works both ways (true). Otherwise (false), it returnstrueif name two is fully contained within name one.assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Peter Goldstein", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Peter Silverman", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Jay Goldstein", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Jay Silverman", true));
assertTrue(isNameInclusive("Silverman-Goldstein, Peter [Jay]", "Goldstein, Peter", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Peter Jay Goldstein", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter' Jay", "Peter Jay Goldstein", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Jay Peter Goldstein", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Peter Jay Silverman", true));
assertTrue(isNameInclusive("Peter Jay Silverman", "Silverman Goldstein, Peter Jay", true));
assertTrue(isNameInclusive("Silverman Goldstein, Peter Jay", "Jay Goldstein", false));
Assertions.assertFalse(isNameInclusive("Silverman Goldstein, Peter Jay", "Peter Jey Silverman", true));
Assertions.assertFalse(isNameInclusive("Peter (Jey) Silverman", "Silverman Goldstein, Peter Jay", true));
Assertions.assertFalse(isNameInclusive("Jay Goldstein", "Silverman Goldstein, Peter Jay", false));isNameAliasInText(String text, List<AliasInfo> aliases)checks if any alias name matches the text, using thetextContainsValuefunction for comparison.// Test when alias names are not found in the text
List<AliasInfo> aliases = Arrays.asList(
new AliasInfo().setName("AliasOne"),
new AliasInfo().setName("AliasTwo")
);
Assertions.assertFalse(RulesUtils.isNameAliasInText("Sample text contains no matches", aliases));
// Test when one of the alias names is found in the text
aliases = Arrays.asList(
new AliasInfo().setName("AliasOne"),
new AliasInfo().setName("MatchThisAlias")
);
Assertions.assertTrue(RulesUtils.isNameAliasInText("Sample text MatchThisAlias found", aliases));
Name match (character-based)
int charsDifferenceDirectional(String one, String two)returns the minimal number of characters from string one that must be removed from (or added to) string two to make the strings equal.Assertions.assertEquals(0, RulesUtils.charsDifferenceDirectional("Max Johnson", "Johnson Max"));
Assertions.assertEquals(2, RulesUtils.charsDifferenceDirectional("Maxim Johnson", "Johnson Max"));
Assertions.assertEquals(3, RulesUtils.charsDifferenceDirectional("Max Johnson", "Xam Jonson"));int charsDifference(String one, String two)returns the minimal number of characters that must be removed from (or added to) the respective strings to make them equal.Assertions.assertEquals(0, RulesUtils.charsDifference("Johnson", "Johnson"));
Assertions.assertEquals(2, RulesUtils.charsDifference("Yohnvson", "Johnson"));
Assertions.assertEquals(7, RulesUtils.charsDifference(null, "Johnson"));
Assertions.assertEquals(7, RulesUtils.charsDifference(StringUtils.EMPTY, "Johnson"));
Assertions.assertEquals(7, RulesUtils.charsDifference("Johnson", StringUtils.SPACE));
Assertions.assertEquals(3, RulesUtils.charsDifference("Max Johnson", "Johnson"));
Assertions.assertEquals(2, RulesUtils.charsDifference("Max Johnson", "Rex Johnson"));
Assertions.assertEquals(2, RulesUtils.charsDifference("Max Johnson", "Xam Johnson"));
Assertions.assertEquals(3, RulesUtils.charsDifference("Max Johnson", "Xam Jonson"));
Assertions.assertEquals(4, RulesUtils.charsDifference("Maxim Johnson", "Xam Jonson"));
Assertions.assertEquals(3, RulesUtils.charsDifference("Maxim Johnson", "Max Jongerson"));
Assertions.assertEquals(0, RulesUtils.charsDifference("Max Johnson", "Johnson Max"));
Assertions.assertEquals(0, RulesUtils.charsDifference("Max Gay Johnson", "Johnson, Max Gay"));
Assertions.assertEquals(0, RulesUtils.charsDifference("Max Gay Johnson", "Johnson, Gay Max"));
Assertions.assertEquals(0, RulesUtils.charsDifference("Max Gay Gay Johnson", "Johnson, Gay Max"));
Assertions.assertEquals(1, RulesUtils.charsDifference("Max Gay Johnson", "Johnson, Gray Max"));
Assertions.assertEquals(3, RulesUtils.charsDifference("Max Gay Gay Johnson", "Johnson, Gray Max"));
Assertions.assertEquals(10, RulesUtils.charsDifference("John Gay, Robin Johnson", "John Robin"));
Date match
minimumDistance(String date1, String date2)calculates the minimum distance between dates represented in two given strings. Each string can contain either a single date value or multiple source dates separated by a pipe (|) delimiter.assertEquals(0L, RulesUtils.minimumDistance("", ""));
assertEquals(0L, RulesUtils.minimumDistance(null, null));
assertEquals(0L, RulesUtils.minimumDistance("34-99", "56|99"));
assertEquals(0L, RulesUtils.minimumDistance("76", null));
assertEquals(0L, RulesUtils.minimumDistance("76", "76|77"));
assertEquals(0L, RulesUtils.minimumDistance("76", "1976|19"));
assertEquals(1, RulesUtils.minimumDistance("01/01/1976", "01/02/1976"));
assertEquals(31, RulesUtils.minimumDistance("01/01/1976", "02/01/1976"));
assertEquals(31, RulesUtils.minimumDistance("01/01/1976", "02/1976"));
assertEquals(31, RulesUtils.minimumDistance("01/01/1976", "1976-02-01"));
assertEquals(31, RulesUtils.minimumDistance("01/01/1976", "1976-02-01| 1977-01-01"));
assertEquals(365, RulesUtils.minimumDistance("01/01/1975", "1976-01-01| 1977-01-01"));
Assertions.assertEquals(356, RulesUtils.minimumDistance("01/01/1975|01/10/1975", "1976-01-01| 1977-01-01")); (v4.0.3)
Maps
mapContainsValue(Map<String, String> messageMap, String key, String value)returnstrueif a map contains a key with the specified value.Assertions.assertFalse(RulesUtils.mapContainsValue(new HashMap<>() {{
put("A", "A");
put("B", "B");
}}, "A", "B"));
assertTrue(RulesUtils.mapContainsValue(new HashMap<>() {{
put("A", "A");
put("B", "B");
}}, "A", "A"));textContainsMapValue(String text, Map<String, String> valueMap)checks if text contains any value from the map.Assertions.assertFalse(RulesUtils.textContainsMapValue("000012345 john Doe 123 street",
new HashMap<>() {{
put("code1", "1256");
put("code2", "00165");
}}));
assertTrue(RulesUtils.textContainsMapValue("000012345 john Doe 123 street",
new HashMap<>() {{
put("code1", "12345");
put("code2", "00165");
}}));
Location in text
isWleLocationInText(String text, PaymentWatchListEntity wle)checks if any sanctioned location elements (name, city, or country) are found in text. This is intended to be used when a sanctioned type isLOCATION.PaymentWatchListEntity wle1 = new PaymentWatchListEntity().setCity("Moscow|Novgorod").setCountry("RU|RUS|Russia").setName("Russian Federation");
PaymentWatchListEntity wle2 = new PaymentWatchListEntity().setCity("Havana").setCountry("CUBA").setName("Havana");
PaymentWatchListEntity wle3 = new PaymentWatchListEntity().setCountry("CUBA").setName("Havana");
PaymentWatchListEntity wle4 = new PaymentWatchListEntity().setName("Russian Federation");
//then
assertTrue(RulesUtils.isWleLocationInText("Moscow investment bank", wle1));
assertTrue(RulesUtils.isWleLocationInText("Russian Federation investment bank", wle1));
assertTrue(RulesUtils.isWleLocationInText("Russian Federation investment bank", wle4));
assertTrue(RulesUtils.isWleLocationInText("Investment Bank RU", wle4));
assertTrue(RulesUtils.isWleLocationInText("Jack Havana", wle3));
Assertions.assertFalse(RulesUtils.isWleLocationInText("Jack Havanan", wle2));
Assertions.assertFalse(RulesUtils.isWleLocationInText("Jack Havanan", wle3));isWleLocationInText(String text, PaymentWatchListEntity wle, boolean searchName)checks whether any sanctioned location elements (name, city, or country) are found in text. WhensearchNameis set tofalse, the function excludes name-based matching, which allows it to be used for any entity type or for searching the entire content for a matching location.PaymentWatchListEntity wle1 = new PaymentWatchListEntity().setCity("Moscow|Novgorod").setCountry("RU|RUS|Russia").setName("Russian Federation");
PaymentWatchListEntity wle2 = new PaymentWatchListEntity().setCity("Havana").setCountry("CUBA").setName("Havana");
PaymentWatchListEntity wle3 = new PaymentWatchListEntity().setCountry("CUBA").setName("Havana");
PaymentWatchListEntity wle4 = new PaymentWatchListEntity().setName("Russian Federation");
assertTrue(RulesUtils.isWleLocationInText("Moscow investment bank", wle1, true));
assertTrue(RulesUtils.isWleLocationInText("Russian Federation investment bank", wle1, true));
assertTrue(RulesUtils.isWleLocationInText("Russian Federation investment bank", wle1, false));
assertTrue(RulesUtils.isWleLocationInText("Russian Federation investment bank", wle4, false));
assertTrue(RulesUtils.isWleLocationInText("Russia investment bank", wle1, true));
assertTrue(RulesUtils.isWleLocationInText("RUS investment bank", wle1, true));
assertTrue(RulesUtils.isWleLocationInText("RU investment bank", wle1, true));
assertTrue(RulesUtils.isWleLocationInText("Novgorod Nafta Invest ", wle1, true));
assertTrue(RulesUtils.isWleLocationInText("BRD TD ACCT CU", wle2, true));
assertTrue(RulesUtils.isWleLocationInText("BRD TD CUBAN ACCT", wle2, true));
assertTrue(RulesUtils.isWleLocationInText("BRD TD ACCT CUB", wle2, true));
assertTrue(RulesUtils.isWleLocationInText("Beautiful Havana City", wle2, true));
Assertions.assertFalse(RulesUtils.isWleLocationInText("RusOilAndGus company", wle1, true));
Assertions.assertFalse(RulesUtils.isWleLocationInText("These rumors were not true ", wle1, true));
Assertions.assertFalse(RulesUtils.isWleLocationInText("Belarusbank", wle1, true));
Assertions.assertFalse(RulesUtils.isWleLocationInText("BRD TD SCUBA ACCT", wle2, true));
Assertions.assertFalse(RulesUtils.isWleLocationInText("Beautiful Havana City", wle3, false));isLocationAnyMatch(String scrCountry, String wleCountry)handles countries that can contain multiple pipe-separated values likeRU|GB.Assertions.assertFalse(RulesUtils.isLocationAnyMatch("", ""));
Assertions.assertFalse(RulesUtils.isLocationAnyMatch(null, null));
Assertions.assertFalse(RulesUtils.isLocationAnyMatch("cuba|iran|russia|TR|USA", null));
Assertions.assertFalse(RulesUtils.isLocationAnyMatch("", "cuba|iran|russia|TR|USA"));
Assertions.assertFalse(RulesUtils.isLocationAnyMatch("cuba|iran|russia|TR", "GB|USA"));
Assertions.assertFalse(RulesUtils.isLocationAnyMatch("russia", "Russian Federation"));
assertTrue(RulesUtils.isLocationAnyMatch("cuba|USA|russia|TR", "GB|USA"));isContentIdMatchesWleCountry(String content, String format, String type, String tags, String wleCountry)searches the message content for known IDs within defined tags and checks for matches with sanctioned countries.String content = "{1:F01CRASGB2LAXXX0000000000}{2:O1030024250909BTAMBSNSAXXX00000000002509090024N}\n" +
":52A:BTAMBSNS\n:57A:HSBCHKHHHKH\n" +
":71A:OUR\n:77B:/ORDERRES/BS/BENEFRES/HK\n-}";
String format = "NATIVE";
String type = "SWF";
String tags = "57A,52A";
assertTrue(RulesUtils.isContentIdMatchesWleCountry(content, format, type, tags, "BS"));
assertTrue(RulesUtils.isContentIdMatchesWleCountry(content, format, type, tags, "HK"));
assertFalse(RulesUtils.isContentIdMatchesWleCountry(content, format, type, tags, "RU"));getCountriesFromText(String text, boolean detectIso2Codes, boolean detectIso3Codes)(available since Tara v4.0.2) searches a given text (location) for possible country references and returns a string of pipe-separated ISO2 codes for the countries found (for example,US|GB). It performs a string-based search and cannot determine whether a token represents an actual country or is part of a person's name or a street name.Assertions.assertEquals("", RulesUtils.getCountriesFromText("", true, true));
Assertions.assertEquals("US", RulesUtils.getCountriesFromText("This is a payment from United States.", true, true));
Assertions.assertEquals("CA|DE|US", RulesUtils.getCountriesFromText("This includes Canada, United States, and also Germany.", true, true));
Assertions.assertEquals("GB|US", RulesUtils.getCountriesFromText("The transaction involves US and GB.", true, true));
Assertions.assertEquals("US", RulesUtils.getCountriesFromText("This includes US and GBR.", true, false));
Assertions.assertEquals("", RulesUtils.getCountriesFromText("There is no valid country here.", true, true));
Assertions.assertEquals("DE|JP", RulesUtils.getCountriesFromText("Transactions from GERmany and jaPan!", true, true));Boolean isTextCountryMatchesWleCountry(String text, boolean detectIso2Codes, boolean detectIso3Codes, String wleCountry)(available since Tara v4.0.2) checks whether a sanctioned country matches any country found in the text and returnsnullif the text does not contain countries; otherwise, returnstrueorfalse.assertNull(isTextCountryMatchesWleCountry("", true, true, "RU"));
assertEquals(Boolean.TRUE, isTextCountryMatchesWleCountry("Payment from Germany via USA to Canada", true, true, "CA"));
assertEquals(Boolean.FALSE, isTextCountryMatchesWleCountry("Payment from Germany via USA to Canada", true, true, "RU|IR"));
assertNull(isTextCountryMatchesWleCountry("This payment is in progress with no issues for us", true, true, "RU"));
Support comparison against CSV file
The functions defined in CsvCacheHelper allow values to be compared against CSV data downloaded from the S3-compatible object storage in the doc-upload bucket under the payment_sanctions_screening/rules/data directory.
These functions support multiple action types to compare strings, numbers, dates, and regular expressions. See the CsvMatchConditionTest.java file for examples.
// String matches
EQUALS,NOT_EQUALS,CONTAINS,NOT_CONTAINS,STARTS_WITH,ENDS_WITH,
FIRST_N_CHARS,LAST_N_CHARS,IS_EMPTY,IS_NOT_EMPTY,IN_LIST,
// Regex
REGEX_MATCH,REGEX_NOT_MATCH,REGEX_CONTAINS,REGEX_NOT_CONTAINS,
// Numeric
EQUALS_NUMERIC,NOT_EQUALS_NUMERIC,GREATER_THAN,LESS_THAN,BETWEEN,
// Date
DATE_EQUALS,DATE_NOT_EQUALS,DATE_BEFORE,DATE_AFTER,DATE_BETWEEN,DATE_WITHIN_DAYS
matchExists(String csvFileName, String factor, Type actionType, String columnName)compares the parameter to each row in the specified CSV column using the provided comparison type.// Sample rule for matching data factors against a set of values defined in a CSV file
// Simplified version of rowMatches() for matching a factor against a large list of values
rule "Example matchExists"
activation-group "default"
salience 1498
when
$hit: PaymentMessageHit()
eval(CsvCacheHelper.matchExists("company_entries.csv", $hit.hitText, CsvMatchCondition.Type.CONTAINS, "Reference Label"))
then
RulesUtils.resolve("Hit matches company_entries.csv", rulesDecision);
endrowMatches(String csvFileName, List<CsvMatchCondition> conditions, MatchMode matchMode)compares the list of conditions to each row in the CSV file. ForMatchMode.ALL, all conditions must match; forMatchMode.ANY, any condition can trigger a match.// Sample rule for matching data factors against a set of values defined in a CSV file
// The company_account_entries.csv file should be placed in the payment_sanctions_screening/rules/data/ S3 directory
// All conditions must match within the same CSV row
rule "CSV data match example"
activation-group "default"
salience 1499
when
$hit: PaymentMessageHit()
$msg: PaymentMessage()
eval($msg.payment != null && $msg.payment.sender != null)
eval(CsvCacheHelper.rowMatches(
"company_account_entries.csv",
Arrays.asList(
new CsvMatchCondition($hit.hitText, CsvMatchCondition.Type.CONTAINS, "Reference Label"),
new CsvMatchCondition($msg.payment.sender.name, CsvMatchCondition.Type.CONTAINS, "Company Name"),
new CsvMatchCondition($msg.payment.sender.accountNumber, CsvMatchCondition.Type.ENDS_WITH, "Account Number")
),
CsvMatchCondition.MatchMode.ALL
))
then
RulesUtils.resolve("CSV data match example", rulesDecision);
end