Skip to main content
Rule matching decides which single rate commissions each order line. Mercur finds every enabled rate whose rules fit the line’s product and seller, then keeps the one scoped on the most dimensions. Knowing the algorithm lets you predict a seller’s commission before an order exists. Resolving the rate for a Linen shirt sold by ACME in the Shirts category: four enabled rates match, the acme-shirts rate scopes on two dimensions and wins, lighting does not match, and the default rate ranks last. Resolving the rate for a Linen shirt sold by ACME in the Shirts category: four enabled rates match, the acme-shirts rate scopes on two dimensions and wins, lighting does not match, and the default rate ranks last.

Each dimension checks one product field

A rule compares its reference_id with one field of the line’s product. The product comes from the order line, and the seller comes from the offer the customer bought. Products are a shared catalog that no seller owns, which is why the seller dimension reads the offer on the line and not the product.
The module stores reference as free text and doesn’t validate it. A rule with any other reference, such as a typo, never matches, so the whole rate never matches.

AND across dimensions, OR within one

Mercur groups a rate’s rules by reference. The rate matches a line when every group has at least one rule that matches. Rules in the same group are alternatives, and groups narrow each other.
A rate with these rules matches lines sold by that seller in either category. It doesn’t match the seller’s lines in other categories, or other sellers’ lines in those categories.

The most specific rate wins

When several rates match, Mercur sorts them by specificity and keeps the first. Specificity is the number of distinct dimensions a rate’s rules use, not the number of rules. The rules above give a specificity of 2. Mercur resolves each line in this order:
  1. Drop disabled rates and rates whose currency_code is set to another currency.
  2. Keep the rates that match the line. A rate without rules always matches.
  3. Sort by specificity, highest first.
  4. Break ties by created_at, oldest first.
  5. Apply the first rate to the line’s base amount.
The global rate has no rules, so its specificity is 0 and any matching scoped rate beats it. If no enabled rate matches, the line gets no commission line.
The tie-break also applies between rule-less rates. If you create a second rate without rules, it competes with the global rate at specificity 0, and the older of the two wins.

Shipping uses the global rate only

Shipping methods aren’t matched against rules. If the global rate has include_shipping set, every shipping method on the order gets a line from it, with the description Shipping Commission. Otherwise shipping isn’t commissioned. The global rate’s include_tax flag applies to shipping too, adding the method’s tax_total to its subtotal. For a fixed global rate, each shipping method gets the fixed amount.

Rates load once per batch

The system provider loads all enabled rates with their rules and values in one query per batch of orders. It then resolves every line of every order in memory. Adding rates doesn’t add queries per line.