wherecontains(): match a payment file to open invoices
Hard
Each morning the bank sends a payment file: one line per payment, holding the invoice number that was paid.
Match it against the open invoices, which are records with a number and an amount. A line the bank could not read arrives as null.
Return a record with three fields
stillOpen: the invoices that were not paid, as records, in their original orderunknown: payment numbers that match no open invoice, in file order, each time they appearunreadable: how many lines were null
Watch out
- An invoice paid twice is simply paid.
wherecontains()returns positions in the list being searched, so the argument order decides which list those positions belong to.- Unlike a comparison, it can also find nulls.
Tip: the invoice numbers are needed more than once. a!localVariables() lets you name them; repeating the expression works too.
Inputs
ri!invoices: List of Mapri!paidNumbers: List of Text
ri! Rule Inputs
ri!invoicesList of Map{
a!map(number: "INV-1", amount: 100),
a!map(number: "INV-2", amount: 250),
a!map(number: "INV-3", amount: 75)
}ri!paidNumbersList of Text{
"INV-2",
"INV-9",
null,
"INV-2"
}Example 1: A typical morning
Input: ri!invoices
{
a!map(number: "INV-1", amount: 100),
a!map(number: "INV-2", amount: 250),
a!map(number: "INV-3", amount: 75)
}Input: ri!paidNumbers
{
"INV-2",
"INV-9",
null,
"INV-2"
}Output:
a!map(stillOpen: {a!map(number: "INV-1", amount: 100), a!map(number: "INV-3", amount: 75)}, unknown: {"INV-9"}, unreadable: 1)Example 2: Everything paid, in another order
Input: ri!invoices
{
a!map(number: "INV-1", amount: 100),
a!map(number: "INV-2", amount: 250),
a!map(number: "INV-3", amount: 75)
}Input: ri!paidNumbers
{
"INV-3",
"INV-1",
"INV-2"
}Output:
a!map(stillOpen: {}, unknown: {}, unreadable: 0)Example 3: Only unreadable lines
Input: ri!invoices
{
a!map(number: "INV-1", amount: 100),
a!map(number: "INV-2", amount: 250),
a!map(number: "INV-3", amount: 75)
}Input: ri!paidNumbers
{
null,
null
}Output:
a!map(stillOpen: {a!map(number: "INV-1", amount: 100), a!map(number: "INV-2", amount: 250), a!map(number: "INV-3", amount: 75)}, unknown: {}, unreadable: 2)Example 4: An unknown number twice
Input: ri!invoices
{
a!map(number: "INV-1", amount: 100),
a!map(number: "INV-2", amount: 250),
a!map(number: "INV-3", amount: 75)
}Input: ri!paidNumbers
{
"INV-7",
"INV-1",
"INV-7"
}Output:
a!map(stillOpen: {a!map(number: "INV-2", amount: 250), a!map(number: "INV-3", amount: 75)}, unknown: {"INV-7", "INV-7"}, unreadable: 0)Example 5: An empty file
Input: ri!invoices
{
a!map(number: "INV-1", amount: 100),
a!map(number: "INV-2", amount: 250),
a!map(number: "INV-3", amount: 75)
}Input: ri!paidNumbers
{}Output:
a!map(stillOpen: {a!map(number: "INV-1", amount: 100), a!map(number: "INV-2", amount: 250), a!map(number: "INV-3", amount: 75)}, unknown: {}, unreadable: 0)Appian Expression Tips
- • Use
ri!variableNamefor rule inputs - • Use
a!localVariables(local!x: …, body)for locals - • Use
a!forEach(items: …, expression: fv!item)to iterate - • Use
where()/reject(fn!isnull, list)to filter