Skip to main content

Design a Order Inventory Management System

Problem Statement

Design an order and inventory management system that allows sellers to add products, maintain stock levels, and process customer orders. The system should ensure that orders are only placed when sufficient inventory is available and should update stock automatically after each successful purchase.


Functional Requirements

  • Sellers should be able to add and manage products
  • System should maintain real-time inventory for each product
  • Users should be able to place orders for products
  • System should validate stock before confirming orders
  • Inventory should be updated after every successful order
  • Orders should maintain status lifecycle (CREATED → CONFIRMED → CANCELLED)

Objects Required

  • Product
  • Seller
  • Inventory
  • Order
  • OrderItem
  • Customer
  • InventoryService

OrderStatus Enum


public enum OrderStatus {
    CREATED,
    CONFIRMED,
    CANCELLED
}

This enum defines the lifecycle of an order. It ensures that every order transitions through a controlled and predictable state flow instead of using free-form strings.


Product Class


public class Product {

    private String productId;
    private String name;
    private double price;
    private Seller seller;

    public Product(String productId, String name, double price, Seller seller) {
        this.productId = productId;
        this.name = name;
        this.price = price;
        this.seller = seller;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public Seller getSeller() {
        return seller;
    }
}

The constructor initializes a product with its identity, name, price, and owner seller. This ensures every product is traceable to a seller in the marketplace system.

The getName() method allows other components to display or log product information without exposing internal fields.

The getPrice() method is used during order calculation to compute total cost per item.

The getSeller() method ensures we can trace ownership of a product back to its seller, which is essential in marketplace systems.


Seller Class


public class Seller {

    private String sellerId;
    private String name;

    public Seller(String sellerId, String name) {
        this.sellerId = sellerId;
        this.name = name;
    }
}

Seller represents a marketplace entity who owns and manages product listings. A seller can have multiple products under their account.


Inventory Class


import java.util.*;

public class Inventory {

    private Map stock = new HashMap<>();

    public void addStock(Product product, int quantity) {
        stock.put(product.getProductId(),
                stock.getOrDefault(product.getProductId(), 0) + quantity);
    }

    public boolean isAvailable(Product product, int quantity) {
        return stock.getOrDefault(product.getProductId(), 0) >= quantity;
    }

    public void reduceStock(Product product, int quantity) {
        if (isAvailable(product, quantity)) {
            stock.put(product.getProductId(),
                    stock.get(product.getProductId()) - quantity);
        }
    }
}

The constructor initializes an empty stock map that tracks available quantity for each product.

The addStock() method increases inventory when new stock is added by a seller, ensuring the system always reflects real availability.

The isAvailable() method checks whether sufficient quantity exists before allowing an order to proceed, preventing overselling.

The reduceStock() method decreases inventory after a successful order, keeping stock levels consistent with actual sales.


OrderItem Class


public class OrderItem {

    private Product product;
    private int quantity;

    public OrderItem(Product product, int quantity) {
        this.product = product;
        this.quantity = quantity;
    }

    public double getTotalPrice() {
        return product.getPrice() * quantity;
    }

    public Product getProduct() {
        return product;
    }

    public int getQuantity() {
        return quantity;
    }
}

The constructor binds a product with a quantity, representing a single line item in an order.

The getTotalPrice() method calculates the total cost for that item, ensuring pricing logic stays encapsulated inside the class.

The getter methods allow controlled access for inventory validation and order processing.


Order Class


import java.util.*;

public class Order {

    private String orderId;
    private List items;
    private OrderStatus status;

    public Order(String orderId, List items) {
        this.orderId = orderId;
        this.items = items;
        this.status = OrderStatus.CREATED;
    }

    public void confirmOrder() {
        this.status = OrderStatus.CONFIRMED;
    }

    public void cancelOrder() {
        this.status = OrderStatus.CANCELLED;
    }

    public double getOrderTotal() {
        double total = 0;
        for (OrderItem item : items) {
            total += item.getTotalPrice();
        }
        return total;
    }

    public List getItems() {
        return items;
    }
}

The constructor creates an order in the CREATED state with all selected items.

The confirmOrder() method updates the order status when inventory validation succeeds and stock is reserved.

The cancelOrder() method marks the order as cancelled, which can later be used to trigger stock restoration logic if required.

The getOrderTotal() method computes the final payable amount by aggregating all item totals.


InventoryService Class


import java.util.*;

public class InventoryService {

    private Inventory inventory;

    public InventoryService(Inventory inventory) {
        this.inventory = inventory;
    }

    public boolean placeOrder(Order order) {

        for (OrderItem item : order.getItems()) {
            if (!inventory.isAvailable(item.getProduct(), item.getQuantity())) {
                System.out.println("Insufficient stock for: " + item.getProduct().getName());
                return false;
            }
        }

        for (OrderItem item : order.getItems()) {
            inventory.reduceStock(item.getProduct(), item.getQuantity());
        }

        order.confirmOrder();
        return true;
    }

    public void cancelOrder(Order order) {
        order.cancelOrder();
    }
}

The constructor injects the inventory dependency so that stock operations remain centralized and consistent.

The placeOrder() method first validates stock for all items. If even one product is unavailable, the entire order is rejected to maintain transactional consistency.

Once validation passes, stock is reduced and the order is marked as CONFIRMED.

The cancelOrder() method updates order status to CANCELLED, which can later be extended to restore inventory if needed.


Main Class


public class Main {

    public static void main(String[] args) {

        Seller seller = new Seller("S1", "John Store");

        Product p1 = new Product("P1", "Laptop", 50000, seller);
        Product p2 = new Product("P2", "Mouse", 1000, seller);

        Inventory inventory = new Inventory();

        inventory.addStock(p1, 10);
        inventory.addStock(p2, 50);

        OrderItem item1 = new OrderItem(p1, 1);
        OrderItem item2 = new OrderItem(p2, 2);

        Order order = new Order("O1", Arrays.asList(item1, item2));

        InventoryService service = new InventoryService(inventory);

        boolean success = service.placeOrder(order);

        if (success) {
            System.out.println("Order confirmed. Total: " + order.getOrderTotal());
        } else {
            System.out.println("Order failed due to insufficient stock");
        }
    }
}

Class Diagram

ProductproductId : Stringname : Stringprice : doublegetName() : StringgetPrice() : doubleSellersellerId : Stringname : StringOrderItemproduct : Productquantity : intgetTotalPrice() : doublegetProduct() : ProductgetQuantity() : intOrderorderId : Stringitems : List<OrderItem>status : OrderStatusconfirmOrder() : voidcancelOrder() : voidgetOrderTotal() : doubleInventoryaddStock(product, qty) : voidisAvailable(product, qty) : booleanreduceStock(product, qty) : voidInventoryServiceplaceOrder(order : Order) : booleancancelOrder(order : Order) : voidMainmain(args : String[]) : voidOrderStatusCREATEDCONFIRMEDCANCELLED

Also See

Comments

Popular posts from this blog

Designing a Parking Lot - Low Level Design

Problem Statement Design a parking lot that can handle vehicles entering and leaving while managing parking across multiple floors. Each vehicle should be assigned a suitable parking spot based on its type, and the spot should be freed once the vehicle exits. The design should also support generating a ticket at entry and optionally calculating the parking fee based on the duration of stay. Asked In Companies Amazon Google Microsoft Uber Walmart Flipkart Meta PayPal Oracle Salesforce Adobe Apple Intuit LinkedIn Atlassian Functional Requirements The design should support multiple vehicle types such as bikes, cars, and trucks A vehicle must be assigned a parking spot compatible with its type A parking spot cannot be assigned to more than one vehicle at a time The parking lot should support multiple levels (floors) The design should search and allocate an availa...

Most Frequently Asked Low Level Design(LLD) Interview Questions

Below are the curated list of most commonly asked Low Level Design (LLD) interview problems. Each problem includes a short description and a link to the complete solution with code and class diagrams. Design Parking Lot System The system should handle parking for different vehicle types such as bikes, cars, and trucks. It should manage slot allocation, availability tracking, and entry/exit flow. The design also ensures efficient usage of parking space under varying load conditions. View Solution Design Elevator / Lift System The system should support multiple elevators operating across floors with request handling logic. It focuses on scheduling algorithms to minimize wait time and optimize movement. It also manages direction control and concurrent floor requests. View Solution Design Movie Ticket Booking System The system should allow users to browse movies, select shows, and book seats. It handles seat ...

Software Design Patterns for LLD Interviews: A Complete Guide

Software Design Patterns for LLD Interviews: A Complete Guide In Software Development Engineer (SDE) interviews—especially for mid-level and senior roles—low-level design (LLD) rounds assess your ability to write clean, reusable, maintainable, and extensible code. The foundation of resolving these architectural challenges lies in the standard Gang of Four (GoF) Design Patterns. Rather than memorizing theoretical definitions, interviewers expect you to apply these patterns to real-world scenarios, identifying the trade-offs of each. Below is a comprehensive guide to the 12 most frequently asked design patterns in LLD interviews, categorized by their classification (Creational, Structural, and Behavioral). Each pattern contains a concrete, real-world Java implementation and a detailed breakdown of design decisions. Creational Design Patterns Creational design patterns deal with object creation mechanisms. They abstract the instantiation process, making a system independent of how...