Photo by Centre for Ageing Better on Unsplash
Business Problem: Inventory and Procurement Optimization
Scenario:
A mid-sized retail company, "RetailPro", is facing challenges in managing its inventory and procurement processes efficiently. The company operates multiple stores and warehouses, and it struggles with stockouts, overstocking, and delayed procurement decisions. These inefficiencies lead to increased holding costs, lost sales, and poor customer satisfaction.
Challenges:
Stock Imbalances:
Some stores face frequent stockouts, while others have excess inventory.
Slow-moving items take up storage space, while fast-moving items run out quickly.
Supplier Performance Issues:
Delays in supplier deliveries affect stock availability.
Lack of insights into supplier lead times and reliability.
Procurement Inefficiencies:
Poor demand forecasting leads to over-ordering or under-ordering.
Manual procurement tracking makes it hard to manage purchase orders effectively.
Cost Optimization:
High inventory holding costs due to excess stock.
Unnecessary procurement expenses due to inefficient order scheduling.
Solution: Power BI Dashboard for Inventory & Procurement Management
Key Insights the Dashboard Provides:
Inventory Overview:
Stock levels by product, store, and warehouse.
Fast-moving vs. slow-moving inventory.
Inventory aging report.
Procurement Insights:
Supplier performance analysis (lead times, on-time deliveries).
Purchase order tracking and status updates.
Procurement spend analysis.
Demand Forecasting & Stock Replenishment:
Predictive analytics for stock demand based on past sales trends.
Suggested reorder quantities and optimal stock levels.
Alerts for low-stock and overstock situations.
Cost & Efficiency Metrics:
Inventory turnover ratio.
Procurement cost trends.
Holding cost vs. stockout cost analysis.
Expected Business Benefits:
✅ Reduced Stockouts & Overstocking: Ensures optimal inventory levels across locations.
✅ Improved Supplier Performance: Identifies reliable suppliers and helps negotiate better terms.
✅ Better Procurement Decisions: Enables data-driven purchasing strategies.
✅ Cost Savings: Lowers storage costs and minimizes wastage.
✅ Enhanced Business Agility: Provides real-time insights for quick decision-making.
Implementation Steps:
Data Integration: Connect Power BI with inventory management, procurement, and sales systems.
Data Modeling: Structure data for better visualization and analysis.
Dashboard Creation: Develop interactive reports for stock levels, supplier performance, and procurement trends.
Deployment & Training: Implement in business operations and train teams to use the insights effectively.
Below is a Python script that generates a dummy Oracle database with relevant tables and populates each table with 1,000 records using numpy
for logic-based data creation. The script uses cx_Oracle
to connect to an Oracle database.
Prerequisites:
Install required libraries:
pip install cx_Oracle numpy pandas faker
Ensure you have an Oracle database running and update the connection details (
USERNAME
,PASSWORD
,HOST
,PORT
,SID/ServiceName
).The script creates the following tables:
Inventory: Stores stock levels and product details.
Suppliers: Contains supplier details and ratings.
Procurement: Tracks procurement orders and supplier transactions.
Sales: Logs product sales and demand trends.
Python Script for Generating and Inserting Dummy Data
import cx_Oracle
import numpy as np
import pandas as pd
from faker import Faker
import random
# Oracle DB Connection Parameters (Update these)
USERNAME = "your_username"
PASSWORD = "your_password"
HOST = "your_host"
PORT = "your_port"
SERVICE_NAME = "your_service_name"
# Establish Oracle Connection
dsn = cx_Oracle.makedsn(HOST, PORT, service_name=SERVICE_NAME)
conn = cx_Oracle.connect(USERNAME, PASSWORD, dsn)
cursor = conn.cursor()
# Faker Instance for Generating Fake Data
faker = Faker()
# Drop tables if they exist
tables = ["Inventory", "Suppliers", "Procurement", "Sales"]
for table in tables:
cursor.execute(f"BEGIN EXECUTE IMMEDIATE 'DROP TABLE {table}'; EXCEPTION WHEN OTHERS THEN NULL; END;")
# Create Tables
cursor.execute("""
CREATE TABLE Inventory (
Product_ID NUMBER PRIMARY KEY,
Product_Name VARCHAR2(100),
Category VARCHAR2(50),
Stock_Level NUMBER,
Warehouse_Location VARCHAR2(50),
Reorder_Threshold NUMBER
)
""")
cursor.execute("""
CREATE TABLE Suppliers (
Supplier_ID NUMBER PRIMARY KEY,
Supplier_Name VARCHAR2(100),
Contact VARCHAR2(50),
Location VARCHAR2(100),
Rating NUMBER(3,1)
)
""")
cursor.execute("""
CREATE TABLE Procurement (
Order_ID NUMBER PRIMARY KEY,
Product_ID NUMBER,
Supplier_ID NUMBER,
Quantity NUMBER,
Order_Date DATE,
Delivery_Date DATE,
Status VARCHAR2(20),
FOREIGN KEY (Product_ID) REFERENCES Inventory(Product_ID),
FOREIGN KEY (Supplier_ID) REFERENCES Suppliers(Supplier_ID)
)
""")
cursor.execute("""
CREATE TABLE Sales (
Sale_ID NUMBER PRIMARY KEY,
Product_ID NUMBER,
Quantity_Sold NUMBER,
Sale_Date DATE,
Customer_Location VARCHAR2(100),
FOREIGN KEY (Product_ID) REFERENCES Inventory(Product_ID)
)
""")
# Generate Dummy Data
categories = ["Electronics", "Furniture", "Clothing", "Groceries", "Toys"]
status_list = ["Pending", "Shipped", "Delivered", "Cancelled"]
# Insert Data into Inventory
inventory_data = []
for i in range(1000):
inventory_data.append((
i + 1,
faker.word().capitalize() + " " + random.choice(["Pro", "Max", "Ultra", "Basic"]),
random.choice(categories),
np.random.randint(10, 500),
faker.city(),
np.random.randint(5, 100)
))
cursor.executemany("INSERT INTO Inventory VALUES (:1, :2, :3, :4, :5, :6)", inventory_data)
# Insert Data into Suppliers
supplier_data = []
for i in range(1000):
supplier_data.append((
i + 1,
faker.company(),
faker.phone_number(),
faker.city(),
round(np.random.uniform(2.5, 5.0), 1)
))
cursor.executemany("INSERT INTO Suppliers VALUES (:1, :2, :3, :4, :5)", supplier_data)
# Insert Data into Procurement
procurement_data = []
for i in range(1000):
product_id = np.random.randint(1, 1001)
supplier_id = np.random.randint(1, 1001)
order_date = faker.date_this_year()
delivery_date = faker.date_between(start_date=order_date, end_date="+30d")
procurement_data.append((
i + 1,
product_id,
supplier_id,
np.random.randint(10, 500),
order_date,
delivery_date,
random.choice(status_list)
))
cursor.executemany("INSERT INTO Procurement VALUES (:1, :2, :3, :4, :5, :6, :7)", procurement_data)
# Insert Data into Sales
sales_data = []
for i in range(1000):
product_id = np.random.randint(1, 1001)
sale_date = faker.date_this_year()
sales_data.append((
i + 1,
product_id,
np.random.randint(1, 50),
sale_date,
faker.city()
))
cursor.executemany("INSERT INTO Sales VALUES (:1, :2, :3, :4, :5)", sales_data)
# Commit changes and close connection
conn.commit()
cursor.close()
conn.close()
print("Dummy data successfully inserted into Oracle database!")
Breakdown of the Script:
Connection to Oracle Database
- Uses
cx_Oracle
to connect using the provided credentials.
- Uses
Table Creation
- Drops existing tables (if they exist) and creates four tables:
Inventory
,Suppliers
,Procurement
, andSales
.
- Drops existing tables (if they exist) and creates four tables:
Data Generation (Using NumPy & Faker)
Uses
numpy
for generating random numbers logically.Uses
faker
for generating realistic names, locations, dates, and contact details.
Data Insertion
- Uses
executemany()
for bulk insertion (efficient for large datasets).
- Uses
Finalization
- Commits the transaction and closes the database connection.
Expected Outcome:
After running the script, your Oracle database will have:
Inventory Table: 1,000 records with stock levels and product details.
Suppliers Table: 1,000 records of supplier details.
Procurement Table: 1,000 records tracking purchase orders.
Sales Table: 1,000 records representing product sales.
Database Schema for Inventory & Procurement System
This document provides a detailed schema for the Inventory & Procurement System. It includes four tables: Inventory
, Suppliers
, Procurement
, and Sales
, along with column descriptions.
1. Inventory Table
Stores product details and stock levels across warehouses.
Column Name | Data Type | Constraints | Description |
Product_ID | NUMBER | PRIMARY KEY | Unique identifier for each product. |
Product_Name | VARCHAR2(100) | NOT NULL | Name of the product. |
Category | VARCHAR2(50) | NOT NULL | Category of the product (e.g., Electronics, Furniture). |
Stock_Level | NUMBER | NOT NULL | Current stock level for the product. |
Warehouse_Location | VARCHAR2(50) | NOT NULL | Warehouse where the product is stored. |
Reorder_Threshold | NUMBER | NOT NULL | Minimum stock level before reordering is needed. |
2. Suppliers Table
Stores information about suppliers providing inventory items.
Column Name | Data Type | Constraints | Description |
Supplier_ID | NUMBER | PRIMARY KEY | Unique identifier for each supplier. |
Supplier_Name | VARCHAR2(100) | NOT NULL | Name of the supplier company. |
Contact | VARCHAR2(50) | NOT NULL | Contact number of the supplier. |
Location | VARCHAR2(100) | NOT NULL | Supplier's location or headquarters. |
Rating | NUMBER(3,1) | CHECK (Rating BETWEEN 0 AND 5) | Supplier's performance rating (scale: 0 to 5). |
3. Procurement Table
Tracks procurement orders, linking products to suppliers.
Column Name | Data Type | Constraints | Description |
Order_ID | NUMBER | PRIMARY KEY | Unique identifier for each procurement order. |
Product_ID | NUMBER | FOREIGN KEY → Inventory(Product_ID) | Product being procured. |
Supplier_ID | NUMBER | FOREIGN KEY → Suppliers(Supplier_ID) | Supplier providing the product. |
Quantity | NUMBER | NOT NULL | Quantity of items ordered. |
Order_Date | DATE | NOT NULL | Date the order was placed. |
Delivery_Date | DATE | NULLABLE | Expected or actual delivery date. |
Status | VARCHAR2(20) | CHECK (Status IN ('Pending', 'Shipped', 'Delivered', 'Cancelled')) | Order processing status. |
4. Sales Table
Records product sales transactions.
Column Name | Data Type | Constraints | Description |
Sale_ID | NUMBER | PRIMARY KEY | Unique identifier for each sale transaction. |
Product_ID | NUMBER | FOREIGN KEY → Inventory(Product_ID) | Product that was sold. |
Quantity_Sold | NUMBER | NOT NULL | Number of units sold. |
Sale_Date | DATE | NOT NULL | Date of the sale transaction. |
Customer_Location | VARCHAR2(100) | NOT NULL | Location of the customer making the purchase. |
Relationships Between Tables
Inventory(Product_ID)
→Procurement(Product_ID)
(One-to-Many)- A product can have multiple procurement orders.
Suppliers(Supplier_ID)
→Procurement(Supplier_ID)
(One-to-Many)- A supplier can provide multiple products in procurement.
Inventory(Product_ID)
→Sales(Product_ID)
(One-to-Many)- A product can have multiple sales transactions.
Additional Features for Optimization
Indexes:
Create indexes on
Product_ID
andSupplier_ID
for faster joins.Index
Order_Date
andSale_Date
for efficient date-based queries.
Constraints & Validation:
CHECK
constraints onRating
(between 0 and 5) andStatus
(enum values).NOT NULL
constraints on essential fields to ensure data integrity.
PowerBI Dashboard Ideas
I'll create a comprehensive Power BI dashboard design document for the RetailPro inventory and procurement management system, including suggested charts, KPIs, and DAX queries.
RetailPro Inventory & Procurement Management Dashboard - Design Document
1. Dashboard Overview
This Power BI solution will address RetailPro's inventory and procurement challenges by providing real-time insights across four key areas:
Inventory Management
Supplier Performance
Procurement Analytics
Sales & Demand Analysis
2. Data Model Structure
Connect to the Oracle database and create the following relationships:
Inventory(Product_ID) ↔ Procurement(Product_ID)
Suppliers(Supplier_ID) ↔ Procurement(Supplier_ID)
Inventory(Product_ID) ↔ Sales(Product_ID)
Calculated Tables
Create a Date dimension table:
Date = CALENDAR(MIN(Sales[Sale_Date]), MAX(Procurement[Delivery_Date]))
3. Key Performance Indicators (KPIs)
Inventory KPIs
Current Stock Value
Total Stock Value = SUMX(Inventory, Inventory[Stock_Level] * RELATED(Products[Unit_Cost]))
Stock Turnover Ratio
Stock Turnover = DIVIDE( CALCULATE(SUM(Sales[Quantity_Sold]), ALL(Date)), AVERAGEX( VALUES(Date[Month]), CALCULATE(SUM(Inventory[Stock_Level])) ) )
Stock Below Threshold %
Stock Below Threshold % = DIVIDE( COUNTROWS(FILTER(Inventory, Inventory[Stock_Level] < Inventory[Reorder_Threshold])), COUNTROWS(Inventory) )
Supplier KPIs
Average Supplier Rating
Avg Supplier Rating = AVERAGE(Suppliers[Rating])
On-Time Delivery %
On-Time Delivery % = DIVIDE( COUNTROWS(FILTER(Procurement, Procurement[Delivery_Date] <= Procurement[Order_Date] + 7)), COUNTROWS(Procurement) )
Average Lead Time (Days)
Avg Lead Time = AVERAGEX( Procurement, DATEDIFF(Procurement[Order_Date], Procurement[Delivery_Date], DAY) )
Procurement KPIs
Total Procurement Spend
Total Procurement Spend = SUMX( Procurement, Procurement[Quantity] * RELATED(Inventory[Unit_Cost]) )
Open Orders Count
Open Orders = COUNTROWS(FILTER(Procurement, Procurement[Status] = "Pending" || Procurement[Status] = "Shipped"))
Average Order Quantity
Avg Order Quantity = AVERAGE(Procurement[Quantity])
Sales KPIs
Total Sales Quantity
Total Sales Quantity = SUM(Sales[Quantity_Sold])
Sales Growth MoM %
Sales Growth MoM % = VAR CurrentMonthSales = CALCULATE(SUM(Sales[Quantity_Sold]), DATESMTD(Date[Date])) VAR PreviousMonthSales = CALCULATE(SUM(Sales[Quantity_Sold]), DATEADD(DATESMTD(Date[Date]), -1, MONTH)) RETURN DIVIDE(CurrentMonthSales - PreviousMonthSales, PreviousMonthSales)
Stock Coverage (Days)
Stock Coverage = DIVIDE( SUM(Inventory[Stock_Level]), CALCULATE( AVERAGE(Sales[Quantity_Sold]), LASTDATE(Date[Date]) - 30 ) )
4. Dashboard Pages and Visualizations
4.1. Executive Overview Page
Visualizations:
Card visuals for top KPIs:
Total Stock Value
Stock Turnover Ratio
Average Supplier Rating
Total Procurement Spend
Total Sales Quantity
Trend line chart: Stock value vs. Sales quantity over time
Gauge visual: Stock below threshold %
Top/Bottom chart: Top 5 performing suppliers by rating
4.2. Inventory Management Page
Visualizations:
Stacked column chart: Stock levels by category and warehouse
Heat map: Products by stock level vs. reorder threshold
Table: Low stock items (below threshold)
Donut chart: Inventory distribution by category
Line chart: Stock level trends over time
DAX Queries:
Low Stock Items =
FILTER(
SUMMARIZE(
Inventory,
Inventory[Product_ID],
Inventory[Product_Name],
Inventory[Category],
Inventory[Stock_Level],
Inventory[Reorder_Threshold]
),
Inventory[Stock_Level] < Inventory[Reorder_Threshold]
)
4.3. Supplier Performance Page
Visualizations:
Scatter plot: Suppliers by rating vs. lead time
Column chart: On-time delivery % by supplier (top 10)
Card visuals: Avg lead time, On-time delivery %, Avg supplier rating
Table: Supplier details with ratings and performance metrics
Line chart: Supplier rating trends over time
DAX Queries:
Supplier Performance =
SUMMARIZE(
Procurement,
Suppliers[Supplier_ID],
Suppliers[Supplier_Name],
Suppliers[Rating],
"Lead Time", AVERAGEX(
RELATEDTABLE(Procurement),
DATEDIFF(Procurement[Order_Date], Procurement[Delivery_Date], DAY)
),
"On-Time %", DIVIDE(
COUNTX(
FILTER(
RELATEDTABLE(Procurement),
Procurement[Delivery_Date] <= Procurement[Order_Date] + 7
),
1
),
COUNTX(RELATEDTABLE(Procurement), 1)
)
)
4.4. Procurement Analytics Page
Visualizations:
Stacked bar chart: Orders by status and supplier
Line and clustered column chart: Order quantity and spend over time
Pie chart: Orders by status
Table: Recent orders with status and details
Area chart: Cumulative procurement spend
DAX Queries:
Procurement Trends =
SUMMARIZE(
Procurement,
Date[Month],
"Order Count", COUNTROWS(Procurement),
"Total Quantity", SUM(Procurement[Quantity]),
"Total Spend", SUMX(
Procurement,
Procurement[Quantity] * RELATED(Inventory[Unit_Cost])
)
)
4.5. Sales & Demand Analysis Page
Visualizations:
Column chart: Sales quantity by product category
Line chart: Sales trends over time
Map: Sales by customer location
Decomposition tree: Analyze sales by hierarchies
Forecast chart: Predict future sales based on historical data
DAX Queries:
Sales by Location and Category =
SUMMARIZE(
Sales,
Sales[Customer_Location],
Inventory[Category],
"Total Quantity Sold", SUM(Sales[Quantity_Sold]),
"Sale Count", COUNTROWS(Sales)
)
5. Slicers and Filters
Include the following slicers for interactive filtering:
Date range
Product category
Warehouse location
Supplier
Order status
6. Advanced Analytics Features
6.1. Forecasting
Set up time series forecasting for:
Stock demand based on sales history
Supplier delivery times
Procurement spend
6.2. Anomaly Detection
Configure anomaly detection to identify:
Unusual stock movements
Unexpected supplier delays
Abnormal sales patterns
7. Dashboard Refresh Schedule
Configure automatic refresh:
Main KPIs: Every 4 hours
Detailed reports: Daily at midnight
Executive summary: Weekly on Monday mornings
8. Implementation Steps
Connect to Oracle database using the provided credentials
Create the data model with proper relationships
Develop calculated measures and tables using the provided DAX queries
Build visualizations as outlined in each dashboard page
Set up slicers and filters for interactive analysis
Configure refresh schedules
Test dashboard with sample scenarios
Deploy to Power BI service for user access
9. User Roles and Permissions
Configure the following access levels:
Executives: View-only access to all pages
Inventory Managers: Edit access to Inventory Management page
Procurement Team: Edit access to Supplier and Procurement pages
Sales Team: Edit access to Sales & Demand page
10. Custom Visuals Required
KPI cards with trend indicators
Inventory heat map
Supplier performance scorecard
Power KPI custom visual for threshold monitoring
11. Mobile View Configuration
Optimize the Executive Overview page for mobile viewing with:
Simplified card visuals
Responsive charts
Touch-friendly filters
This comprehensive dashboard will provide RetailPro with the insights needed to optimize inventory levels, improve supplier relationships, streamline procurement processes, and align stock with customer demand
More ideas and theory to learn
RetailPro Inventory & Procurement Dashboard: Real-World Benefits
What This Dashboard Does in Simple Terms
This Power BI dashboard takes all the data from RetailPro's systems and turns it into easy-to-understand visuals that help staff make better decisions about inventory and purchasing. Here's what it does and why it matters:
1. Shows What's in Stock and Where
What it does: Shows current inventory levels across all stores and warehouses.
Real-world benefit: Store managers can quickly see when they're running low on popular items so customers don't leave disappointed. It prevents the frustration of one store being out of stock while another has too many of the same item.
2. Highlights Which Suppliers Are Reliable
What it does: Rates suppliers based on on-time deliveries and overall performance.
Real-world benefit: When managers know which suppliers consistently deliver late, they can place orders earlier or find better alternatives. This means fewer empty shelves and happier customers.
3. Tracks Spending on Inventory
What it does: Shows how much money is being spent on ordering products.
Real-world benefit: Helps prevent overspending on inventory that sits unsold. The company saves money that can be used for other needs like hiring staff or improving stores.
4. Predicts What Customers Will Want
What it does: Analyzes past sales to predict future demand.
Real-world benefit: Stores can stock up on items before they're needed. For example, if sales data shows umbrellas always sell out when rainy season starts, managers can order more in advance.
5. Alerts When Stock Is Running Low
What it does: Sends notifications when products drop below minimum levels.
Real-world benefit: Prevents the disappointing "sorry, we're out of stock" conversation with customers. Automatic alerts mean items get reordered before they run out.
How It Helps Different People at RetailPro
For Store Managers:
Spend less time checking stock and more time helping customers
Know exactly when orders will arrive
Make smarter decisions about what to display and promote
For the Procurement Team:
Easily see which suppliers deliver on time
Know exactly what needs to be ordered and when
Reduce paperwork and manual tracking
For Executives:
See how the business is performing at a glance
Identify problems before they affect sales
Make better decisions about where to invest
For Customers (even though they don't see the dashboard):
Find the products they want in stock
Experience fewer delays and out-of-stock situations
Get better service because staff have the information they need
The Bottom Line
This dashboard takes complex data and turns it into actionable insights that help RetailPro:
Keep the right products in stock
Save money by not over-ordering
Work with reliable suppliers
Meet customer needs more effectively
Instead of guessing or using outdated information, staff at all levels can make confident decisions based on up-to-date data, ultimately creating a better shopping experience for customers while improving the company's profitability.