Agent Wranglers

PRC-12Recommended

Compute tiered and volume prices in one tested function

Store each tiered price with its mode, graduated or volume, and its tiers in minor units. Compute every quote, usage page and invoice line through one function with table tests at each tier edge.

How to do it

The two modes give different totals for the same quantity. Graduated pricing charges each unit at the rate of the tier it falls in, and the tier totals add up. Volume pricing charges every unit at the rate of the tier the total quantity reaches. Take 7 USD for units 1 to 5 and 6.50 USD for units 6 to 10. Six units then cost 41.50 USD graduated and 39 USD volume. Volume pricing can make a larger quantity cheaper than a smaller one, so say which mode applies on the pricing page. Keep the tiers on the price in the versioned catalogue, never in code. Round once per line, in minor units, never per unit. The usage page uses the same function, as Show live usage that matches the invoice requires.

Examples

TypeScript example

type Tier = { upTo: number | null; unitMinor: number; flatMinor?: number }

export function tieredTotalMinor(quantity: number, tiers: Tier[], mode: 'graduated' | 'volume'): number {
  if (mode === 'volume') {
    const tier = tiers.find(t => t.upTo === null || quantity <= t.upTo)!
    return quantity * tier.unitMinor + (tier.flatMinor ?? 0)
  }
  let total = 0
  let previousUpTo = 0
  for (const tier of tiers) {
    const inTier = Math.min(quantity, tier.upTo ?? Infinity) - previousUpTo
    if (inTier <= 0) break
    total += inTier * tier.unitMinor + (tier.flatMinor ?? 0)
    previousUpTo = tier.upTo ?? Infinity
  }
  return total
}

Python example

def tiered_total_minor(quantity: int, tiers: list[dict], mode: str) -> int:
    if mode == "volume":
        tier = next(t for t in tiers if t["up_to"] is None or quantity <= t["up_to"])
        return quantity * tier["unit_minor"] + tier.get("flat_minor", 0)
    total, previous_up_to = 0, 0
    for tier in tiers:
        upper = quantity if tier["up_to"] is None else min(quantity, tier["up_to"])
        in_tier = upper - previous_up_to
        if in_tier <= 0:
            break
        total += in_tier * tier["unit_minor"] + tier.get("flat_minor", 0)
        previous_up_to = upper
    return total

How to check

A table test prices 0, 1, 5, 6, 10, 11 and 25 units in both modes and matches totals worked out by hand. Search the code for a second function that multiplies a quantity by a tier rate. None exists.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/pricing/plans-and-prices/tiered-and-volume-pricing">Agent Wranglers pricing, plans and entitlements playbook</a>. In code you write, add a comment next to it with the same link.