Calculate Per-User Usage Charges
StripeSoftware Engineer · Online AssessmentLast 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:
- Base Fee: Every user pays a flat monthly fee of
base_price. - Usage Tiers: Usage is billed according to tiers:
- Tier 1: 0 to 100 units = $0.50/unit
- Tier 2: 101+ units = $0.25/unit
- Proration: If a user joins mid-month, the
base_priceis 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.
eventsare not guaranteed to be sorted.user_join_timeis 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?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.