83. Design Flipkart Delivery Service

Design Flipkart Delivery Service
Design and implement an in-memory FK Delivery Service. The service manages orders that are delivered to a pincode and delivery agents who can pick up and deliver those orders.

The system must support:
  • Users creating orders with an order name, order pincode, and creation time.
  • Admin creating delivery agents and associating them with pincodes.
  • Executing a driver function that assigns orders to eligible agents and returns delivery status logs.

Key rules:
  • Multiple delivery agents can be registered to a single pincode.
  • In the base version, an agent can deliver to only one pincode.
  • Orders for a pincode are delivered by an agent registered for that pincode.
  • All logs include timestamps in the standard time format.

Bonus extensions:
  • Allow an agent to deliver to multiple pincodes.
  • Support scheduled deliveries with a scheduled start time and duration (minutes).

Standard Time Format

  • All timestamps are provided as strings in the exact format: "yyyy-MM-dd, HH:mm"
  • Timestamps will be always be provided in valid format.
  • yyyy is a 4-digit year
  • MM is a 2-digit month from 01 to 12
  • dd is a 2-digit day of month from 01 to 31
  • HH is a 2-digit hour from 00 to 23 (24-hour clock)
  • mm is a 2-digit minute from 00 to 59
  • Example valid timestamps:
    • "2025-02-11, 14:56"
    • "2030-01-03, 13:05"
  • Because of this fixed-width format, chronological ordering is the same as lexicographic string ordering.
  • All times are assumed to be in the same local timezone (no timezone conversion required).

Method Signatures

Class

  • Implement the following class: FKDeliveryService

1) Create Order

String createOrder(String orderName, String pincode, String creationTime)
  • Creates a non-scheduled order with orderName to be delivered to pincode.
  • creationTime is used for ordering during execute() for non-scheduled orders.
  • Returns:
    • "ORDER_CREATED" if created successfully
    • "ORDER_ALREADY_EXISTS" if an order with the same orderName already exists

2) Create Scheduled Order (Bonus)

String createOrderScheduled(String orderName, String pincode, String scheduledStartTime, int durationMinutes)
  • Creates a scheduled order.
  • scheduledStartTime is the earliest allowed pickup time and is used for ordering during execute().
  • durationMinutes is the time needed to deliver the order.
  • Returns:
    • "ORDER_CREATED" if created successfully
    • "ORDER_ALREADY_EXISTS" if an order with the same orderName already exists
    • "INVALID_SCHEDULE" if durationMinutes <= 0

3) Create Agent

String createAgent(String agentName, String pincode)
  • Registers a delivery agent who can deliver to the given pincode.
  • In the base version, an agent can deliver to only one pincode (the pincode passed here).
  • Returns:
    • "AGENT_CREATED" if created successfully
    • "AGENT_ALREADY_EXISTS" if an agent with the same agentName already exists

4) Add Agent Pincode (Bonus: multi-pincode agents)

String addAgentPincode(String agentName, String pincode)
  • Adds an additional deliverable pincode to an existing agent.
  • Returns:
    • "PINCODE_ADDED" if added successfully
    • "AGENT_NOT_FOUND" if agentName does not exist
    • "PINCODE_ALREADY_PRESENT" if the agent already has that pincode

5) Execute Delivery Driver

List<String> execute()
  • It will only be called once and will be the last method call.
  • Executes the delivery simulation for all currently pending orders even if completion time lies in the future and returns the status logs as a list of strings. (in the exact order the simulated events occur).
  • Order selection rule (which order to schedule next):
    • Consider all pending orders across all pincodes together.
    • Each order has an ordering time:
      • Non-scheduled: orderingTime = creationTime
      • Scheduled: orderingTime = scheduledStartTime
    • Process orders in increasing orderingTime (lexicographic string ordering is sufficient).
    • If two orders have the same orderingTime, pick lexicographically smaller orderName first.
    • When an order is successfully planned for delivery (i.e., it has at least one eligible agent), it receives an internal assignment index based on this planning sequence within the current execute() call (first planned order has index 1, then 2, etc.).
  • Eligibility and agent choice:
    • An agent is eligible for an order if the agent can deliver to that order's pincode.
    • If an order has no eligible agents at all, it remains pending and produces no logs in this execute().
    • Agent free/completion rule (must be reflected by logs):
      • An agent can pick up a new order at time T only if the agent is free at time T.
      • For scheduled orders, an agent is busy from actualPickupTime until completionTime.
      • An agent becomes free exactly at completionTime (so picking up another order at the same timestamp is allowed only after completion).
    • When choosing between multiple eligible agents for a pickup time:
      • If multiple eligible agents are free at that pickup time, pick lexicographically smallest agentName.
      • If no eligible agent is free at the earliest allowed pickup time, delay pickup to the earliest time when any eligible agent becomes free.
      • If multiple eligible agents become free at the same earliest time, pick lexicographically smallest agentName.
  • Time handling and simulation rules:
    • Non-scheduled orders:
      • creationTime is the earliest allowed pickup time.
      • If no eligible agent is free at creationTime, pickup is delayed until the earliest time when any eligible agent becomes free.
      • They are treated as instant deliveries (zero duration):
        • actualPickupTime is determined as described above (at creationTime if possible, otherwise delayed).
        • completionTime = actualPickupTime.
      • They include timestamps in logs (using actualPickupTime and completionTime).
      • They do not make an agent busy (since duration is zero).
    • Scheduled orders:
      • scheduledStartTime is the earliest allowed pickup time.
      • They include timestamps in logs.
      • An agent is considered busy for a scheduled order from actualPickupTime until completionTime.
      • Pickup can be delayed when the eligible agent is busy.
      • Completion time is based on actual pickup time (not scheduledStartTime).
      • Definitions:
        • actualPickupTime is:
          • scheduledStartTime if there exists at least one eligible agent free at scheduledStartTime
          • otherwise, the earliest time when any eligible agent becomes free
        • completionTime = actualPickupTime + durationMinutes
  • Log ordering (deterministic, must reflect agent completion before next pickup for that agent):
    • Each delivered order produces exactly two events: pickup and completion.
    • Events are returned sorted by:
      • 1) Event time ascending (lexicographic string ordering is sufficient)
      • 2) If same event time: smaller assignment index first (based on the order planning sequence inside the current execute())
      • 3) If same event time and same assignment index: pickup log before completion log (within the same order)
      • 4) If still tied: lexicographically smaller orderName first
      • 5) If still tied: lexicographically smaller agentName first
    • This ordering ensures that if an agent completes one order at time T and then picks up another at the same time T, the completion log of the earlier assigned order appears before the pickup log of the later assigned order.
    • For non-scheduled orders, both events have event time = actualPickupTime (instant), and the timestamp is printed in both log strings.
  • Post-conditions:
    • Once an order is delivered, it is marked completed and will not be delivered again in future execute() calls.
    • Orders that have no eligible agent remain pending and may be delivered in a later execute() call after agents are added.
  • Log format (exact strings):
    • Non-scheduled orders:
      • "<agentName> has picked up <orderName> at <actualPickupTime>"
      • "<agentName> has delivered <orderName> to <pincode> at <completionTime>"
    • Scheduled orders:
      • "<agentName> has picked up <orderName> at <actualPickupTime>"
      • "<agentName> has completed delivery of <orderName> to <pincode> at <completionTime>"

Constraints

  • 1 ≤ orderName.length() ≤ 50
  • 1 ≤ agentName.length() ≤ 50
  • pincode is a string of digits with 1 ≤ pincode.length() ≤ 10
  • createOrder and createOrderScheduled use unique orderName as the order identifier.
  • createAgent uses unique agentName as the agent identifier.
  • Time format is exactly "yyyy-MM-dd, HH:mm".
  • durationMinutes > 0 for scheduled orders.
  • All operations are performed in-memory (no external storage).

Examples

Example 1: Basic Functionalities (Non-scheduled orders ordered by creationTime)

  • Input (method calls):
    • FKDeliveryService service = new FKDeliveryService()
    • service.createOrder(orderName="Order A", pincode="560087", creationTime="2025-03-22, 10:00")"ORDER_CREATED"
    • service.createOrder(orderName="Order B", pincode="560088", creationTime="2025-03-22, 10:01")"ORDER_CREATED"
    • service.createOrder(orderName="Order C", pincode="560089", creationTime="2025-03-22, 10:02")"ORDER_CREATED"
    • service.createOrder(orderName="Order D", pincode="560087", creationTime="2025-03-22, 10:03")"ORDER_CREATED"
    • service.createAgent(agentName="AgentA", pincode="560087")"AGENT_CREATED"
    • service.createAgent(agentName="AgentB", pincode="560088")"AGENT_CREATED"
    • service.createAgent(agentName="AgentC", pincode="560089")"AGENT_CREATED"
    • service.execute() → output below
  • Output (List<String>):
    • "AgentA has picked up Order A at 2025-03-22, 10:00"
    • "AgentA has delivered Order A to 560087 at 2025-03-22, 10:00"
    • "AgentB has picked up Order B at 2025-03-22, 10:01"
    • "AgentB has delivered Order B to 560088 at 2025-03-22, 10:01"
    • "AgentC has picked up Order C at 2025-03-22, 10:02"
    • "AgentC has delivered Order C to 560089 at 2025-03-22, 10:02"
    • "AgentA has picked up Order D at 2025-03-22, 10:03"
    • "AgentA has delivered Order D to 560087 at 2025-03-22, 10:03"

Example 2: Tie-breaking for same creationTime (lexicographically smaller orderName first)

  • Input (method calls):
    • FKDeliveryService service = new FKDeliveryService()
    • service.createOrder(orderName="Order B", pincode="560087", creationTime="2025-03-22, 09:00")"ORDER_CREATED"
    • service.createOrder(orderName="Order A", pincode="560087", creationTime="2025-03-22, 09:00")"ORDER_CREATED"
    • service.createAgent(agentName="AgentA", pincode="560087")"AGENT_CREATED"
    • service.execute() → output below
  • Output (List<String>):
    • "AgentA has picked up Order A at 2025-03-22, 09:00"
    • "AgentA has delivered Order A to 560087 at 2025-03-22, 09:00"
    • "AgentA has picked up Order B at 2025-03-22, 09:00"
    • "AgentA has delivered Order B to 560087 at 2025-03-22, 09:00"

Example 3: Scheduled Delivery with delayed pickup (ordering by scheduledStartTime, tie by orderName)

  • Input (method calls):
    • FKDeliveryService service = new FKDeliveryService()
    • service.createAgent(agentName="AgentA", pincode="560087")"AGENT_CREATED"
    • service.createOrderScheduled(orderName="Order A", pincode="560087", scheduledStartTime="2025-03-22, 10:30", durationMinutes=20)"ORDER_CREATED"
    • service.createOrderScheduled(orderName="Order B", pincode="560087", scheduledStartTime="2025-03-22, 10:30", durationMinutes=30)"ORDER_CREATED"
    • service.execute() → output below
  • Output (List<String>):
    • "AgentA has picked up Order A at 2025-03-22, 10:30"
    • "AgentA has completed delivery of Order A to 560087 at 2025-03-22, 10:50"
    • "AgentA has picked up Order B at 2025-03-22, 10:50"
    • "AgentA has completed delivery of Order B to 560087 at 2025-03-22, 11:20"

Example 4: Mixed non-scheduled and scheduled orders (ordered by orderingTime, tie by orderName)

  • Input (method calls):
    • FKDeliveryService service = new FKDeliveryService()
    • service.createAgent(agentName="AgentA", pincode="560087")"AGENT_CREATED"
    • service.createOrder(orderName="Order X", pincode="560087", creationTime="2025-03-22, 10:15")"ORDER_CREATED"
    • service.createOrderScheduled(orderName="Order A", pincode="560087", scheduledStartTime="2025-03-22, 10:30", durationMinutes=30)"ORDER_CREATED"
    • service.execute() → output below
  • Output (List<String>):
    • "AgentA has picked up Order X at 2025-03-22, 10:15"
    • "AgentA has delivered Order X to 560087 at 2025-03-22, 10:15"
    • "AgentA has picked up Order A at 2025-03-22, 10:30"
    • "AgentA has completed delivery of Order A to 560087 at 2025-03-22, 11:00"




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