181. Design Vending Machine Leasing System

Asked in

Design Vending Machine Leasing System
You need to design a VendingMachineLeasingSystem that manages vending machines, lease agreements, and lease payments.

A vending machine can be leased to a customer for a fixed period. Each lease agreement connects one customer with one vending machine.

The system must support two payment strategies: monthly payment and one-time payment.

Each vending machine also has a current machine state. The machine state should be handled using states such as Idle, OutOfStock, and Maintenance.

The design should keep interfaces clean and should be easy to extend with new machine states or new payment strategies.

Requirements

  • Register a vending machine with a unique machine id.
  • Create a lease agreement between a customer and an available vending machine.
  • Use currentMonth to decide whether a lease is active, upcoming, expired, or ended.
  • Do not allow overlapping lease periods for the same vending machine.
  • Track the current state of each vending machine.
  • Allow state changes between Idle, OutOfStock, and Maintenance.
  • Allow payments to be calculated based on the payment strategy chosen for the lease.
  • Support querying lease and machine details.

Important Rules

  • A lease has a fixed month range represented by startMonth and endMonth.
  • A lease is considered active at currentMonth if it has not been manually ended and startMonth ≤ currentMonth ≤ endMonth.
  • A lease is considered upcoming at currentMonth if it has not been manually ended and currentMonth < startMonth.
  • A lease is considered expired at currentMonth if it has not been manually ended and currentMonth > endMonth.
  • A lease is considered ended if endLease has been called for that lease.
  • A vending machine cannot have two non-ended leases with overlapping month ranges.
  • Expired leases are still considered non-ended leases. Therefore, an expired lease can still block creation of another overlapping lease unless it was manually ended.
  • Two lease ranges overlap if max(startMonth1,startMonth2) ≤ min(endMonth1,endMonth2).
  • A vending machine can be leased only if its current machine state is Idle.
  • Creating or ending a lease does not automatically change the machine state.
  • Upcoming leases do not make the machine's leasedStatus equal to "LEASED". Only active leases count.
  • Manual ending does not change the result of calculatePayment. Payment is always calculated using the original lease period and original payment strategy.
  • The system only stores whether a lease was manually ended. It does not need to return the month when it was ended.
  • State names and payment strategy names are case-sensitive.
  • When multiple error conditions apply, return the error for the first matching condition in the order listed for that method.

Machine States

Each vending machine must always be in exactly one of the following machine states:
  • Idle: The machine is working normally and is not under maintenance or out of stock. A machine in Idle state may still be leased. Leasing status is tracked separately from machine state.
  • OutOfStock: The machine has no inventory available and cannot be leased for a new lease while it remains in this state.
  • Maintenance: The machine is temporarily unavailable because it needs service and cannot be leased for a new lease while it remains in this state.

Payment Strategies

Each lease agreement uses one payment strategy:
  • MONTHLY: The lease amount is calculated as amount * numberOfMonths. Here, amount represents the monthly lease amount.
  • ONE_TIME: The lease amount is calculated as the fixed amount. Here, amount represents the total fixed lease amount.

Method Signatures

Constructor

VendingMachineLeasingSystem()

Creates an empty vending machine leasing system.

Register Machine

String registerMachine(String machineId, String location)

Registers a vending machine with the given machine id and location.

The input values machineId and location will always satisfy the stated constraints.
  • If machineId is already registered, return "Machine already exists".
  • Otherwise, add the machine in Idle state and return "Machine registered".

Create Lease

String createLease(String leaseId, String machineId, String customerId, int startMonth, int endMonth, int currentMonth, String paymentStrategy, int amount)

Creates a lease agreement for a vending machine.

The input values leaseId, machineId, customerId, startMonth, endMonth, currentMonth, paymentStrategy, and amount will always satisfy the stated value constraints.

A lease may be created for an already-started period as long as its endMonth is not before currentMonth.
  • If leaseId already exists, return "Lease already exists".
  • If machineId is not registered, return "Machine not found".
  • If endMonth < currentMonth, return "Lease period already expired".
  • If the machine has any non-ended lease whose month range overlaps with [startMonth,endMonth], return "Machine already leased for this period".
  • If the machine state is not Idle, return "Machine not available".
  • Otherwise, create the lease and return "Lease created".

Change Machine State

String changeMachineState(String machineId, String newState)

Changes the state of a vending machine.

The input value newState will always be one of "Idle", "OutOfStock", or "Maintenance".
  • If machineId is not registered, return "Machine not found".
  • Otherwise, update the machine state and return "State changed".

Calculate Payment

int calculatePayment(String leaseId)

Calculates the total payment required for a lease agreement.

Manual ending does not change the payment calculation.
  • If leaseId does not exist, return -1.
  • For "MONTHLY", return amount * (endMonth - startMonth + 1).
  • For "ONE_TIME", return amount.

End Lease

String endLease(String leaseId, int currentMonth)

Ends a lease agreement manually at the given current month.

The input value currentMonth will always satisfy the stated constraints.
  • If leaseId does not exist, return "Lease not found".
  • If the lease has already been manually ended, return "Lease already ended".
  • If currentMonth < startMonth, return "Lease not started".
  • Otherwise, mark the lease as ended and return "Lease ended".

Get Machine Details

String getMachineDetails(String machineId, int currentMonth)

Returns the details of a vending machine at the given current month.

The input value currentMonth will always satisfy the stated constraints.
  • If machineId is not registered, return "Machine not found".
  • Otherwise, return the machine details in the format "machineId,location,state,leasedStatus".
  • leasedStatus must be "LEASED" if the machine has a lease that is active at currentMonth.
  • leasedStatus must be "AVAILABLE" if the machine has no lease that is active at currentMonth.

Get Lease Details

String getLeaseDetails(String leaseId, int currentMonth)

Returns the details of a lease agreement at the given current month.

The input value currentMonth will always satisfy the stated constraints.
  • If leaseId does not exist, return "Lease not found".
  • Otherwise, return the lease details in the format "leaseId,machineId,customerId,startMonth,endMonth,paymentStrategy,amount,status".
  • status must be "ACTIVE" if the lease is active at currentMonth.
  • status must be "UPCOMING" if the lease has not started yet at currentMonth.
  • status must be "EXPIRED" if the lease period has passed at currentMonth and the lease was not manually ended.
  • status must be "ENDED" if the lease was manually ended using endLease.

Constraints

  • 1 ≤ machineId.length() ≤ 50
  • 1 ≤ leaseId.length() ≤ 50
  • 1 ≤ customerId.length() ≤ 50
  • 1 ≤ location.length() ≤ 100
  • 1 ≤ startMonth ≤ endMonth ≤ 120
  • 1 ≤ currentMonth ≤ 120
  • 1 ≤ amount ≤ 1,000,000
  • paymentStrategy will always be either "MONTHLY" or "ONE_TIME".
  • newState will always be one of "Idle", "OutOfStock", or "Maintenance".
  • All string parameters will be non-null and will satisfy their length constraints.
  • The system will receive at most 104 method calls.
  • Test cases will never pass invalid parameter values such as null strings, empty ids, invalid month ranges, invalid payment strategies, invalid machine states, negative amounts, or values outside the stated constraints.

Examples

Example 1

VendingMachineLeasingSystem system = new VendingMachineLeasingSystem()
system.registerMachine(machineId = "VM1", location = "Delhi") returns "Machine registered"
system.createLease(leaseId = "L1", machineId = "VM1", customerId = "C1", startMonth = 2, endMonth = 7, currentMonth = 1, paymentStrategy = "MONTHLY", amount = 5000) returns "Lease created"
system.getLeaseDetails(leaseId = "L1", currentMonth = 1) returns "L1,VM1,C1,2,7,MONTHLY,5000,UPCOMING"
system.getLeaseDetails(leaseId = "L1", currentMonth = 3) returns "L1,VM1,C1,2,7,MONTHLY,5000,ACTIVE"
system.calculatePayment(leaseId = "L1") returns 30000
system.getMachineDetails(machineId = "VM1", currentMonth = 3) returns "VM1,Delhi,Idle,LEASED"
system.getMachineDetails(machineId = "VM1", currentMonth = 8) returns "VM1,Delhi,Idle,AVAILABLE"

Explanation: Lease L1 starts at month 2 and ends at month 7. At month 1, it is upcoming. At month 3, it is active. The payment is 5000 * 6 = 30000. At month 8, the lease is expired, so the machine has no active lease.

Example 2

VendingMachineLeasingSystem system = new VendingMachineLeasingSystem()
system.registerMachine(machineId = "VM2", location = "Mumbai") returns "Machine registered"
system.changeMachineState(machineId = "VM2", newState = "Maintenance") returns "State changed"
system.createLease(leaseId = "L2", machineId = "VM2", customerId = "C7", startMonth = 4, endMonth = 6, currentMonth = 3, paymentStrategy = "ONE_TIME", amount = 18000) returns "Machine not available"
system.changeMachineState(machineId = "VM2", newState = "Idle") returns "State changed"
system.createLease(leaseId = "L2", machineId = "VM2", customerId = "C7", startMonth = 4, endMonth = 6, currentMonth = 3, paymentStrategy = "ONE_TIME", amount = 18000) returns "Lease created"
system.calculatePayment(leaseId = "L2") returns 18000
system.getLeaseDetails(leaseId = "L2", currentMonth = 5) returns "L2,VM2,C7,4,6,ONE_TIME,18000,ACTIVE"

Explanation: The machine cannot be leased while it is in Maintenance. After changing the machine state back to Idle, the lease is created. Since the payment strategy is ONE_TIME, the payment is exactly 18000.

Example 3

VendingMachineLeasingSystem system = new VendingMachineLeasingSystem()
system.registerMachine(machineId = "VM3", location = "Pune") returns "Machine registered"
system.createLease(leaseId = "L3", machineId = "VM3", customerId = "C2", startMonth = 3, endMonth = 5, currentMonth = 2, paymentStrategy = "MONTHLY", amount = 4000) returns "Lease created"
system.createLease(leaseId = "L4", machineId = "VM3", customerId = "C3", startMonth = 5, endMonth = 8, currentMonth = 2, paymentStrategy = "MONTHLY", amount = 4500) returns "Machine already leased for this period"
system.createLease(leaseId = "L5", machineId = "VM3", customerId = "C4", startMonth = 6, endMonth = 8, currentMonth = 2, paymentStrategy = "MONTHLY", amount = 4500) returns "Lease created"
system.getLeaseDetails(leaseId = "L3", currentMonth = 4) returns "L3,VM3,C2,3,5,MONTHLY,4000,ACTIVE"
system.getLeaseDetails(leaseId = "L5", currentMonth = 4) returns "L5,VM3,C4,6,8,MONTHLY,4500,UPCOMING"

Explanation: Lease L4 overlaps with lease L3 because both include month 5, so it is rejected. Lease L5 starts after L3 ends, so it can be created.

Example 4

VendingMachineLeasingSystem system = new VendingMachineLeasingSystem()
system.registerMachine(machineId = "VM4", location = "Chennai") returns "Machine registered"
system.createLease(leaseId = "L6", machineId = "VM4", customerId = "C8", startMonth = 2, endMonth = 10, currentMonth = 2, paymentStrategy = "MONTHLY", amount = 3000) returns "Lease created"
system.getMachineDetails(machineId = "VM4", currentMonth = 4) returns "VM4,Chennai,Idle,LEASED"
system.endLease(leaseId = "L6", currentMonth = 5) returns "Lease ended"
system.getLeaseDetails(leaseId = "L6", currentMonth = 6) returns "L6,VM4,C8,2,10,MONTHLY,3000,ENDED"
system.getMachineDetails(machineId = "VM4", currentMonth = 6) returns "VM4,Chennai,Idle,AVAILABLE"
system.calculatePayment(leaseId = "L6") returns 27000

Explanation: Lease L6 is manually ended at month 5. After that, the lease status is ENDED, and the machine has no active lease at month 6. The payment is still calculated using the original lease range from month 2 to month 10, so the payment is 3000 * 9 = 27000.




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