EzyStudio ADF

Rule Groups & Logic

Rule Groups & Logic

Rule groups are the primary building blocks of discount configuration. Each rule group defines a set of conditions and a corresponding discount to apply when those conditions are met. Understanding how conditions are evaluated within a rule group — especially the interaction between AND/OR logic and the two condition categories — is essential for building correct discount rules.


Rule Group Structure

Every rule group shares a common set of fields, with additional type-specific fields depending on the function type.

Common Fields

FieldTypeRequiredDescription
idstringYesUnique identifier for the rule group
namestringYesHuman-readable name for the rule group
enabledbooleanYesWhether this rule group is active
prioritynumberYesEvaluation order (lower numbers evaluate first)
conditionLogicstringYesHow conditions combine: "and" or "or"
conditionsarrayYesArray of condition objects

Type-Specific Fields

Depending on the function type, rule groups include additional fields:

  • Conditional: discountValue, target (product, order, or shipping target configuration)
  • Tiered: tiers (array of tier definitions with quantity/spend thresholds and discount values)
  • BXGY: buyConditions, getConditions, discountValue, maxUses (buy X / get Y configuration)
  • Bundle: bundleItems, discountValue (bundle component definitions)

For details on discount values and targets, see the Discount Values & Targets reference.


Condition Logic Deep Dive

The conditionLogic field determines how the conditions array is evaluated. The behavior differs significantly between "and" and "or", particularly when mixing cart-level and product-level conditions.


AND Logic

When conditionLogic is set to "and", all conditions must be satisfied for the rule group to apply.

The evaluation proceeds in two phases:

  1. Cart-level conditions are evaluated first. Every cart-level condition must pass. If any single cart-level condition fails, the entire rule group fails immediately — product-level conditions are never evaluated.

  2. Product-level conditions filter individual lines. Each cart line is tested against all product-level conditions. A line must pass every product-level condition to be eligible for the discount. Lines that fail any product-level condition are excluded.

{
  "conditionLogic": "and",
  "conditions": [
    { "type": "cartSubtotal", "operator": "greaterThan", "value": 100 },
    { "type": "customerTag", "operator": "hasAny", "tags": ["VIP"] },
    { "type": "productTag", "operator": "hasAny", "tags": ["premium"] }
  ]
}

In this example:

  • The cart subtotal must exceed $100 and the customer must have the “VIP” tag (both cart-level conditions must pass).
  • Only lines with the “premium” product tag are eligible for the discount.
  • If the subtotal is $80, the rule fails entirely — no products are discounted regardless of tags.

OR Logic

When conditionLogic is set to "or", the evaluation follows a more nuanced process that depends on whether cart-level conditions pass and whether product-level conditions are present.

The rules for OR logic are:

  1. If any cart-level condition passes, ALL cart lines are eligible for the discount. Product-level conditions are skipped entirely — the passing cart-level condition is sufficient.

  2. If all cart-level conditions fail but product-level conditions exist, each cart line is evaluated against the product-level conditions. A line is eligible if it passes any of the product-level conditions.

  3. If all cart-level conditions fail and no product-level conditions exist, the rule group fails entirely.

This means OR logic creates a “fast path” through cart-level conditions: a single passing cart-level condition makes everything eligible without per-line filtering.


Example: OR with Mixed Conditions

Consider the following rule group:

{
  "conditionLogic": "or",
  "conditions": [
    { "type": "cartSubtotal", "operator": "greaterThan", "value": 200 },
    { "type": "productTag", "operator": "hasAny", "tags": ["premium"] }
  ]
}

Scenario A: Cart subtotal is $250

The cartSubtotal condition passes. Because a cart-level condition passed in OR mode, all lines in the cart are eligible for the discount — even lines without the “premium” tag. The productTag condition is never evaluated.

Scenario B: Cart subtotal is $150, cart contains lines tagged “premium” and “basic”

The cartSubtotal condition fails. Since all cart-level conditions failed but a product-level condition exists, the function evaluates each line individually:

  • Lines tagged “premium” pass the productTag condition and are eligible.
  • Lines tagged “basic” fail and are excluded.

Scenario C: Cart subtotal is $150, no lines have the “premium” tag

The cartSubtotal condition fails. The productTag condition fails for every line. No lines are eligible, and the rule group produces no discount.


Empty Conditions

When the conditions array is empty, the rule group always matches. There are no conditions to fail, so the rule group is treated as unconditionally active.

{
  "id": "rule_always_on",
  "name": "Store-wide discount",
  "enabled": true,
  "priority": 1,
  "conditionLogic": "and",
  "conditions": []
}

This is a valid and common pattern for discounts that should apply universally without any prerequisites, such as store-wide sales or unconditional free shipping.

The conditionLogic value is irrelevant when conditions are empty — both "and" and "or" produce the same result (always match).