Relative pricing tiers
A pricing tier is a named price list, and every product can carry a different price in each tier. Most tiers are absolute — you type each product's price in by hand. A relative tier is different: it doesn't store hand-entered prices. Instead it stores a formula, and SKU computes each product's price in that tier by applying the formula to a source value. Change the source and the relative price recomputes on its own.
This page explains the model behind relative tiers: the three things a formula can derive from, how the arithmetic works, and how a change in one place ripples out to every tier that depends on it. For the hands-on task of creating tiers and setting the default, see Manage pricing tiers. For every field and guard, see the Pricing tier fields & guards reference.
The three derivation bases
Every relative tier has a basis — the kind of source its formula reads from. There are three:
| Basis | Reads from | Formula shape |
|---|---|---|
| Pricing Tier | Another product pricing tier's price for the same product | percentage markup of the base tier's price |
| Supplier Tier | The product's preferred supplier cost in a supplier pricing tier (cost-plus) | percentage markup of the supplier cost |
| Attribute | A numeric product attribute value (for example weight or length) | value × rate + offset |
The basis determines what a tier watches, and therefore what makes it recompute. A Pricing Tier basis watches another tier's price. A Supplier Tier basis watches the preferred supplier cost. An Attribute basis watches an attribute value on the product. See Manage a product's suppliers for how preferred supplier cost is set, and Set a product's categories & attributes for numeric attributes.
Legacy tiers default to the Pricing Tier basis
The Pricing Tier basis is the original relative-tier behavior. Relative tiers created before the other two bases existed have no stored basis value; SKU treats any such tier as a Pricing Tier basis. You never need to backfill them — a null basis and an explicit Pricing Tier basis behave identically.
Chain depth and cycles
Pricing-Tier-basis tiers can stack: tier C can derive from tier B, which derives from an absolute tier A. SKU caps this chain depth at 3 levels and rejects any base selection that would point a tier back at itself, directly or through the chain (a circular reference). A relative tier also inherits its currency from the source it derives from, so you can't mix currencies within a chain.
The formula
Whatever the basis, the formula runs the source value through the same three-step tail: a per-basis starting calculation, then rounding, then a fixed adjustment, floored at zero.
Step 1 — starting calculation depends on the basis:
- Pricing Tier and Supplier Tier bases apply a percentage:
source × (1 + adjustment_percentage / 100). A20percentage marks the source up by 20%; a-10marks it down by 10%. The adjustment percentage is required for these two bases. - Attribute basis applies a linear rate:
attribute_value × attr_rate + attr_offset. The rate (attr_rate) is required; the offset (attr_offset) is optional and defaults to0.
Step 2 — rounding. If a rounding value is set, the running total is rounded to the nearest multiple of it — a rounding value of 0.05 snaps to the nearest 5 cents, 1.00 to the nearest whole unit. If no rounding value is set, the total is simply rounded to 2 decimal places.
Step 3 — fixed adjustment and floor. A fixed amount (adjustment_fixed_amount, may be positive or negative) is added last, after rounding — so it lands exactly on the price and isn't itself snapped to the rounding multiple. The result is rounded to 4 decimal places for storage and then floored with max(result, 0), so a large negative fixed amount can never produce a negative price.
The ordering matters: percentage first, then round, then the flat amount. A common pattern is a percentage markup, a rounding value of 1.00 to land on whole units, and a -0.01 fixed amount to produce charm prices like $29.99.
How changes propagate
Because relative prices are computed, not typed, SKU has to recompute them whenever a source changes. That recomputation is asynchronous — it runs in a background job (PropagateRelativePricesJob) so a single edit never blocks on recalculating thousands of products. Recomputation walks affected products in chunks of 500.
Downstream: A source price changes
When you set a product's price in a tier, SKU saves it and then — only if that tier has dependent tiers — dispatches a propagation job for that one product. The job recomputes the product's price in each Pricing-Tier-basis dependent, then recurses down the chain to their dependents.
Only Pricing Tier basis dependents recompute from a parent tier's price. Supplier-Tier and Attribute basis tiers are deliberately skipped here: they don't read from another tier's price, so a tier-price change is irrelevant to them. They recompute from their own sources instead (see below).
Upstream: A supplier cost or attribute value changes
Two other kinds of change feed relative tiers from the other direction:
- Supplier cost change. When a product's preferred supplier cost changes in a supplier tier, SKU recomputes every Supplier-Tier basis product tier that reads from that supplier tier for that product. A tier with no explicit supplier tier falls back to the default supplier tier, so cost changes on the default supplier tier reach those fallback tiers too.
- Attribute value change. When a numeric attribute value changes on a product, SKU recomputes every Attribute basis tier that reads from that attribute, for that product.
Editing the tier's own formula
Editing a relative tier — not a product price, the tier itself — also triggers recomputation, and changing its type changes prices in bulk:
- Absolute → relative. SKU deletes the tier's hand-entered prices (they no longer make sense) and recomputes every product's price from the new formula.
- Relative → absolute. SKU clears all the relative fields (basis, base references, rate, offset, percentage, fixed amount, rounding). Existing computed prices remain as the tier's now-absolute prices until you edit them.
- Formula edit on a relative tier. Changing the basis, a base reference, the rate, offset, percentage, fixed amount, or rounding value re-propagates the whole tier so every product's computed price reflects the new formula.
The propagation guard
Propagation writes prices, and those writes could in turn trigger more propagation. To prevent an infinite loop, the recompute writes are flagged as "already propagating," which suppresses re-dispatch during a run. Combined with the chain-depth cap and the circular-reference check, this keeps a single source change to one bounded pass down the dependency tree.
Next steps
- Manage pricing tiers — create tiers, set the default, archive and import/export.
- Set a product's price — enter a price in a tier and see propagation kick off.
- Pricing tier fields & guards reference — every field, default, and validation rule.
- Manage a product's suppliers — where preferred supplier cost comes from.