Skip to main content

Rounding

Rounding controls how Quantaprice formats the final price of an item. It is applied only after the full pricing pipeline has completed (VAT, inheritance, bundles, and scheduled updates). The goal is to keep rounding simple, predictable, and suitable for both B2B and B2C use cases.

Quantaprice provides a small set of configurable options that together cover the vast majority of real-world pricing scenarios.


Why Rounding Is Useful

Rounding helps ensure that prices:

  • follow consistent decimal rules across markets and currencies
  • meet compliance requirements
  • use predictable price increments
  • can optionally follow common "charm price" patterns (e.g., .99, .95)
  • avoid unexpected decimal noise from upstream systems

Rounding can be configured using profiles at different levels, giving full flexibility across markets, currencies, or channels.


Rounding Options

Quantaprice uses a tier-based rounding system defined by Rounding Profiles. Each Rounding Profile consists of one or more Rounding Tier Rules. These tier rules specify how prices within certain ranges should be rounded, allowing flexible and precise control over the final price formatting.


Rounding Tier Rules (Amount-Based Rounding)

A Rounding Profile is composed of one or more Rounding Tier Rules. Each tier rule defines the rounding behavior for prices within a specific range and includes the following fields:

  • rangeStart (decimal): The inclusive lower bound of the price range for this tier.
  • direction (enum): The rounding direction to apply. Possible values:
    • Up (round upwards)
    • Down (round downwards)
    • Closest (round to the nearest value)
  • decimals (nullable integer): Number of decimal places to round to. If null, rounding is done based on increment.
  • increment (nullable decimal): The increment to which the price should be rounded (e.g., 0.05). If null, rounding is done based on decimals.
  • offset (decimal): A value to add or subtract after rounding, which can be used to create charm pricing effects ( e.g., -0.01).

This tier-based approach allows complex rounding schemes to be defined in a clear and maintainable way.

Note that there's no property rangeEnd, the range end is implicitly the next greater range start, and if no greater range start exists the current one covers everything greater than rangeStart. The reason for not having a rangeEnd is to ensure there's no gaps.


Rounding Configuration Levels

Rounding rules in Quantaprice are intentionally simple and explicit to avoid silent fallbacks or unexpected behaviour.

A rounding configuration is a coded set of rounding options, now represented as a Rounding Profile containing one or more rounding tiers. Any number of configurations may exist in the system, but only the following attachments are allowed:

  • Zero or one global default rounding configuration
  • Zero or one rounding configuration assigned to each currency (currency default)
  • Any configuration may be selected explicitly on a request using roundingConfig

No implicit inheritance or cross-currency fallback ever occurs.

Configuration Selection Rules

Quantaprice resolves rounding as follows:

When no rounding configuration is specified in the request:

  1. If the requested currency has a default rounding configuration, use it.
  2. Otherwise, if a global default rounding configuration exists, use that.
  3. Otherwise, no rounding is applied.

When a rounding configuration is specified in the request (e.g. roundingConfig = "b2b"):

  1. If a rounding configuration with that exact code exists, use it (even if it's connected to another currency).
  2. Otherwise, if the requested currency has a default rounding configuration, use it.
  3. Otherwise, if a global default exists, use it.
  4. Otherwise, no rounding.

This model ensures:

  • predictable behaviour,
  • no accidental fallbacks across currencies,
  • no dependency on pricelists,
  • no hidden or implicit rounding logic.

Evaluation Order

Rounding is deterministic and always applied in the following order:

  1. Select rounding profile (request → currency default → global default)
  2. Select tier based on raw price (range match)
  3. Apply tier logic in order: rounding via increment or decimals, then apply offset.

This ensures consistent results regardless of how complex the upstream pricing logic is.


Example

Example of a single tier rule producing a charm-like effect:

{
"rangeStart": 0,
"direction": "Down",
"decimals": 2,
"increment": null,
"offset": -0.01
}

This rule rounds prices down to two decimals and then subtracts 0.01, producing prices ending in .99 (e.g., 12.30 → 12.29).