Need to create rules based on bundles?
Learn more
LogoLogo
APIsChangelog
  • Getting started
  • Rules
  • Conditions
    • Scope
    • Aggregations
    • Nested
    • Dynamic values
  • Actions
    • Types
      • Percentage
      • Fixed amount
      • Fixed price
      • Buy X pay Y
      • Every X discount Y
    • Bundle
      • Balanced
      • Every
    • Aggregation
    • Limit
  • Matchers
  • Operators
  • Check and validation
  • Core API integration
    • Order rules
    • Price rules
    • Virtual relationships
  • Resources
    • Promotions
    • Price lists
  • Use cases
    • Promotions
      • Discount line items based on item's price
      • Get a discount when paying by credit card
      • Discount an order based on promo item and total number of items
      • Offer a specific shipping method for free in a specific country
      • Discount items with large stock availability
      • Discount all the SKU in an order based on the shipping country
      • Discount all the SKU in an order based on the customer email domain
    • Price lists
      • Discount all prices greater than or equal to a specific value
      • Discount specific SKUs for new clients
      • Change strike-through price based on customer email domain
On this page
  • How the balanced algorithm works
  • Example
  • 1. Sorting
  • 2. Total quantity of units
  • 3. Bottleneck
  • 4. Bundles of items to be discounted
  • Wrap-up
  1. Actions
  2. Bundle

Balanced

How balanced bundles work

The default bundling strategy applies the desired action to the targeted items selecting them in order to ensure a balanced and even distribution across groups (i.e. all groups contribute equally to the single promotional bundles that are recursively identified by the algorithm).

Bundles of type balanced can be created starting from at least two groups containing at least one item each. If the related actions.groups array is made by one group only, the Rule Engine will return an error. If one (or more) of the groups are empty, the action won't be applied.

To configure balanced bundles you just need to define the sorting logic within the sort object:

Key
Type
Required
Notes

type

String

If specified, must be "balanced".

sort

Object

How the balanced algorithm works

  1. The items within each targeted group are sorted according to the sort.direction function applied to the sort.attribute numeric field. The groups are also sorted considering the same logic on the same attribute (adding up its value for all the group's items).

  2. The total quantity of units within each group is calculated by adding up the quantities of each item.

  3. The minimum quantity of units across all group Q is the bottleneck of the algorithm (i.e. Q is the number of balanced bundles that will be created).

  4. Starting from the top of the ordered list generated by the sorting, Q elements from each group are picked to be discounted, thus leading to Q discountable balanced bundles containing one item per group each.

If some items of the same group match the bundle's sort.direction function with the same numeric value of the field specified in the sort.attribute, they will be sorted as they are listed in the payload against which the rule is evaluated. If the computation for the total group sorting gives the same result the groups will be sorted in the same order as they are defined in the actions.groups array.

Example

Let's assume that a rule's conditions define the following groups of line items:

The group labeled as t-shirts contains 4 line items for a total of 10 units:

[
  {
    "id": "mnptRLjoXJ",
    "type": "line_items",
    "quantity": 1,
    "unit_amount_cents": 10000,
    "total_amount_cents": 10000,
    "sku": {
      "id": "zTdkkFXdgN",
      "code": "TSHIRT01"
    }
  },
  {
    "id": "jndtDLsoAM",
    "type": "line_items",
    "quantity": 2,
    "unit_amount_cents": 5000,
    "total_amount_cents": 10000,
    "sku": {
      "id": "xCKdTcQFQH",
      "code": "TSHIRT02"
    }
  },
  {
    "id": "AfetSAsqbY",
    "type": "line_items",
    "quantity": 3,
    "unit_amount_cents": 3000,
    "total_amount_cents": 9000,
    "sku": {
      "id": "meKHSeNbyN",
      "code": "TSHIRT03"
    }
  },
  {
    "id": "sjyTdAfrgY",
    "type": "line_items",
    "quantity": 4,
    "unit_amount_cents": 2000,
    "total_amount_cents": 8000,
    "sku": {
      "id": "uKtHCCJpWn",
      "code": "TSHIRT04"
    }
  }
]

The group labeled as polos contains 2 line items for a total of 6 units:

[
  {
    "id": "QqRkzFPjIb",
    "type": "line_items",
    "quantity": 1,
    "unit_amount_cents": 7000,
    "total_amount_cents": 7000,
    "sku": {
      "id": "cZuCQqLaqd",
      "code": "POLO01"
    }
  },
  {
    "id": "PSqqslbiYQ",
    "type": "line_items",
    "quantity": 5,
    "unit_amount_cents": 6000,
    "total_amount_cents": 30000,
    "sku": {
      "id": "GjvdHKYIwm",
      "code": "POLO02"
    }
  }
]

The group labeled as mugs contains 3 line items for a total of 5 units:

[
  {
    "id": "qOYocnANsO",
    "type": "line_items",
    "quantity": 3,
    "unit_amount_cents": 1000,
    "total_amount_cents": 3000,
    "sku": {
      "id": "PeHfayCvwQ",
      "code": "MUG01"
    }
  },
  {
    "id": "nlHjpkVpCG",
    "type": "line_items",
    "quantity": 1,
    "unit_amount_cents": 4000,
    "total_amount_cents": 4000,
    "sku": {
      "id": "pHaoUAvTVy",
      "code": "MUG02"
    }
  },
  {
    "id": "DtZjSMEKvm",
    "type": "line_items",
    "quantity": 1,
    "unit_amount_cents": 3000,
    "total_amount_cents": 3000,
    "sku": {
      "id": "TkhHRotCOA",
      "code": "MUG03"
    }
  }
]

Let's consider a simple action that uses only the required parameters to be applied to a set of balanced bundles. The following action applies a 20% discount to all the possible bundles that can be created from the groups above, provided that they contain at least one item per group, prioritizing the items with the higher total amount:

"actions": [
  {
    "type": "percentage",
    "selector": "order.line_items.sku",
    "groups": [ "mugs", "polos", "t-shirts" ],
    "bundle": {
      "sort": {
        "attribute": "total_amount_cents",
        "direction": "desc"
      }
    },
    "value": 0.2
  }
]

1. Sorting

The items of the group are sorted based on their total amount, from the highest to the lowest. On top of that, the groups are sorted based on the sum of the total amount of each group's item, according to the same logic:

SKU
Group
Quantity
Item total amount
Group total amount

POLO02

polos
5

30000

37000

POLO01

polos
1

7000

37000

TSHIRT01

t-shirts
1

10000

37000

TSHIRT02

t-shirts
2

10000

37000

TSHIRT03

t-shirts
3

9000

37000

TSHIRT04

t-shirts
4

8000

37000

MUG02

mugs
1

4000

10000

MUG01

mugs
3

3000

10000

MUG03

mugs
1

3000

10000

TSHIRT01 ranks higher than TSHIRT02 within the t-shirts group even if they have the same total amount (10000) because this is how they are listed in the payload. The same happens to MUG01 and MUG03 within the mugs group. The elements of the polos groups rank higher than the elements of the t-shirts group even if the two groups have the same total amount (37000) because this is how they are listed in the actions.groups array.

2. Total quantity of units

The total quantity of units within each group is:

Group
Units
mugs
5
polos
6
t-shirts
10

3. Bottleneck

The group with the lowest total number of units limits the number of bundles that will be created. In this case the mugs group is the bottleneck, thus the discount will be applied to 5 bundles.

4. Bundles of items to be discounted

SKU
Group
Quantity
Discounted total amount

POLO02

polos
5

24000

TSHIRT01

t-shirts
1

8000

TSHIRT02

t-shirts
2

8000

TSHIRT03

t-shirts
2

4800

MUG02

mugs
1

3200

MUG01

mugs
3

2400

MUG03

mugs
1

2400

Bundle #1

SKU
Group
Quantity
Discounted unit amount

POLO02

polos
1

4800

TSHIRT01

t-shirts
1

8000

MUG02

mugs
1

3200

Bundle #2

SKU
Group
Quantity
Discounted unit amount

POLO02

polos
1

4800

TSHIRT02

t-shirts
1

4000

MUG01

mugs
1

800

Bundle #3

SKU
Group
Quantity
Discounted unit amount

POLO02

polos
1

4800

TSHIRT02

t-shirts
1

4000

MUG01

mugs
1

800

Bundle #4

SKU
Group
Quantity
Discounted unit amount

POLO02

polos
1

4800

TSHIRT03

t-shirts
1

2400

MUG01

mugs
1

800

Bundle #5

SKU
Group
Quantity
Discounted unit amount

POLO02

polos
1

4800

TSHIRT03

t-shirts
1

2400

MUG03

mugs
1

2400

Wrap-up

The results above confirm some general highlights of the balanced bundling strategy:

  • An equal contribution of each group to the bundle formation is the distinctive feature. It's a quite strict requirement that leaves some items not discounted (in the analyzed case, 1 unit of POLO01, 1 unit of TSHIRT03, and 4 units of TSHIRT04), prioritizing the ones to discount based on the desired sorting logic.

  • Only the elements of the group(s) with the minimum number of total units will be all discounted, and the total number of bundles identified will be equal to the number of total units of the group(s) that with minimum number of total units (in the analyzed case, the mugs group which has a total number of units equal to 5 and turns out to be the bottleneck of the algorithm).

  • The total number of discounted units is given by the number of total units of the group with the minimum number of total units multiplied by the total number of groups (in the analyzed case, 5 * 3 = 15).

PreviousBundleNextEvery

Last updated 2 months ago

Learn more .

We can now pick 5 elements from each group, following the from top to bottom:

This is equivalent to picking one item per group while mugs units (our ) last, thus leading to the following 5 bundles to be discounted:

ordered list
bottleneck
here