97. Design Dasher Payout Service

Design Dasher Payout Service
Design and implement a Dasher payout service as part of a new Payments Service in a micro-service architecture. The service must expose a payout API that calculates how much a Dasher should be paid for a given day.

Overview

  • Calculate total payout based on time spent fulfilling orders.
  • Handle overlapping deliveries correctly.

Payment Rules

  • Multi-order pay rate: ongoingDeliveries * basePayRate
  • An order contributes pay only for the minutes between its start time and end time.
  • If multiple orders overlap, payout during the overlap must increase proportionally to the number of ongoing deliveries.

Delivery Activity Data Format

This problem should use List<String>, each activity record is represented as a string in the format:

  • orderId=<id>,action=<START|END>,time=<HH:MM>
  • Time is in 24 hours format

Example records:

  • orderId=O1,action=START,time=09:00
  • orderId=O1,action=END,time=09:20

Assumptions and Clarifications

  • All activity records returned for a Dasher belong to the same day.
  • Each order has maximum one START and one END record with the same orderId.
  • Time is measured in whole minutes.
  • Use [start, end] semantics: both start minute and end minute are included.
  • Total delivery time = end-start+1 minutes
  • If start > end, that order contributes 0 minutes of payout.
  • Records may arrive unordered; your implementation should process them correctly.
  • If a Dasher has no activity records, the payout is 0.
DasherPayoutService()
  • Creates the payout service.

Method Signatures

void addOrUpdatePayoutMetadata(String dasherId, int basePayRate, int bonusPay, int deliveryCountsToGetBonus)
  • dasherId will always be valid. It will contain characters from a-z and 0-9
  • basePayRate number of cents per minute that the dasher will get paid.
  • Each dasher may also get bonus pay after they have completed a certain number of deliveries in a day.
    e.g. 200 cents after every 10 deliveries.
    So If a dasher delivered 22 orders (both start and end time available) then they will make extra 200*2 = 400 cents bonus for that day.
  • 0<basePayRate, deliveryCountsToGetBonus<100
  • 0<=bonusPay<=1000
void addDeliveryActivity(String dasherId, List<String> deliveryActivities)
  • dasherId will always be valid.
  • deliveryActivities contains activity strings in the required format.
  • addDeliveryActivity() may be called several times for the same day for same dasher, aggregate all to calculate payout.
  • It may happen that start and end time for same orderId arrive out of order or even in separate addDeliveryActivity() call.
int payout(String dasherId)
  • Calculates and returns the final payout in cents for the given dasherId.
  • It must apply the payment rules including bonuses using the full set of activity records received for that Dasher.

Constraints

  • 1 ≤ dasherId.length() ≤ 100
  • 0 ≤ deliveryActivities.size() ≤ 100
  • Each method will always be called with valid input data.
  • Each activity string follows the format orderId=<id>,action=<START|END>,time=<HH:MM>
  • 00:00 ≤ time ≤ 23:59
  • Multiple orders may overlap in time.
  • There is no fixed upper bound on concurrent active orders in the logic.
  • The solution should be efficient enough to handle large activity lists.

Examples

Example 1: Non-overlapping deliveries

  • DasherPayoutService service = new DasherPayoutService()
  • service.addOrUpdatePayoutMetadata(dasherId="D1", basePayRate=30, bonusPay=200, deliveryCountsToGetBonus=10)
  • service.addDeliveryActivity(dasherId="D1", deliveryActivities=List.of("orderId=O1,action=START,time=09:00", "orderId=O1,action=END,time=09:10", "orderId=O2,action=START,time=09:20", "orderId=O2,action=END,time=09:30"))
  • service.payout(dasherId="D1") = 660

Explanation:

  • Order O1 runs from 09:00 to 09:10 using [start, end] semantics, so it contributes 11 minutes.
  • Order O2 runs from 09:20 to 09:30, so it also contributes 11 minutes.
  • Total delivery minutes = 11 + 11 = 22.
  • Base payout = 22 * 30 = 660 cents.
  • Completed deliveries = 2, which is less than 10, so bonus = 0.
  • Total payout = 660 cents.

Example 2: Overlapping deliveries

  • DasherPayoutService service = new DasherPayoutService()
  • service.addOrUpdatePayoutMetadata(dasherId="D2", basePayRate=30, bonusPay=200, deliveryCountsToGetBonus=10)
  • service.addDeliveryActivity(dasherId="D2", deliveryActivities=List.of("orderId=O10,action=START,time=09:00", "orderId=O10,action=END,time=09:20", "orderId=O11,action=START,time=09:10", "orderId=O11,action=END,time=09:30"))
  • service.payout(dasherId="D2") = 1260

Explanation:

  • 09:00 to 09:09 = 10 minutes with 1 ongoing delivery → 10 * 30 = 300 cents.
  • 09:10 to 09:20 = 11 minutes with 2 ongoing deliveries → 11 * (2 * 30) = 660 cents.
  • 09:21 to 09:30 = 10 minutes with 1 ongoing delivery → 10 * 30 = 300 cents.
  • Base payout = 300 + 660 + 300 = 1260 cents.
  • Completed deliveries = 2, so bonus = 0.
  • Total payout = 1260 cents.

Example 3: Records arrive unordered and across multiple calls

  • DasherPayoutService service = new DasherPayoutService()
  • service.addOrUpdatePayoutMetadata(dasherId="D3", basePayRate=25, bonusPay=150, deliveryCountsToGetBonus=2)
  • service.addDeliveryActivity(dasherId="D3", deliveryActivities=List.of("orderId=O20,action=END,time=10:05", "orderId=O21,action=START,time=10:08"))
  • service.addDeliveryActivity(dasherId="D3", deliveryActivities=List.of("orderId=O20,action=START,time=10:00", "orderId=O21,action=END,time=10:10"))
  • service.payout(dasherId="D3") = 375

Explanation:

  • Order O20 is reconstructed as 10:00 to 10:056 minutes.
  • Order O21 is reconstructed as 10:08 to 10:103 minutes.
  • Total delivery minutes = 6 + 3 = 9.
  • Base payout = 9 * 25 = 225 cents.
  • Completed deliveries = 2, so bonus = 150 * 1 = 150 cents.
  • Total payout = 225 + 150 = 375 cents.

Example 4: Bonus applied multiple times

  • DasherPayoutService service = new DasherPayoutService()
  • service.addOrUpdatePayoutMetadata(dasherId="D4", basePayRate=50, bonusPay=120, deliveryCountsToGetBonus=2)
  • service.addDeliveryActivity(dasherId="D4", deliveryActivities=List.of("orderId=O1,action=START,time=08:00", "orderId=O1,action=END,time=08:00", "orderId=O2,action=START,time=08:10", "orderId=O2,action=END,time=08:10", "orderId=O3,action=START,time=08:20", "orderId=O3,action=END,time=08:20", "orderId=O4,action=START,time=08:30", "orderId=O4,action=END,time=08:30", "orderId=O5,action=START,time=08:40", "orderId=O5,action=END,time=08:40"))
  • service.payout(dasherId="D4") = 490

Explanation:

  • Each order starts and ends in the same minute, so each contributes 1 minute.
  • Total delivery minutes = 5.
  • Base payout = 5 * 50 = 250 cents.
  • Completed deliveries = 5.
  • Bonus applies after every 2 deliveries, so number of bonuses = floor(5 / 2) = 2.
  • Total bonus = 2 * 120 = 240 cents.
  • Total payout = 250 + 240 = 490 cents.

Example 5: No delivery activity

  • DasherPayoutService service = new DasherPayoutService()
  • service.addOrUpdatePayoutMetadata(dasherId="D5", basePayRate=30, bonusPay=200, deliveryCountsToGetBonus=10)
  • service.payout(dasherId="D5") = 0

Explanation:

  • No activity records were added for D5.
  • So the Dasher has 0 delivery minutes and 0 completed deliveries.
  • Total payout = 0 cents.




Please use Laptop/Desktop or any other large screen to add/edit code.