Stagehand Wage Ledger With Accrued and Settled Pay
RipplingSoftware Engineer · Technical ScreenLast updated
Design an in-memory class that tracks hourly pay for theater stagehands across logged call times, keeps running cost totals, and settles wages up to a cutoff without ever paying the same minute twice.
A stage crew booking tool pays stagehands by the hour for the time they spend on a "call" (a scheduled work block on a show). Implement a class that tracks this in memory.
Support these operations:
add_worker(worker_id, hourly_rate_usd)registers a stagehand with a USD hourly rate.log_call(worker_id, start_time, end_time)records a completed call as the interval the worker was on the clock.total_cost()returns the total labor cost accrued across every worker and every logged call, whether or not it has been paid.pay_through(cutoff_time)settles wages for all work performed up tocutoff_time. Calling it again with the same or an earlier time must not pay anything twice.unpaid_balance()returns the total wages still owed after the settlements so far.
ledger = StageWageLedger()
ledger.add_worker("crew_7", 42.0)
ledger.log_call("crew_7", 0, 7200) # a 2-hour call -> $84
ledger.total_cost() # 84.0
ledger.pay_through(3600) # settle the first hour -> $42 paid
ledger.unpaid_balance() # 42.0
ledger.pay_through(3600) # no-op, already settled through here
ledger.unpaid_balance() # still 42.0
Constraints and Clarifications
- Timestamps are integers in seconds (e.g. Unix time). A call's cost is the worker's hourly rate times the call's duration in hours.
- A call may be logged after a cutoff has already been applied to that worker, with a start time before the cutoff; only the portion after the cutoff is unpaid.
- A worker may have many overlapping or back-to-back calls; each logged call contributes its own duration independently.
total_cost()andunpaid_balance()may be called far more often than the other two operations.- Everything lives in memory in one process; no persistence or concurrent callers unless you choose to discuss them.
Clarifying Questions
- Should amounts be exact to the cent even after many small calls and settlements?
- If
log_callis given a call that starts before a worker's lastpay_throughcutoff, is the pre-cutoff portion simply ignored, or is that an error? - Is
pay_throughever called with a time before the previous cutoff, and if so, should it truly be a no-op?
Hints
Hint 1
Which of the two getters can be kept as running totals that you update incrementally, instead of rescanning every call on each call?
Hint 2
For pay_through, each call splits into a part before the cutoff and a part after it. Track a per-worker "paid through" timestamp so a repeat or earlier call changes nothing.
Hint 3
An hourly rate times a duration in seconds rarely lands on a whole number of cents. Keep a smaller, exact unit (like micro-cents) internally and only convert to dollars when returning a value.
Hint 4
Decide what happens when a call is logged with a start time already before the worker's paid-through pointer, and make log_call compute the correct already-paid portion for that call on arrival.
Follow-up questions
- How would you support multiple currencies or an hourly rate that changes mid-engagement?
- How would you make pay_through faster than O(calls logged so far), for a ledger with millions of calls?
- What should total_cost() report for a call that has started but has no end_time yet?
- How would this design change if log_call and pay_through could be called concurrently from multiple threads?
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.