> ## Documentation Index
> Fetch the complete documentation index at: https://docs.slm.m1amdocs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration Method - Decision Rules

Decision rules are a dynamic way to change system behavior without making code changes per merchant. Each decision rule utilizes a predefined object or a defined function.

Decision rules are a a proprietary tool. Decision rules are not visible or accessible to merchants. Merchants provide their input to related features and Vindicia inputs the values as decision rules. Despite this, decision rules are a powerful tool as they allow dynamic behavior per merchant and new rules can be defined using the tools we have in place already.

The rule main syntax is:

an IF condition followed by a THEN answer = value FLAG

The value entered for the decision rule is received and acted on by the Vindicia codebase. A decision rule can contain several condition statements that are evaluated in descending order, from the highest ordinary to the lowest one.

Conditions can use data elements from objects, that are specified by "@" , or from another object that was passed to the decision rule from the caller side.Those are marked by "\_". The table below details the entities that are used for each decision rule and the "\_" data that can be used for each rule.

The FLAG allows additional flexibility, such as an option to mark a label on the IF condition and to define the behavior in a different rule

Example :

IF @.country = "US" THEN :='Do\_US'

IF @.country = 'CA' THEN :='Do\_Canada'

STOP

:Do\_US IF @.district = 'AL' THEN ans="Alabama" IF @.district = 'CA' THEN ans="California" IF 1 THEN STOP

This topic provides explanations of how to define decision rules. In configuration pages appearing later in this book, the required decision rule and functionality is explained not how to write the syntax.

These are the decision rules in use and their respective objects:

| Decision rule type | Role | Utilized on | Example | Comments | | |
| - | - | - | - | - | - | - |
| Sales Taxes There are four types : SalesTax, SalesTax\_Avalara, SalesTax\_AvaBrazil, SalesTax\_Vertex | Used when sending data to the tax interface. For more details see section below | Subscribe | IF \_.caller = 'calculate\_tax' AND \_.addr.country = 'BR' THEN rule = \&#123;"header.entity.federalTaxId" => '12345678987654321',"lines.#.itemCode" => 'D100'\&#125; STOP | "@" uses any taxable class"\_" data is tax vendor dataReturns **rule** = tax vendor hashref | | |
| InvoiceLifeCycle | Used for MAP Subscriptions, to set the invoice lifecycle differently based on different parameters of the subscription | Subscribe | IF (\_.error\_count > 0) and (\_.days\_till\_due \< 1) THEN ans = "SetDelinquent", ans = "CancelAutoBill", ans ="Disentitle", ans = "SendCancellation" STOP | "@" uses **TransactionBilling**"\_" data:**error\_count** is set from **TransactionBilling.dunning\_index** **days\_till\_due** is the days till the invoice is due **template\_exists** whether the current statement template exists **next\_template\_exists** whether the next statement template exists **terms** something to do with **AutoBill.invoice\_terms** Returns **ans** = anything- ISee **TramsactionBilling::process\_statement()** for details. | | |
| RetryInterval | Defines rules for retry in case of a soft failure. There are diferent nuances between Subscribe & Retain, that are described in the relevant chapter | & & Retain | IF \_.transaction\_index =2 THEN 'ans' ='3 days' STOP | - "@" uses **Transaction** - "\_" data: - **transaction\_index** is the **TransactionBilling.soft\_error\_count**. - **billing\_day** is the day of the week (Sun, Mon, etc) for either the TransactionBilling.original\_activity, or the current time. - Returns **ans** = an interval (1 day, 3 weeks) | | |
| [RetryNewProcessor](decisionRulesRetryProviderRouting_r) | Defines rules for routing retry attempts to specific payment providers . **Note:** The payment providers that can be defined, must also be defined in the merchant's Routing Rules using the name\_value\_processor (22) method | Retain & Subscribe | IF \_.prior\_routing = 'CyberSource' THEN pp = (\&#123;'value' => 'CyberSource'\&#125;) STOP THEN pp = (\&#123;'1' => \&#123;'value' => 'Compass'\&#125;, '2' => \&#123;'value' => 'CyberSource'\&#125;\&#125;\&#123;\_.soft\_error\_count\&#125; \\ | \\ | null) STOP THEN pp = null STOP | - \*\*"@"\*\*uses **Transaction** - "\_" data: - **transaction\_index** is the **TransactionBilling.soft\_error\_count** the soft error count is used for the Transaction - this serves as a counter for retry attempts. You can define which attempt to route to a specific provider using this index - **prior\_routing** is the original payment provider **name** to which the Transaction was routed prior to the NVPs added by the decision rule. - **Note:** TransactionBilling::generate\_transaction sets a **NVP** for the selected payment\_provider on the **Tx** which is then used by the name\_value\_processor method routing rules to redirect the transaction retry. |
| RetryOverride | Defines when to "flip" the recurring flag for a transaction | Retain | THEN override = (\&#123;'2' => \&#123;'recurring' => 0\&#125;,'3' => \&#123;'recurring' => 0\&#125;\&#125;\&#123;\_.transaction\_index\&#125; \\ | \\ | null) STOP | "@" uses **Transaction**- "\_" data: - **billing\_attempt** is TransactionBilling.autobill\_sequence - **transaction\_index** depends on where it is called from: - **CashBox\_Utils::deposit\_failed\_authorization()** sets it to TransactionBilling.soft\_error\_count + 1. - **TransactionBilling::set\_retry\_overrides()** sets it to TransactionBilling.soft\_error\_count, or 0 if not defined. - **year\_month** is the current year and month, as YYYYMM - returns **override** = specially formatted string - **CashBox\_Utils::deposit\_failed\_authorization()** only cares if it got back any answer, not what the answer is. - **TransactionBilling::set\_retry\_overrides()** evals some answers, ignores others (see the code for details). |
| ExpiryOverride | In case of expired cards, the system tries to guess possible exoiration dates. Every retry (as setin the rule) will attempt to add a number of years either to today date ot to the card expiration date. The rule is evaluated when a transaction is created. | Subscribe & Retain | THEN ans = (\&#123;'0' => 'BLANK', '1' => 'EXP 1 year','2' => 'EXP 4 year', '3' => 'EXP 3 year', '4' => 'EXP 2 year'\&#125;\&#123;\_.transaction\_index\&#125; \\ | \\ | null) STOP | - "@" uses **Transaction** - "\_" data: - **transaction\_index** is the **TransactionBilling.soft\_error\_count**. Returns **ans** = anything |
| ForcedDeposit | Rule that set the conditions if to force deposit a transaction. The rule is evaluated during post\_processing of a transaction, looks at the auth code response that was received from the payment processor and based on that, flag that the next transaction should be forced. | Subscribe merchants that have ART mode turned on and Retain Merchants | IF @.auth\_response\_code IN ('100','302', '530', '303') THEN ans = 1 | - "@" uses **Transaction** - "\_" data: - **billing\_attempt** is the **TransactionBilling.autobill\_sequence** - **transaction\_index** is the **TransactionBilling.soft\_error\_count** Returns **ans** = anything- Only cares that there is a non-false answer | | |
| WhiteList | Rule that is relevant only if a Forced Deposit. was enabled. Allows to force only on a pre-defined list of BINS | Subscribe merchants that have ART mode turned on and Retain Merchants | IF (@.auth\_response\_code IN ('100','530','302','303')) THEN ans = 1 STOP | - "@" uses **Transaction** - "\_" data: - **billing\_attempt** is the **TransactionBilling.autobill\_sequence** - **transaction\_index** is the **TransactionBilling.soft\_error\_count** | | |
| For more information on how to add decisions rules, see the [Adding Decision rule Vindicia wiki page](https://wiki.corp.aws.vindicia.com/x/lALJAw). | | | | | | |

## Additional Decision Rules, Not as widely used

| Rule | Utilized on | Utilize | Answer |
| - | - | - | - |
| **AuthenticationProvider** | | - "@" uses **Transaction** - "\_" data is not used | Returns **ans** = string of key=val joined by comma- **enable\_3ds**=1 sets Transaction.enable\_3ds to 1, otherwise sets it to 0. - **authentication\_provider**=val sets tx\_detail.authentication\_provide |
| **AutoFight** | Chargeguard | - "@" uses **Chargeback** - "\_" data is not used | Returns **status** = CBDisposition.id- Unimplemented |
| **DivisionNumber** | Subscribe & Retain | - "@" uses **Transaction** - "\_" data is unused | Returns **ans** = anything- Unimplemented |
| **Full Deposit Threshold** | Retain | - "@" uses **Transaction** - "\_" data: - **billing\_attempt** is the **TransactionBilling.autobill\_sequence** - **transaction\_index** is the **TransactionBilling.soft\_error\_count** | - Returns **ans** = anything - Returned verbatim by **Transaction::get\_full\_deposit\_threshold()**. |
| **PartialAuthThreshold** | Retain | - "@" uses **Transaction** - "\_" data: - **billing\_attempt** is the **TransactionBilling.autobill\_sequence** - **transaction\_index** is the \*\*TransactionBilling.\*\***soft\_error\_count** - **otx\_amount** is the **Transaction.amount** or **original\_amount** | - Returns **ans** = anything - The returned answer is the partial auth threshold. |
| **Routing** | Subscribe & Retain | - "@" uses **Transaction** - "\_" data is unused | - Returns **pp = PaymentProvider** - It is used by **Obj::Entity::RoutingRule::get\_payment\_provider\_for\_merchant().** |
| **Whitelist** | | - "@" uses **Transaction** - "\_" data: - **billing\_attempt** is the **TransactionBilling.autobill\_sequence** - **transaction\_index** is the **TransactionBilling.soft\_error\_count** | - Returns **ans** = anything - It is apparently just a true/false flag; returns **true** to check the whitelist. - See **CashBox\_Utils::check\_bin\_whitelist()** for details. |

## Sales Tax Specific Decision rules

| SalesTax | Enables adjusting the fields sent to the tax interface based on the function that is used | Subscribe - will be decomission when all merchants are moving out the sales tax engine | |
| - | - | - | - |
| SalesTax\_Avalara | | Subscribe | |
| SalesTax\_Vertex | Enables adjusting the fields sent to the tax interface based on the function that is invoked | Subscribe | |

Outside tax vendor types have some common features:

* Writing tax vendor rules requires deep knowledge of vendor requests and through testing.
* Their only use is custom modifications of the tax vendor requests fr special cases.
  * DirecTV uses this to convert from our Vertex default version of 7/9 to their version 6.
* Uses any taxable class:
  * **Transaction**
  * **TransactionBilling**
  * **Chargeback**
  * **Refund**
  * **MerchantCustomer** when dealing with exemptions. These are obsolete but the code is still active.
* Data is tax data:
  * **addr** is the possibly-mangled sales tax address.
  * **caller** is a string identifying the calling method:
    * **calculate\_tax**
    * **ping**
    * **post**
    * **void**
    * **"\_item"** will be appended on each line item, as opposed to the entire request. Yes, there can be separate rules for the entire request and for line items.
  * **req** is the specific line item hashref of the request; not the entire request.
* Returned tax data
  * This is a very peculiar hashref. See **SalesTax::merge\_request()** et al for details.

For more information on decision rules syntax, see the [Writing Decision Rules Vindicia wiki page](https://wiki.corp.aws.vindicia.com/x/M4J7)

**Parent topic:**[Configuration Methods](../topics/configurationInterface)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.