|

Simple Inventory Management System

Spread the love

Project Description

Create a C++ console application to track products in a store’s inventory. The system must support the following features:

  • Product Representation: Each item should be modeled by a Product class containing:
    • SKU (std::string): a unique alphanumeric key identifying the product.
    • Name (std::string): the human-readable title of the product.
    • Quantity (int): the current number of units in stock.
    • Price (double): cost per single unit.
    • Methods:
      • restock(int amount): increases the quantity by a positive amount and reports the action.
      • sell(int amount): decreases the quantity if sufficient stock exists; otherwise, returns failure.
      • display(): prints current SKU, name, quantity, and price.
  • Inventory Management: A InventoryManager class is responsible for maintaining the product catalog:
    • productExists(const std::string& sku): checks if a product with the given SKU is already registered, preventing duplicates.
    • addProduct(const std::string& sku, const std::string& name, int quantity, double price): registers a new product after validating uniqueness and nonnegative initial stock.
    • removeProduct(const std::string& sku): deletes a product by SKU if it exists.
    • restockProduct(const std::string& sku, int amount): finds the product and calls its restock method.
    • sellProduct(const std::string& sku, int amount): finds the product and calls its sell method.
    • getLowStockProducts(int threshold): returns a list of products whose quantity is below the threshold, for reporting.
    • displayAllProducts(): iterates through the catalog and prints each product’s details.
  • Behavioral Requirements:
    • Stock operations must validate inputs: restock amounts must be positive; sell amounts cannot exceed current stock.
    • All actions should provide console feedback indicating success or failure.
    • The system should use modern C++ memory management by storing products in a container of std::unique_ptr to ensure exclusive ownership and automatic cleanup.

Solution :

Product Class :
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <string>

// Product class
class Product {
public:
    std::string sku;
    std::string name;
    int quantity;
    double price;

    Product(const std::string& id,
            const std::string& n,
            int qty,
            double p)
        : sku(id), name(n), quantity(qty), price(p) {}

    void restock(int amount) {
        if (amount > 0) {
            quantity += amount;
            std::cout << amount << " units added to " << sku << "\n";
        } else {
            std::cerr << "Invalid restock amount\n";
        }
    }

    bool sell(int amount) {
        if (amount > 0 && amount <= quantity) {
            quantity -= amount;
            std::cout << amount << " units sold from " << sku << "\n";
            return true;
        }
        std::cerr << "Sale failed: insufficient stock or invalid amount\n";
        return false;
    }

    void display() const {
        std::cout << "SKU: " << sku
                  << " | Name: " << name
                  << " | Qty: " << quantity
                  << " | Price: $" << price << "\n";
    }
};
InventoryManager Class :
// InventoryManager class
class InventoryManager {
    std::vector<std::unique_ptr<Product>> products;

public:
    bool productExists(const std::string& sku) const {
        return std::any_of(products.begin(), products.end(),
            [&](const auto& p) { return p->sku == sku; });
    }

    void addProduct(const std::string& sku,
                    const std::string& name,
                    int qty,
                    double price) {
        if (productExists(sku)) {
            std::cerr << "Product exists: " << sku << "\n";
            return;
        }
        if (qty < 0 || price < 0.0) {
            std::cerr << "Invalid initial quantity or price\n";
            return;
        }
        products.push_back(std::make_unique<Product>(sku, name, qty, price));
        std::cout << "Product " << sku << " added\n";
    }

    bool removeProduct(const std::string& sku) {
        auto it = std::remove_if(products.begin(), products.end(),
            [&](const auto& p) { return p->sku == sku; });
        if (it == products.end()) {
            std::cerr << "Product not found: " << sku << "\n";
            return false;
        }
        products.erase(it, products.end());
        std::cout << "Product " << sku << " removed\n";
        return true;
    }

    void restockProduct(const std::string& sku, int amount) {
        for (const auto& p : products) {
            if (p->sku == sku) { p->restock(amount); return; }
        }
        std::cerr << "Product not found: " << sku << "\n";
    }

    void sellProduct(const std::string& sku, int amount) {
        for (const auto& p : products) {
            if (p->sku == sku) { p->sell(amount); return; }
        }
        std::cerr << "Product not found: " << sku << "\n";
    }

    std::vector<Product*> getLowStockProducts(int threshold) {
        std::vector<Product*> result;
        for (const auto& p : products) {
            if (p->quantity < threshold) {
                result.push_back(p.get());
            }
        }
        return result;
    }

    void displayAllProducts() const {
        std::cout << "\n=== Inventory ===\n";
        for (const auto& p : products) p->display();
        std::cout << "=================\n";
    }
};
Example :
// Example usage
int main() {
    InventoryManager inv;
    inv.addProduct("A100", "Widget", 50, 2.99);
    inv.addProduct("B200", "Gadget", 20, 5.49);

    inv.sellProduct("A100", 5);
    inv.restockProduct("B200", 30);

    auto low = inv.getLowStockProducts(25);
    std::cout << "\nLow stock products:\n";
    for (auto* p : low) p->display();

    inv.displayAllProducts();
    return 0;
}

Detailed Explanation of Logic

The inventory manager maintains ownership of all Product instances in a std::vector<std::unique_ptr<Product>>. By using unique_ptr, each product’s lifetime is automatically tied to the container, eliminating manual new/delete calls. When a client calls addProduct, we first invoke productExists (using std::any_of) to check for duplicate SKUs; if none exist and the initial stock and price are valid, a new Product is created with std::make_unique and appended to the vector.

Removal uses std::remove_if to shift matching elements to the end based on SKU equality, then erases them, issuing feedback if no product was found. The sellProduct and restockProduct methods perform a simple linear search—dereferencing each unique pointer with p->—and call the corresponding Product methods to adjust quantity. These methods themselves validate input ranges (e.g., nonnegative restock, sufficient stock for sales), update the internal state, and print confirmation or error messages.

The reporting function getLowStockProducts demonstrates non-owning access: it iterates over the owned pointers, checks each quantity against the threshold, and collects raw Product* pointers via unique_ptr::get() into a result vector. This allows the caller to inspect or display these objects without altering ownership.

Finally, displayAllProducts loops through the catalog and invokes each product’s display method, cleanly separating data storage, mutation logic, and presentation. This layered design keeps responsibilities clear and leverages modern C++ features for safety and maintainability.

Similar Posts