pythonintermediate45 minPython 3

Warehouse Inventory Manager with Invariant Validation

Design object-oriented inventory management classes in Python enforcing stock constraints, replenishment, and order fulfillment.

The incident

Company
SwiftStock Logistics
Engineer
Aditya Nair, Software Engineer
Trigger
Fulfillment software oversold stock by accepting orders when physical warehouse bins were empty, forcing costly backorders.
Stakes
Backorder compensation vouchers and expedited courier surcharges cost 12 lakh rupees in lost margins over a holiday shopping weekend.

On a Tuesday morning following a major national holiday promotional campaign, Aditya Nair was summoned to an emergency operations review at SwiftStock Logistics. The warehouse management software had accepted forty-five customer orders for high-demand mechanical keyboards even though physical warehouse bins held only ten units in stock across the main fulfillment center. Because fulfillment teams could not locate physical inventory on shelves, regional dispatch centers stalled and dozens of priority shipments breached customer delivery commitments across multiple metropolitan distribution regions, generating acute customer frustration and internal support chaos.

The customer service department was completely overwhelmed with escalation tickets from disappointed buyers whose deliveries had failed to arrive on schedule. To prevent widespread customer churn and mitigate brand damage on public review forums, operations management had to issue twelve lakh rupees in apology credits and customer gift vouchers. The logistics group also had to absorb expensive expedited air courier surcharges to source replacement items from distant third-party supplier warehouses at a significant financial loss for the company.

Investigation into the inventory microservice revealed that stock balances were maintained as raw mutable dictionary counters shared across concurrent worker threads without validation wrappers. Any asynchronous order worker or replenishment script could decrement stock quantities directly without verifying whether available units were sufficient to fulfill the request. This unconstrained mutation corrupted order reporting across all regional dashboards.

The engineering director instructed Aditya to redesign the core inventory domain layer using rigorous object-oriented programming principles. The new architecture needed to encapsulate product state within a dedicated Product class, shielding internal stock attributes behind validated instance methods. The class had to provide explicit restock and fulfill operations that enforced business invariants and raised domain-specific exceptions whenever an allocation exceeded available physical quantities on warehouse shelves, preventing corrupt inventory states before database persistence.

Aditya structured the domain model around clean defensive boundaries. When fulfillment requests exceeded available inventory, the system raised an InsufficientStockError immediately, rejecting the order before database commit. The model also tracked cumulative fulfilled revenue and maintained an append-only transaction ledger to provide complete operational auditability for warehouse managers reconciling physical counts with warehouse ledger entries during weekly stock audits across regional fulfillment centers.

When deployed to the staging environment, the object-oriented inventory model successfully eliminated overselling anomalies, rejecting excessive allocations deterministically while processing valid fulfillments without latency penalties. The inventory class specifications, invariant tests, and exception handling protocols are reviewed weekly by the Warehouse Operations Director and Lead Systems Architect to ensure compliance with enterprise inventory governance standards and prevent recurring financial write-downs during peak promotional shopping events across regional warehouses.

What you will learn

  • Encapsulate state and business validation rules within Python OOP classes
  • Raise custom domain exceptions (InsufficientStockError) on illegal inventory decrements
  • Model continuous stock mutations through restock and fulfillment methods
  • Track financial revenue generated by fulfilled order quantities

What you need first

Object-Oriented EncapsulationPython OOP basics

Classes encapsulate state in instance attributes and enforce business validation rules through dedicated methods rather than raw dictionary access.

PythonMini example
class Item: def __init__(self, s): self.stock = s
print(Item(10).stock)
10
Watch out

Directly modifying instance attributes like item.stock -= 5 bypasses business validation rules and enables negative quantities.

Custom Domain ExceptionsPython error handling

Creating application-specific exceptions derived from Exception allows callers to intercept domain boundary violations cleanly.

PythonMini example
class OutOfStock(Exception): pass
print(issubclass(OutOfStock, Exception))
True
Watch out

Raising generic Exception instead of custom domain exceptions prevents callers from distinguishing business errors from unexpected system bugs.

State Mutation InvariantsPython control flow

Mutation methods should validate preconditions before updating internal state.

PythonMini example
def deduct(curr, req): return curr - req if curr >= req else None
print(deduct(5, 3), deduct(2, 5))
2 None
Watch out

Performing attribute updates before running validation checks leaves internal state corrupted if an exception occurs mid-method.

Architecture and data flow

Problem scenario diagram for py-proj-inventory-classes
Problem scenario diagram for py-proj-inventory-classes. Figure 1: Operational problem and business context
Data flow diagram for py-proj-inventory-classes
Data flow diagram for py-proj-inventory-classes. Figure 2: Pipeline execution and data transformation flow
Result shape diagram for py-proj-inventory-classes
Result shape diagram for py-proj-inventory-classes. Figure 3: Output verification and method results

The data

A warehouse product record with SKU, name, unit price, and initial stock level.

products: Warehouse product inventory records

skunamepricestock
KB-990Mechanical Keyboard350010
MS-401Wireless Ergonomic Mouse120025

Step by step

Read each step, run its code, then check your output against the one shown.

  1. Define Product class schema and attributes

    We construct the foundation of our inventory domain model by defining a Product class with encapsulated instance attributes. The constructor initializes the product SKU identifier, product name, unit selling price, and opening inventory count. Storing these values as instance attributes ensures that every physical product maintains an independent lifecycle and state boundary. We inspect the instantiated object attributes to confirm accurate initialization before introducing business mutation methods to govern stock changes safely without shared state contamination. This explicit architectural boundary ensures that warehouse inventory records maintain mathematical consistency and prevent overselling across concurrent client workers.

    PythonStep 1
    class Product:
        def __init__(self, sku: str, name: str, price: float, stock: int = 0):
            self.sku = sku
            self.name = name
            self.price = price
            self.stock = stock
    
    p = Product("KB-990", "Mechanical Keyboard", 3500.0, 10)
    print(f"Product initialized: {p.sku} | {p.name} | Stock: {p.stock} | Price: ₹{p.price}")
    Product initialized: KB-990 | Mechanical Keyboard | Stock: 10 | Price: ₹3500.0
    Common mistake

    Watch out: Defining mutable default values like lists or dicts inside class bodies shares state across all instances instead of isolating per product.

    How you will know

    The output confirms that the Product instance initializes with SKU KB-990 and 10 units in stock.

  2. Demonstrate pitfalls of unvalidated dictionary mutation

    Wrong turn first: this step shows the mistake before the fix

    We demonstrate the primary architectural defect of legacy inventory systems: mutating inventory balances directly without invariant boundary checks. When orders are processed by simple arithmetic subtraction on raw dictionaries or unprotected attributes, an order requesting fifteen units against a stock of ten decrements the balance directly to minus five. In real warehouse fulfillment operations, negative balances create phantom orders, breach delivery SLAs, and trigger expensive customer apology vouchers that damage brand reputation and create operational confusion. This explicit architectural boundary ensures that warehouse inventory records maintain mathematical consistency and prevent overselling across concurrent client workers.

    PythonStep 2
    inventory = {"KB-990": 10}
    order_qty = 15
    
    # Naive unvalidated decrement
    inventory["KB-990"] -= order_qty
    print(f"Stock after unvalidated order: {inventory['KB-990']} (oversold!)")
    Stock after unvalidated order: -5 (oversold!)
    Common mistake

    Watch out: Direct dictionary subtractions do not check for negative boundary conditions.

    How you will know

    The output exposes a negative stock level of -5, illustrating the overselling flaw.

  3. Implement InsufficientStockError and defensive fulfill method

    To guarantee that inventory can never enter a negative state, we introduce a custom domain exception named InsufficientStockError and implement a defensive fulfill() method on the Product class. Before decrementing stock, the method validates that the requested quantity is strictly positive and does not exceed available units. If an allocation exceeds stock, it raises the exception with precise diagnostic context. If valid, it decrements stock and returns fulfilled revenue for ledger accounting and warehouse reporting. This explicit architectural boundary ensures that warehouse inventory records maintain mathematical consistency and prevent overselling across concurrent client workers.

    PythonStep 3
    class InsufficientStockError(Exception):
        pass
    
    class Product:
        def __init__(self, sku: str, name: str, price: float, stock: int = 0):
            self.sku = sku
            self.name = name
            self.price = price
            self.stock = stock
    
        def fulfill(self, quantity: int) -> float:
            if quantity <= 0:
                raise ValueError("Fulfill quantity must be strictly positive")
            if quantity > self.stock:
                raise InsufficientStockError(
                    f"Cannot fulfill {quantity} units of {self.sku}; only {self.stock} available"
                )
            self.stock -= quantity
            return quantity * self.price
    
    p = Product("KB-990", "Mechanical Keyboard", 3500.0, 10)
    rev1 = p.fulfill(4)
    print(f"Fulfilled 4 units. Revenue: ₹{rev1} | Remaining Stock: {p.stock}")
    
    try:
        p.fulfill(10)
    except InsufficientStockError as e:
        print(f"Caught expected error: {e}")
    Fulfilled 4 units. Revenue: ₹14000.0 | Remaining Stock: 6
    Caught expected error: Cannot fulfill 10 units of KB-990; only 6 available
    Common mistake

    Watch out: Mutating self.stock before checking quantity > self.stock corrupts stock levels before an exception is raised.

    How you will know

    The first fulfillment succeeds with 6 units remaining; the second fulfillment cleanly raises InsufficientStockError.

  4. Implement restock method with positive quantity validation

    Warehouse operations require replenishment capabilities when supplier shipments arrive at receiving docks. We implement a dedicated restock() method on our Product class to handle incoming batches. The method validates that the received quantity is greater than zero to prevent accidental negative replenishment entries caused by clerical typos. We confirm that restocking increments available inventory deterministically and returns the updated stock level for warehouse receiving receipts and accounting reconciliation across physical bins. This explicit architectural boundary ensures that warehouse inventory records maintain mathematical consistency and prevent overselling across concurrent client workers.

    PythonStep 4
    class InsufficientStockError(Exception):
        pass
    
    class Product:
        def __init__(self, sku: str, name: str, price: float, stock: int = 0):
            self.sku = sku
            self.name = name
            self.price = price
            self.stock = stock
    
        def fulfill(self, quantity: int) -> float:
            if quantity <= 0:
                raise ValueError("Fulfill quantity must be strictly positive")
            if quantity > self.stock:
                raise InsufficientStockError(f"Insufficient stock for {self.sku}")
            self.stock -= quantity
            return quantity * self.price
    
        def restock(self, quantity: int) -> int:
            if quantity <= 0:
                raise ValueError("Restock quantity must be positive")
            self.stock += quantity
            return self.stock
    
    p = Product("KB-990", "Mechanical Keyboard", 3500.0, 6)
    new_stock = p.restock(20)
    print(f"Restocked 20 units. Total Available Stock: {new_stock}")
    Restocked 20 units. Total Available Stock: 26
    Common mistake

    Watch out: Permitting zero or negative quantities in restock allows erroneous data entry to silently degrade inventory counts.

    How you will know

    The output confirms that adding 20 units to the existing 6 brings total stock to 26.

  5. Process multi-order batch and aggregate financial revenue

    In this final milestone, we simulate a realistic batch order fulfillment loop. We process a list of incoming customer purchase orders against our product instance, accumulating total sales revenue for fulfilled items while safely catching and isolating InsufficientStockError exceptions for stockouts. This design allows automated order dispatch pipelines to fulfill valid line items immediately while routing out-of-stock items to procurement reorder queues without crashing the batch worker execution thread or corrupting inventory balances. This explicit architectural boundary ensures that warehouse inventory records maintain mathematical consistency and prevent overselling across concurrent client workers.

    PythonStep 5
    class InsufficientStockError(Exception):
        pass
    
    class Product:
        def __init__(self, sku: str, name: str, price: float, stock: int = 0):
            self.sku = sku
            self.name = name
            self.price = price
            self.stock = stock
    
        def fulfill(self, quantity: int) -> float:
            if quantity <= 0:
                raise ValueError("Quantity must be positive")
            if quantity > self.stock:
                raise InsufficientStockError(f"Insufficient stock for {self.sku}")
            self.stock -= quantity
            return quantity * self.price
    
        def restock(self, quantity: int) -> int:
            if quantity <= 0:
                raise ValueError("Quantity must be positive")
            self.stock += quantity
            return self.stock
    
    p = Product("KB-990", "Mechanical Keyboard", 3500.0, 10)
    orders = [3, 5, 4, 2]  # Cumulative requested: 14 units (stock only 10)
    
    total_revenue = 0.0
    fulfilled_count = 0
    failed_count = 0
    
    for qty in orders:
        try:
            rev = p.fulfill(qty)
            total_revenue += rev
            fulfilled_count += 1
            print(f"Order for {qty} units fulfilled (+₹{rev:.1f}) | Stock left: {p.stock}")
        except InsufficientStockError:
            failed_count += 1
            print(f"Order for {qty} units rejected (Stockout) | Stock left: {p.stock}")
    
    print("--- Fulfillment Summary ---")
    print(f"Fulfilled Orders: {fulfilled_count}")
    print(f"Rejected Orders: {failed_count}")
    print(f"Total Revenue: ₹{total_revenue:.1f}")
    print(f"Final Inventory Balance: {p.stock}")
    Order for 3 units fulfilled (+₹10500.0) | Stock left: 7
    Order for 5 units fulfilled (+₹17500.0) | Stock left: 2
    Order for 4 units rejected (Stockout) | Stock left: 2
    Order for 2 units fulfilled (+₹7000.0) | Stock left: 0
    --- Fulfillment Summary ---
    Fulfilled Orders: 3
    Rejected Orders: 1
    Total Revenue: ₹35000.0
    Final Inventory Balance: 0
    Common mistake

    Watch out: Failing to trap InsufficientStockError inside the batch iteration causes the entire order processing job to abort on the first out-of-stock item.

    How you will know

    Summary prints 2 fulfilled orders (8 units total, ₹28,000.0), 2 rejected orders, and 2 units remaining in stock.

Build it yourself

Write your solution below, run it in your browser, and pass every check.

Python 3Ready to run
Loading editor…
Press Run Code to evaluate
Inventory manager executes cleanly
Fulfills 4 units and computes revenue
Raises InsufficientStockError on over-allocation
Restocks inventory correctly

What the result means

Interpretation

The object-oriented inventory domain model guarantees that stock balances can never decrement into negative numbers. In production, this boundary check prevents overselling before orders are committed to payment gateways, saving SwiftStock Logistics over twelve lakh rupees in expedited courier charges and backorder compensation vouchers.

The message you would send

Hi Warehouse Operations Team, the upgraded inventory domain classes have been validated. The new engine strictly enforces non-negative stock invariants, rejecting order over-allocations deterministically with InsufficientStockError while maintaining clean fulfillment revenue calculations.

Put it on your CV

Resume or LinkedIn bullet

OutputCopy this line
Architected an object-oriented inventory management domain engine in Python with custom invariant exceptions, eliminating negative stock overselling across warehouse fulfillment pipelines.

README for GitHub

OutputREADME.md
# Warehouse Inventory Manager with Invariant Validation

## Business Context
Fulfillment microservices oversold high-demand inventory during peak promotional periods by executing unvalidated dictionary decrements, causing backorders and customer compensation vouchers.

## Solution Architecture
- Encapsulated inventory balances within an object-oriented `Product` domain class.
- Raised domain-specific `InsufficientStockError` exceptions to intercept over-allocations.
- Provided validated `restock()` and `fulfill()` methods.

## Verification
Passes all automated verification checks on Python 3 standard library.
Stretch goal

Extend the Product class with a reservation lock method that temporarily holds inventory during online checkout sessions and releases it after a 15-minute timeout.

Keep going