Applying Per-Unit Conservation Surcharges in Python

A conservation surcharge is a deceptively simple line item: a few cents per kilowatt-hour or per thousand gallons (kgal) that a utility levies on consumption above a policy threshold, designed to discourage waste during a drought or a peak-demand season. The arithmetic looks trivial until three questions collide — does the surcharge apply to the whole volume or only the units above the threshold, what happens exactly at the threshold, and does it get taxed? Each answer changes the ratepayer’s total, and getting any of them wrong produces a bill that no ordinance authorizes. This page sits under surcharge and fee application logic, part of the broader automated rate calculation and rule engines subsystem, and shows how to compute a per-unit conservation surcharge deterministically with decimal.Decimal, layer it cleanly on the base commodity charge, and apply it in the correct order relative to utility tax.

Minimal Prerequisites

  • Python 3.11+ — for the X | None union syntax and modern typing used below; no third-party runtime dependency is required for the core calculation.
  • decimal.Decimal for every quantity — usage volume, threshold, per-unit rate, and money all stay in Decimal. A per-unit rate like 0.0032 per gallon multiplied by a large volume is exactly the kind of value where binary float drift crosses a cent.
  • A single, explicit rounding boundary — the surcharge is quantized to the cent once, with ROUND_HALF_UP, and never re-rounded.
  • Pydantic v2 (pydantic>=2.6) is assumed upstream for validating the surcharge definition, but the function here takes already-typed Decimal inputs so it can be unit-tested in isolation.

Data assumptions: the base commodity charge for the account has already been rated (this page decorates it, it does not recompute it), metered usage is a clean non-negative Decimal in the same unit as the threshold (kWh or kgal), and the per-unit surcharge rate and threshold come from an authoritative, version-controlled rule record with a governing PUC reference. The one design decision you must fix before writing a line of code is whether the surcharge is marginal — applied only to units above the threshold — or whole-volume — applied to every unit once any threshold is crossed. Marginal is by far the more common and more defensible conservation design, so it is the default here, with the whole-volume variant shown explicitly as an edge case.

Annotated Implementation

The whole computation is one pure function. It takes usage, a threshold, a per-unit surcharge rate, and the already-rated base cost, and returns a small breakdown so the caller can post each component to the ledger separately. Keeping it pure — no I/O, no clock, no global state — is what makes it deterministically replayable during an audit.

from __future__ import annotations

from dataclasses import dataclass
from decimal import Decimal, ROUND_HALF_UP

CENTS = Decimal("0.01")


def _money(value: Decimal) -> Decimal:
    # Quantize to the cent exactly once, at the boundary, with an explicit mode.
    return value.quantize(CENTS, rounding=ROUND_HALF_UP)


@dataclass(frozen=True)
class SurchargeResult:
    billable_units: Decimal      # units the surcharge actually applied to
    surcharge: Decimal           # the conservation surcharge, quantized to cents
    subtotal: Decimal            # base commodity charge + surcharge, pre-tax
    tax: Decimal                 # utility tax, computed on the subtotal
    total: Decimal               # amount due


def apply_conservation_surcharge(
    usage: Decimal,              # metered consumption, kWh or kgal
    threshold: Decimal,          # units below this are exempt from the surcharge
    per_unit_rate: Decimal,      # surcharge charged per unit above the threshold
    base_cost: Decimal,          # base commodity charge, already rated (Decimal)
    tax_rate: Decimal,           # utility tax as a fraction, e.g. Decimal("0.045")
) -> SurchargeResult:
    """Apply a marginal per-unit conservation surcharge, then tax the subtotal."""
    if usage < 0 or threshold < 0 or per_unit_rate < 0:
        raise ValueError("usage, threshold, and rate must be non-negative")

    # Marginal design: only the slice of usage ABOVE the threshold is surcharged.
    # max(...) clamps at zero so usage at or below the threshold yields no charge.
    billable_units = max(Decimal("0"), usage - threshold)

    # Full-precision multiply first; quantize the surcharge ONCE, here.
    surcharge = _money(billable_units * per_unit_rate)

    # The surcharge is layered on the base commodity charge to form the subtotal.
    subtotal = _money(base_cost + surcharge)

    # Tax is applied to the subtotal LAST, so it captures the surcharge too.
    tax = _money(subtotal * tax_rate)
    total = _money(subtotal + tax)

    return SurchargeResult(
        billable_units=billable_units,
        surcharge=surcharge,
        subtotal=subtotal,
        tax=tax,
        total=total,
    )

Two ordering decisions carry all the billing weight. First, billable_units is computed as usage - threshold clamped at zero, so a customer who stayed under the conservation threshold pays nothing extra and the account exactly at the threshold pays nothing extra either — the surcharge begins on the first unit past the line, not at it. Second, the surcharge is folded into the subtotal before tax is computed, so the utility tax lands on the base charge plus the surcharge together. Reversing that order — taxing the base, then adding an untaxed surcharge — understates the tax the ordinance requires and is one of the most common quiet errors in a conservation-fee rollout. The single-quantization discipline mirrors the marginal-slice approach used across surcharge and fee application logic: multiply at full precision, round once at the money boundary.

How a marginal per-unit conservation surcharge is computed and taxed A usage bar runs from zero to total metered usage with a threshold mark part way along. Units from zero to the threshold carry the base rate only; units from the threshold up to total usage carry the base rate plus the per-unit conservation surcharge, so the surcharge applies to the marginal slice alone. Below, two inputs — the base commodity charge and the conservation surcharge equal to units above threshold times the per-unit rate — merge into a pre-tax subtotal, and the utility tax is then applied to that subtotal last to produce the invoice total. surcharge applies to this slice only 0 → threshold base rate only threshold → usage base rate + per-unit surcharge 0 threshold usage Base commodity charge already rated Conservation surcharge (usage − threshold) × rate Subtotal base + surcharge Utility tax LAST tax × subtotal → total applied after

Edge Cases and Billing Gotchas

Conservation surcharges break in specific, threshold-shaped ways. These are the boundary conditions a naive implementation charges wrong.

  • Usage exactly at the threshold. With max(Decimal("0"), usage - threshold), an account that lands precisely on the threshold has zero billable units and pays no surcharge — the fee begins on the first unit above the line. Decide this deliberately and document it against the ordinance; some conservation programs instead specify the surcharge begins at the threshold, in which case the comparison must change. Because everything is Decimal, a usage of Decimal("500.00") against a Decimal("500") threshold compares exactly, with none of the 499.9999 drift a float would introduce.
  • Marginal vs. whole-volume surcharge. The function surcharges only the slice above the threshold. Some drought ordinances instead surcharge every unit once any usage crosses the threshold. That is a different rule: billable_units = usage if usage > threshold else Decimal("0"). Whole-volume is punitive by design and far more sensitive to a reading error near the threshold, so confirm which the ordinance mandates before shipping — the two produce very different bills for a customer just over the line.
  • Tiered conservation surcharge. Some programs escalate the per-unit rate in bands — for example a lower rate for the first block above the threshold and a steeper rate beyond it. That is the marginal-slice model applied to the surcharge itself; reuse the band-slicing approach from step-rate versus block-rate structure design rather than a single per_unit_rate, and quantize only after summing every band’s contribution.
  • Rounding order relative to tax. Quantize the surcharge once, fold it into the subtotal, then tax the subtotal. Taxing the base charge and the surcharge separately and summing invites a double-rounding discrepancy of a cent; taxing before the surcharge is added under-collects tax the statute requires. The order in the code — surcharge, subtotal, then tax — is the auditable one.
  • Partial-month conservation windows. A drought surcharge that begins mid-cycle applies only to usage inside the effective window, which requires point-in-time rule resolution rather than a flat per-cycle threshold; the seasonal-window mechanics live in surcharge and fee application logic, and time-based fee proration is covered separately under proration and billing period calculation.

Verification Snippet

Test the boundaries that matter: below, exactly at, and above the threshold, plus the tax-ordering invariant. Every expected figure is a literal Decimal so the assertions catch drift the moment it appears.

from decimal import Decimal


def test_conservation_surcharge_boundaries() -> None:
    threshold = Decimal("500")           # kgal
    rate = Decimal("0.0032")             # surcharge per gallon above threshold
    base = Decimal("42.00")              # already-rated base commodity charge
    tax_rate = Decimal("0.045")          # 4.5% utility tax

    # Below threshold: no surcharge, tax on base only.
    under = apply_conservation_surcharge(Decimal("450"), threshold, rate, base, tax_rate)
    assert under.billable_units == Decimal("0")
    assert under.surcharge == Decimal("0.00")
    assert under.total == Decimal("43.89")            # 42.00 + (42.00 * 0.045)

    # Exactly at threshold: still no surcharge (fee starts on the next unit).
    at = apply_conservation_surcharge(Decimal("500"), threshold, rate, base, tax_rate)
    assert at.surcharge == Decimal("0.00")

    # Above threshold: surcharge on the marginal 300 units, taxed with the base.
    over = apply_conservation_surcharge(Decimal("800"), threshold, rate, base, tax_rate)
    assert over.billable_units == Decimal("300")
    assert over.surcharge == Decimal("0.96")          # 300 * 0.0032 = 0.96
    assert over.subtotal == Decimal("42.96")          # base + surcharge
    assert over.tax == Decimal("1.93")                # 42.96 * 0.045, half-up
    assert over.total == Decimal("44.89")

    # Ordering invariant: tax is computed on the surcharge-inclusive subtotal.
    assert over.tax == (over.subtotal * tax_rate).quantize(Decimal("0.01"))

Running these against fixtures drawn from real reconciled bills — not only synthetic numbers — is what surfaces the off-by-a-cent tax cases and the “just over the threshold” disputes before a cycle posts. An account whose stored total no longer matches a fresh recomputation points to a rule change that was applied in place instead of versioned.

FAQ

Does the surcharge apply to all usage or only the units above the threshold?
By default here it is marginal: only the slice of usage above the threshold is surcharged, computed as max(0, usage minus threshold) times the per-unit rate. That is the most common conservation design because it preserves a clean incentive — a customer pays the surcharge only on the excess. Some ordinances instead specify a whole-volume surcharge that applies to every unit once the threshold is crossed; that is a different rule and must be coded explicitly, because it produces a much larger jump for a customer just over the line.
Should the surcharge be taxed?
In most jurisdictions the utility tax applies to the whole billed amount, so the surcharge is folded into the pre-tax subtotal and the tax is computed on that combined figure. The function does exactly this: it adds the surcharge to the base charge first, quantizes the subtotal, then applies the tax rate to the subtotal last. Taxing the base and surcharge separately risks a double-rounding cent, and taxing before the surcharge is added under-collects. Confirm the taxability against the governing statute, but tax-last on the combined subtotal is the safe default.
What happens when usage is exactly at the threshold?
The account pays no surcharge. Because billable units are max(0, usage minus threshold), a usage equal to the threshold yields zero billable units, so the fee begins on the first unit past the line. Decimal makes this comparison exact — a usage of Decimal("500.00") against a Decimal("500") threshold matches cleanly, with no float drift to push it fractionally over or under. If the ordinance instead intends the surcharge to begin at the threshold, change the comparison and document the choice.
Why use Decimal for the per-unit rate and usage?
A per-unit conservation rate is often a small fraction of a cent — for example 0.0032 per gallon — multiplied by a large volume. In binary float those values cannot be represented exactly, and the tiny errors accumulate until a total lands a cent off, which reconciliation cannot explain. Decimal stores base-ten values exactly, and quantizing the surcharge once with ROUND_HALF_UP guarantees a reproducible, auditable figure that matches what the ordinance predicts.
How do I handle a drought surcharge that only runs part of the billing cycle?
A surcharge with an effective window applies only to usage inside that window, which is a point-in-time resolution problem rather than a flat per-cycle threshold. Version the surcharge rule by its effective date, split the consumption at the window boundary, and apply the per-unit surcharge only to the in-window slice. The seasonal-window resolution mechanics live in the parent surcharge and fee guide, and general time-based fee proration is covered under proration and billing period calculation.

Up: Surcharge & Fee Application Logic · Automated Rate Calculation & Rule Engines