Price Types

March 5, 2026 · View on GitHub

Overview

Four price type implementations, each with different calculation strategies.

SinglePrice

Fixed per-unit rate: price × quantity = sum.

Use for: monthly fees, per-item charges, fixed-rate resources.

EnumPrice

Discrete lookup table: maps specific quantity values to specific sums.

Use for: tiered pricing with exact breakpoints, discrete service levels. Throws exception if quantity doesn't match any entry.

RatePrice

Percentage-based calculation.

Use for: referral commissions, rebates, percentage discounts.

ProgressivePrice

Tiered pricing with thresholds and prepaid amounts.

Use for: overage billing (e.g., CDN with 5TB prepaid, then per-GB tiers above).

Algorithm:

  1. Subtract prepaid amount from usage; if remaining <= 0, charge is zero
  2. Build threshold list: configured thresholds + prepaid as the base tier
  3. Sort thresholds by quantity descending
  4. For each tier (highest to lowest):
    • Determine how much usage falls in this tier
    • Multiply tier usage by tier price
    • Subtract billed usage from remaining
  5. Sum all tier charges; uses MultipliedMoney for sub-cent prices

When to Use Which

ScenarioPrice Type
Fixed monthly feeSinglePrice
Per-unit with constant rateSinglePrice
Overage above prepaid quotaProgressivePrice
Commission/referral percentageRatePrice
Exact quantity-to-price mappingEnumPrice

AbstractPrice Rounding Rule

AbstractPrice.calculateSum() applies a minimum charge rule: if usage is nonzero but the calculated sum rounds to zero (via ROUND_HALF_UP), it re-calculates with ROUND_UP to ensure at least 1 cent is charged. This prevents free service for very small but nonzero usage.

Price Interfaces

InterfaceProvidesUsed by
PriceInterfacecalculateSum, calculateUsage, calculatePrice, isApplicableAll prices
PriceWithMoneyInterfacegetPrice(): MoneySinglePrice, ProgressivePrice
PriceWithQuantityInterfacegetPrepaid(): QuantityInterfaceSinglePrice, ProgressivePrice
PriceWithRateInterfacegetRate(): floatRatePrice
PriceWithSumsInterfacegetSums(): SumsEnumPrice
PriceWithThresholdsInterfacegetThresholds(): ProgressivePriceThresholdListProgressivePrice
PriceWithCurrencyInterfacegetCurrency(): CurrencyEnumPrice, via PriceWithMoneyInterface
PriceWithUnitInterfacegetUnit(): UnitInterfaceEnumPrice, via PriceWithQuantityInterface