Katkat

Calculate Per-User Usage Charges

StripeSoftware Engineer · Online Assessment

Last updated

This problem tests your ability to efficiently process and aggregate time-series usage data while handling complex proration rules and tiered pricing models.

Problem Statement

You are building a billing engine that calculates a user's monthly invoice based on a list of events and a pricing_plan. Each event has a timestamp (integer), type, and quantity.

The billing period is defined from start_time to end_time (exclusive).

Rules:

  1. Base Fee: Every user pays a flat monthly fee of base_price.
  2. Usage Tiers: Usage is billed according to tiers:
    • Tier 1: 0 to 100 units = $0.50/unit
    • Tier 2: 101+ units = $0.25/unit
  3. Proration: If a user joins mid-month, the base_price is prorated based on the fraction of the month they were active (total active time / total month duration). Usage-based charges are not prorated.

Function Signature

def calculate_invoice(events, pricing_plan, start_time, end_time, user_join_time):
    # events: list of dicts {'timestamp': int, 'quantity': int}
    # pricing_plan: dict {'base_price': float}
    # returns: float representing the final bill

Constraints

  • Time is represented as Unix integers.
  • events are not guaranteed to be sorted.
  • user_join_time is within the [start_time, end_time] range.

Example

Input: events = [{'timestamp': 100, 'quantity': 60}, {'timestamp': 200, 'quantity': 60}] pricing_plan = {'base_price': 100.0} start_time = 0, end_time = 400, user_join_time = 200

Calculation:

  • Proration: Active time = (400-200) = 200. Total month = 400. Factor = 200/400 = 0.5. Prorated Base = 100 * 0.5 = 50.0.
  • Usage: Total units = 120. First 100 at 0.5 ($50), remaining 20 at 0.25 ($5) = $55.0.
  • Total: 50.0 + 55.0 = 105.0.

Edge Cases

  • No events recorded during the period.
  • User joins exactly at end_time.
  • Usage exactly at the tier boundary (100 units).

Hints

Hint 1

Sort the events by timestamp to ensure chronological processing if your logic depends on state.

Hint 2

Calculate the total sum of quantities first, as usage pricing is independent of time distribution in this model.

Hint 3

Ensure the proration calculation uses floating-point division to avoid integer truncation errors.

Follow-up questions

  • How would you modify your solution if the usage tiers were reset every 24 hours instead of monthly?
  • What changes are needed if we introduce a 'minimum spend' guarantee where the user pays the maximum of their usage or a fixed amount?
  • How would you optimize the calculation if you had to process millions of users with thousands of events each?