Firing criteria

A condition is a single comparison: a left-hand value, an operator, and a right-hand value. The engine evaluates each condition in the rule, then combines them using the rule’s ConditionsMet setting (All / Any / Custom).

Tested object + tested field

What value does the left-hand side read? The picker offers:

  • Quote — fields on the parent Quote (Quote-mode orgs only).
  • Opportunity — fields on the parent Opportunity (both modes).
  • Account — fields on the deal’s Account.
  • ConfigurationOption — scalar fields on the in-flight configuration draft: TotalPrice, ProductCount, OptionName, PricingModel, Status.
  • Product — any line on the deal carries this product (any-match semantics; fires if at least one product on the cart matches).
  • Bundle Option — any bundle option in the configured tree matches.

Operators

The picklist mirrors the pricing rule operator vocabulary so admins who already author Price Conditions feel at home:

OperatorReads asNumeric?String?Notes
Equalslhs == rhsyesyesCase-insensitive for strings
Not_Equalslhs != rhsyesyes
Greater_Thanlhs > rhsyesSkips if RHS null (see below)
Greater_Or_Equallhs >= rhsyesSkips if RHS null
Less_Thanlhs < rhsyesSkips if RHS null
Less_Or_Equallhs <= rhsyesSkips if RHS null
Is_Nulllhs is nullyesyes
Is_Not_Nulllhs is not nullyesyes
Containslhs contains rhsyesCase-insensitive
Starts_Withlhs begins with rhsyesCase-insensitive
Ends_Withlhs ends with rhsyesCase-insensitive

Value source

What value does the right-hand side read?

  • Literal. Whatever you typed. 20, Enterprise, true. Coerced numerically when both sides parse as numbers.
  • Field Reference. A scope-qualified field path like Account:Discount_Threshold__c. Reads the same context map the LHS uses, so you can compare two fields on the same deal.
  • Variable. A reference to an ApprovalVariable__c by name, written as either ${VarName} or bare VarName. See Approval variables.

Combining conditions

Each rule has a ConditionsMet setting:

  • All. Every condition must pass. Default. Use for AND semantics.
  • Any. At least one must pass. Use for OR semantics.
  • Custom. A boolean expression like (1 AND 2) OR 3, referring to conditions by their 1-indexed position. If the expression is unparseable, the engine falls back to All and logs the fallback in the trace.

Aggregate conditions

A single condition like “discount > 20%” only reads ONE field on ONE record. To answer “how many bundle lines are in roll-up mode?” or “what’s the total margin across all lines?”, switch the condition’s Mode picker from Field to Line Aggregate.

The sub-editor exposes:

  • AggregatorCOUNT / SUM / AVG / MIN / MAX.
  • Aggregator Field — the line-item field the aggregator operates on (ignored for COUNT). Schema-driven picker: filtered to numeric fields when the outer operator is numeric, otherwise unconstrained.
  • Filter Field / Operator / Value — an optional WHERE clause that decides which line items participate. Same operator picklist as field-mode.
  • Outer Operator + Value — compares the aggregate result. Forced to numeric operators because every aggregator returns a number.

Worked examples.

You wantMode = Line Aggregate, set:
Approve if any line has > 20% discountCOUNT(*) where Discount__c Greater_Than 20, outer Greater_Or_Equal 1
Approve if total line value > $250kSUM(TotalPrice), no filter, outer Greater_Than 250000
Approve if average margin under 30%AVG(Margin__c), no filter, outer Less_Than 30
Approve if any bundle is in Roll-Up modeCOUNT(*) where PricingModel Equals Roll-Up, outer Greater_Or_Equal 1
Approve if minimum line margin under 10%MIN(Margin__c), no filter, outer Less_Than 10
Approve if largest single-line price > $50kMAX(TotalPrice), no filter, outer Greater_Than 50000

Empty result sets resolve to 0 for every aggregator (so an empty cart never fires a SUM-over-threshold rule by accident). Non-numeric aggregator fields log a trace note and resolve to 0 as well.

Approval variables

A variable is a named expression you author once. Conditions reference it by name; the engine resolves the expression against the deal at submit time.

When to factor a value out:

  • The same threshold appears in three rules (“$50k” duplicated; if the threshold changes, you’d edit three places).
  • The value lives on the Account, not the Quote — e.g. Account.Discount_Threshold__c — and several rules want it.
  • The math is non-trivial — a formula crossing two objects.

Author variables in Pinion Admin → ApprovalsVariables. Each record has:

  • Name — referenced from conditions as ${Name}.
  • Description — surfaced in the wizard picker so the right one gets chosen.
  • Formula — a dotted field path (e.g. Quote.Account.Discount_Threshold__c) or constant expression.
  • Return TypeNumber / Currency / Percent / Text / Boolean. Drives operator compatibility.

Scope Product

A rule (or a single condition) can be scoped to a product so it only fires when that product is on the deal. This is the difference between “any high-value deal needs CFO” (no scope) and “any deal with our Enterprise SKU needs Product Marketing” (scoped).

The rule’s ScopeProduct__c field is the rule-level scope. When set, the engine pre-filters: if the deal doesn’t carry the product, the rule is skipped before its conditions even evaluate. Bundle parents count — a child line whose ParentBundle__c.Product2Id matches the scope product satisfies the gate. Non-bundle products match on direct Product2Id.

Conditions have their own ScopeProduct__c for per-condition overrides. Inheritance rule: the effective scope is condition.ScopeProduct ?? rule.ScopeProduct — a condition without an override inherits the rule’s, but a condition with its own override replaces (not narrows) the rule’s. Use this when most conditions on a rule share a scope but one condition needs a different product (rare; usually a sign you want two rules).

Worked example. A rule scoped to “Enterprise Tier” with two conditions:

  1. Opportunity.Amount Greater_Than 100000 — no condition scope, inherits “Enterprise Tier” → only fires when Enterprise Tier is on the cart AND amount > $100k.
  2. Product.Quantity Greater_Than 10 — same inheritance. Reads “any Product on this cart whose quantity > 10,” gated to deals carrying Enterprise Tier.

If you instead want condition 2 to scope to “Starter Tier” — same rule, different product — set its ScopeProduct__c to Starter Tier and the rule keeps Enterprise.