Inventory Dashboard:-Managing inventory is one of the most important tasks for any business. Whether you run a retail store, warehouse, manufacturing unit, or small business, keeping track of stock levels, sales performance, inventory value, and product movement is critical for making informed decisions.
The challenge is that most businesses still rely on manual Excel reports. Creating Pivot Tables, formatting reports, building charts, calculating KPIs, and preparing dashboards can easily consume hours every week. Even a small change in the source data often requires repeating the same tasks again and again.
What if all of this could be automated?
In this project, I created a fully automated Inventory Dashboard using Excel VBA that transforms raw data into a professional business dashboard in just 25 seconds. With a single click, the system formats data, creates Pivot Tables, generates charts, calculates key metrics, and builds an executive-ready dashboard automatically.
Let’s explore how this dashboard works and why VBA automation can completely change the way businesses analyze inventory data.
Why Traditional Inventory Reporting Is Inefficient
Many organizations still prepare inventory reports manually. The typical process involves:
- Cleaning raw data
- Creating multiple Pivot Tables
- Calculating inventory values
- Building charts
- Designing dashboard layouts
- Formatting reports
- Updating reports whenever new data arrives
This process is not only time-consuming but also increases the risk of human error.
Managers need information quickly. Waiting hours to generate reports can delay important business decisions such as stock replenishment, purchasing, and sales planning.
This is where automation becomes a game changer.
The Goal of This VBA Dashboard
The primary goal of this project was simple:
Convert raw inventory data into a professional dashboard automatically with a single click.
Instead of spending hours building reports, users simply press a button and allow VBA to perform all repetitive tasks automatically.
The dashboard was designed to help businesses answer important questions such as:
- What is the current inventory value?
- Which products are running low?
- Which products are selling the most?
- How do purchases compare with sales?
- Which categories generate the highest revenue?
- Where should management focus attention?
All these insights become available within seconds.
VBA Code Download
Option Explicit
'==============================================================
' INVENTORY MANAGEMENT DASHBOARD - ERP v2 (Premium UI)
'==============================================================
Private Const SH_DATA As String = "InventoryData"
Private Const SH_PIVOT As String = "Pivot"
Private Const SH_DASH As String = "Dashboard"
Private Const SH_SETTINGS As String = "Settings"
Private Const SH_AUDIT As String = "AuditTrail"
Private Const C_BG As Long = 16381425
Private Const C_NAVY As Long = 3810072
Private Const C_DKNAVY As Long = 2758673
Private Const C_WHITE As Long = 16777215
Private Const C_BORDER As Long = 15788258
Private Const C_TEXT As Long = 3877150
Private Const C_GREYTXT As Long = 9139300
Private Const C_LGREY As Long = 16579320
Private Const C_DGREY As Long = 6903111
Private Const C_BLUE As Long = 15426341
Private Const C_GREEN As Long = 4891414
Private Const C_RED As Long = 2500316
Private Const C_ORANGE As Long = 809194
Private Const C_PURPLE As Long = 15547004
Private Const C_TEAL As Long = 8950797
Private Const C_GOLD As Long = 423897
Private Const C_ALRTRED As Long = 14869246
Private Const C_ALRTAMB As Long = 13497343
Private Const C_ALRTGRN As Long = 15203548
Private Const C_ALRTREDT As Long = 1776537
Private Const C_ALRTAMBT As Long = 934034
Private Const C_ALRTGRNT As Long = 3433750
Private Const PAUSE_SHORT As Long = 200
Private Const PAUSE_MED As Long = 450
Private Const PAUSE_LONG As Long = 800
Private Const PAUSE_PIVOT As Long = 350
Private Const PAUSE_CHART As Long = 500
Private Const PAUSE_KPI As Long = 300
Private Const PAUSE_ALERT As Long = 250
'==============================================================
' TIMING HELPERS
'==============================================================
Private Sub WaitMs(ByVal ms As Long)
Dim t As Single
t = Timer
Do While (Timer - t) * 1000 < ms
DoEvents
Loop
End Sub
Private Sub ShowBar(ByVal step As Integer, ByVal total As Integer, ByVal msg As String)
Dim bar As String
Dim i As Integer
Dim filled As Integer
filled = Int((CDbl(step) / CDbl(total)) * 12)
bar = "|"
For i = 1 To 12
If i <= filled Then bar = bar & "##" Else bar = bar & "--"
Next i
bar = bar & "|"
Application.StatusBar = bar & " Step " & step & "/" & total & " " & msg
DoEvents
End Sub
'==============================================================
' MAIN ENTRY POINT
'==============================================================
Public Sub BuildInventoryDashboard()
Dim T As Double
T = Timer
On Error GoTo ErrHandler
Application.ScreenUpdating = True
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Application.DisplayAlerts = False
ShowBar 1, 5, "Preparing data sheet..."
WaitMs PAUSE_MED
Call PrepareDataSheet
WaitMs PAUSE_LONG
ShowBar 2, 5, "Building pivot analysis..."
WaitMs PAUSE_MED
Call BuildPivotSheet
WaitMs PAUSE_LONG
ShowBar 3, 5, "Building dashboard..."
WaitMs PAUSE_MED
Call BuildDashboardSheet
WaitMs PAUSE_LONG
ShowBar 4, 5, "Settings & Audit..."
WaitMs PAUSE_MED
Call BuildSettingsSheet
WaitMs PAUSE_SHORT
Call BuildAuditSheet
WaitMs PAUSE_SHORT
Call AddAuditRow("BUILD", "Dashboard built by " & Environ("USERNAME"))
ShowBar 5, 5, "Done!"
WaitMs PAUSE_MED
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.DisplayAlerts = True
Sheets(SH_DASH).Activate
Range("A1").Select
WaitMs PAUSE_LONG
Application.StatusBar = "Dashboard ready! Built in " & Format(Timer - T, "0.0") & "s"
MsgBox "Dashboard Built Successfully!" & vbCrLf & _
"Time: " & Format(Timer - T, "0.0") & " seconds", _
vbInformation, "Inventory ERP v2"
Exit Sub
ErrHandler:
Application.ScreenUpdating = True
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.DisplayAlerts = True
Application.StatusBar = False
MsgBox "ERROR: " & Err.Description & vbCrLf & "Line: " & Erl, _
vbCritical, "Inventory ERP v2"
End Sub
'==============================================================
' STEP 1 - PREPARE DATA SHEET
'==============================================================
Private Sub PrepareDataSheet()
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(SH_DATA)
On Error GoTo 0
Application.StatusBar = "Step 1/5 Locating data sheet..."
DoEvents
WaitMs PAUSE_SHORT
If ws Is Nothing Then
Dim s As Worksheet
For Each s In ThisWorkbook.Sheets
If s.Cells(1, 1).Value = "Item ID" Then
s.Name = SH_DATA
Set ws = s
Exit For
End If
Next s
End If
If ws Is Nothing Then
Set ws = Sheets.Add(Before:=Sheets(1))
ws.Name = SH_DATA
End If
ws.Activate
WaitMs PAUSE_MED
Application.StatusBar = "Step 1/5 Styling header row..."
DoEvents
ws.Tab.Color = C_NAVY
Dim hdr As Range
Set hdr = ws.Range("A1:O1")
With hdr
.Font.Bold = True
.Font.Color = C_WHITE
.Font.Size = 10
.Font.Name = "Calibri"
.Interior.Color = C_NAVY
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.RowHeight = 30
End With
DoEvents
WaitMs PAUSE_MED
Dim lastR As Long
lastR = GetLastRow(ws)
If lastR > 1 Then
Application.StatusBar = "Step 1/5 Formatting columns..."
DoEvents
ws.Range("G2:M" & lastR).NumberFormat = "#,##0.00"
ws.Range("N2:N" & lastR).NumberFormat = "dd-mmm-yyyy"
DoEvents
WaitMs PAUSE_SHORT
Application.StatusBar = "Step 1/5 Auto-fitting columns..."
DoEvents
ws.Columns("A:O").AutoFit
ws.Columns("B").ColumnWidth = 20
DoEvents
WaitMs PAUSE_SHORT
Application.StatusBar = "Step 1/5 Creating Excel Table..."
DoEvents
If ws.ListObjects.Count = 0 Then
Dim tbl As ListObject
Set tbl = ws.ListObjects.Add(xlSrcRange, _
ws.Range("A1:O" & lastR), , xlYes)
tbl.Name = "tblInv"
tbl.TableStyle = "TableStyleMedium2"
End If
DoEvents
WaitMs PAUSE_MED
ws.Activate
ActiveWindow.FreezePanes = False
ws.Cells(2, 1).Select
ActiveWindow.FreezePanes = True
WaitMs PAUSE_SHORT
End If
End Sub
'==============================================================
' STEP 2 - PIVOT SHEET
' NOTE: All KPI values are stored in named helper cells
' so Dashboard reads from Pivot (not raw data)
'==============================================================
Private Sub BuildPivotSheet()
Dim ws As Worksheet
Dim src As Worksheet
Set ws = GetSheet(SH_PIVOT)
Set src = Sheets(SH_DATA)
ws.Cells.Clear
ws.Tab.Color = C_BLUE
ws.Cells.Font.Name = "Calibri"
ws.Cells.Font.Size = 9
Dim srcName As String
srcName = src.Name
Dim lastR As Long
lastR = GetLastRow(src)
ws.Activate
WaitMs PAUSE_MED
'--- BLOCK 1: Stock by Category ---
Application.StatusBar = "Step 2/5 Building: Stock by Category..."
DoEvents
WritePivotTitle ws, 1, 1, "STOCK SUMMARY BY CATEGORY"
ws.Cells(2, 1).Value = "Category"
ws.Cells(2, 2).Value = "Items"
ws.Cells(2, 3).Value = "Stock In"
ws.Cells(2, 4).Value = "Stock Out"
ws.Cells(2, 5).Value = "Current Stock"
ws.Cells(2, 6).Value = "Stock Value"
StylePivHead ws, 2, 1, 6
Dim cats As Variant
cats = Array("Electronics", "Furniture", "IT Accessories", "Office Supplies", "Safety")
Dim r As Long
Dim i As Integer
r = 3
For i = 0 To UBound(cats)
ws.Cells(r, 1).Value = cats(i)
ws.Cells(r, 2).Formula = "=COUNTIF('" & srcName & "'!C:C,A" & r & ")"
ws.Cells(r, 3).Formula = "=SUMIF('" & srcName & "'!C:C,A" & r & ",'" & srcName & "'!H:H)"
ws.Cells(r, 4).Formula = "=SUMIF('" & srcName & "'!C:C,A" & r & ",'" & srcName & "'!I:I)"
ws.Cells(r, 5).Formula = "=SUMIF('" & srcName & "'!C:C,A" & r & ",'" & srcName & "'!J:J)"
ws.Cells(r, 6).Formula = "=SUMIF('" & srcName & "'!C:C,A" & r & ",'" & srcName & "'!M:M)"
ws.Range(ws.Cells(r, 3), ws.Cells(r, 6)).NumberFormat = "#,##0"
If r Mod 2 = 0 Then ws.Range(ws.Cells(r, 1), ws.Cells(r, 6)).Interior.Color = C_LGREY
r = r + 1
Next i
ws.Cells(r, 1).Value = "TOTAL"
ws.Cells(r, 2).Formula = "=SUM(B3:B" & r - 1 & ")"
ws.Cells(r, 3).Formula = "=SUM(C3:C" & r - 1 & ")"
ws.Cells(r, 4).Formula = "=SUM(D3:D" & r - 1 & ")"
ws.Cells(r, 5).Formula = "=SUM(E3:E" & r - 1 & ")"
ws.Cells(r, 6).Formula = "=SUM(F3:F" & r - 1 & ")"
ws.Range(ws.Cells(r, 3), ws.Cells(r, 6)).NumberFormat = "#,##0"
StyleTotRow ws, r, 1, 6
DoEvents
WaitMs PAUSE_PIVOT
'--- BLOCK 2: Stock by Warehouse ---
Application.StatusBar = "Step 2/5 Building: Stock by Warehouse..."
DoEvents
WritePivotTitle ws, 1, 8, "STOCK SUMMARY BY WAREHOUSE"
ws.Cells(2, 8).Value = "Warehouse"
ws.Cells(2, 9).Value = "Items"
ws.Cells(2, 10).Value = "Current Stock"
ws.Cells(2, 11).Value = "Stock Value"
StylePivHead ws, 2, 8, 11
Dim whs As Variant
whs = Array("Bangalore WH", "Chennai WH", "Delhi WH", "Mumbai WH", "Pune WH")
r = 3
For i = 0 To UBound(whs)
ws.Cells(r, 8).Value = whs(i)
ws.Cells(r, 9).Formula = "=COUNTIF('" & srcName & "'!E:E,H" & r & ")"
ws.Cells(r, 10).Formula = "=SUMIF('" & srcName & "'!E:E,H" & r & ",'" & srcName & "'!J:J)"
ws.Cells(r, 11).Formula = "=SUMIF('" & srcName & "'!E:E,H" & r & ",'" & srcName & "'!M:M)"
ws.Range(ws.Cells(r, 9), ws.Cells(r, 11)).NumberFormat = "#,##0"
If r Mod 2 = 0 Then ws.Range(ws.Cells(r, 8), ws.Cells(r, 11)).Interior.Color = C_LGREY
r = r + 1
Next i
ws.Cells(r, 8).Value = "TOTAL"
ws.Cells(r, 9).Formula = "=SUM(I3:I" & r - 1 & ")"
ws.Cells(r, 10).Formula = "=SUM(J3:J" & r - 1 & ")"
ws.Cells(r, 11).Formula = "=SUM(K3:K" & r - 1 & ")"
ws.Range(ws.Cells(r, 9), ws.Cells(r, 11)).NumberFormat = "#,##0"
StyleTotRow ws, r, 8, 11
DoEvents
WaitMs PAUSE_PIVOT
'--- BLOCK 3: Supplier Analysis ---
Application.StatusBar = "Step 2/5 Building: Supplier Analysis..."
DoEvents
WritePivotTitle ws, 1, 13, "SUPPLIER ANALYSIS"
ws.Cells(2, 13).Value = "Supplier"
ws.Cells(2, 14).Value = "Items"
ws.Cells(2, 15).Value = "Stock In"
ws.Cells(2, 16).Value = "Stock Value"
StylePivHead ws, 2, 13, 16
Dim supps As Variant
supps = Array("ABC Traders", "Elite Distributors", "Global Supply", "Prime Industries", "Tech Source")
r = 3
For i = 0 To UBound(supps)
ws.Cells(r, 13).Value = supps(i)
ws.Cells(r, 14).Formula = "=COUNTIF('" & srcName & "'!F:F,M" & r & ")"
ws.Cells(r, 15).Formula = "=SUMIF('" & srcName & "'!F:F,M" & r & ",'" & srcName & "'!H:H)"
ws.Cells(r, 16).Formula = "=SUMIF('" & srcName & "'!F:F,M" & r & ",'" & srcName & "'!M:M)"
ws.Range(ws.Cells(r, 14), ws.Cells(r, 16)).NumberFormat = "#,##0"
If r Mod 2 = 0 Then ws.Range(ws.Cells(r, 13), ws.Cells(r, 16)).Interior.Color = C_LGREY
r = r + 1
Next i
ws.Cells(r, 13).Value = "TOTAL"
ws.Cells(r, 14).Formula = "=SUM(N3:N" & r - 1 & ")"
ws.Cells(r, 15).Formula = "=SUM(O3:O" & r - 1 & ")"
ws.Cells(r, 16).Formula = "=SUM(P3:P" & r - 1 & ")"
ws.Range(ws.Cells(r, 14), ws.Cells(r, 16)).NumberFormat = "#,##0"
StyleTotRow ws, r, 13, 16
DoEvents
WaitMs PAUSE_PIVOT
'--- BLOCK 4: Monthly Trend ---
Application.StatusBar = "Step 2/5 Building: Monthly Trend..."
DoEvents
WritePivotTitle ws, 14, 1, "MONTHLY INVENTORY TREND"
ws.Cells(15, 1).Value = "Month"
ws.Cells(15, 2).Value = "Stock In"
ws.Cells(15, 3).Value = "Stock Out"
ws.Cells(15, 4).Value = "Net Movement"
ws.Cells(15, 5).Value = "Stock Value"
StylePivHead ws, 15, 1, 5
Dim mths As Variant
mths = Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", _
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
r = 16
For i = 0 To 11
ws.Cells(r, 1).Value = mths(i)
ws.Cells(r, 2).Formula = "=SUMIF('" & srcName & "'!O:O,A" & r & ",'" & srcName & "'!H:H)"
ws.Cells(r, 3).Formula = "=SUMIF('" & srcName & "'!O:O,A" & r & ",'" & srcName & "'!I:I)"
ws.Cells(r, 4).Formula = "=B" & r & "-C" & r
ws.Cells(r, 5).Formula = "=SUMIF('" & srcName & "'!O:O,A" & r & ",'" & srcName & "'!M:M)"
ws.Range(ws.Cells(r, 2), ws.Cells(r, 5)).NumberFormat = "#,##0"
If r Mod 2 = 0 Then ws.Range(ws.Cells(r, 1), ws.Cells(r, 5)).Interior.Color = C_LGREY
r = r + 1
Next i
ws.Cells(r, 1).Value = "TOTAL"
ws.Cells(r, 2).Formula = "=SUM(B16:B" & r - 1 & ")"
ws.Cells(r, 3).Formula = "=SUM(C16:C" & r - 1 & ")"
ws.Cells(r, 4).Formula = "=SUM(D16:D" & r - 1 & ")"
ws.Cells(r, 5).Formula = "=SUM(E16:E" & r - 1 & ")"
ws.Range(ws.Cells(r, 2), ws.Cells(r, 5)).NumberFormat = "#,##0"
StyleTotRow ws, r, 1, 5
DoEvents
WaitMs PAUSE_PIVOT
'--- BLOCK 5: Low Stock Alert List ---
Application.StatusBar = "Step 2/5 Building: Low Stock Alert List..."
DoEvents
WritePivotTitle ws, 14, 8, "LOW STOCK ALERT LIST"
ws.Cells(15, 8).Value = "Item ID"
ws.Cells(15, 9).Value = "Item Name"
ws.Cells(15, 10).Value = "Category"
ws.Cells(15, 11).Value = "Warehouse"
ws.Cells(15, 12).Value = "Current Stock"
ws.Cells(15, 13).Value = "Reorder Level"
ws.Cells(15, 14).Value = "Shortage"
StylePivHead ws, 15, 8, 14
Dim srcWs As Worksheet
Set srcWs = Sheets(SH_DATA)
r = 16
Dim j As Long
Dim cs As Double
Dim rl As Double
For j = 2 To lastR
cs = Val(srcWs.Cells(j, 10).Value)
rl = Val(srcWs.Cells(j, 11).Value)
If rl > 0 And cs <= rl Then
ws.Cells(r, 8).Value = srcWs.Cells(j, 1).Value
ws.Cells(r, 9).Value = srcWs.Cells(j, 2).Value
ws.Cells(r, 10).Value = srcWs.Cells(j, 3).Value
ws.Cells(r, 11).Value = srcWs.Cells(j, 5).Value
ws.Cells(r, 12).Value = cs
ws.Cells(r, 13).Value = rl
ws.Cells(r, 14).Value = rl - cs
If cs = 0 Then
ws.Range(ws.Cells(r, 8), ws.Cells(r, 14)).Interior.Color = C_ALRTRED
Else
ws.Range(ws.Cells(r, 8), ws.Cells(r, 14)).Interior.Color = C_ALRTAMB
End If
r = r + 1
End If
Next j
If r = 16 Then ws.Cells(16, 8).Value = "No low-stock items found."
DoEvents
WaitMs PAUSE_PIVOT
'==============================================================
' KPI HELPER CELLS — Row 32 onwards, col A
' Dashboard reads from HERE (Pivot) not from raw data
'==============================================================
Application.StatusBar = "Step 2/5 Writing KPI helper values..."
DoEvents
' Find actual last data row dynamically
Dim dLastR As Long
dLastR = GetLastRow(srcWs)
' KPI labels in col A, formulas in col B (row 32+)
ws.Cells(32, 1).Value = "KPI_LABEL"
ws.Cells(32, 2).Value = "KPI_VALUE"
With ws.Range("A32:B32")
.Interior.Color = C_NAVY
.Font.Color = C_WHITE
.Font.Bold = True
End With
' KPI 1 - Total Stock Value
ws.Cells(33, 1).Value = "Total Stock Value"
ws.Cells(33, 2).Formula = "=SUM(F3:F7)"
ws.Cells(33, 2).NumberFormat = "#,##0"
' KPI 2 - Total SKUs
ws.Cells(34, 1).Value = "Total SKUs"
ws.Cells(34, 2).Formula = "=SUM(B3:B7)"
ws.Cells(34, 2).NumberFormat = "#,##0"
' KPI 3 - Low Stock Count
ws.Cells(35, 1).Value = "Low Stock Count"
ws.Cells(35, 2).Formula = "=SUMPRODUCT(('" & srcName & "'!J2:J" & dLastR & "<='" & srcName & "'!K2:K" & dLastR & ")*('" & srcName & "'!K2:K" & dLastR & ">0))"
ws.Cells(35, 2).NumberFormat = "#,##0"
' KPI 4 - Out of Stock Count
ws.Cells(36, 1).Value = "Out of Stock"
ws.Cells(36, 2).Formula = "=COUNTIF('" & srcName & "'!J2:J" & dLastR & ",0)"
ws.Cells(36, 2).NumberFormat = "#,##0"
' KPI 5 - Total Warehouses
ws.Cells(37, 1).Value = "Total Warehouses"
ws.Cells(37, 2).Formula = "=COUNTA(H3:H7)"
ws.Cells(37, 2).NumberFormat = "#,##0"
' KPI 6 - Total Suppliers
ws.Cells(38, 1).Value = "Total Suppliers"
ws.Cells(38, 2).Formula = "=COUNTA(M3:M7)"
ws.Cells(38, 2).NumberFormat = "#,##0"
' KPI 7 - Avg Item Value
ws.Cells(39, 1).Value = "Avg Item Value"
ws.Cells(39, 2).Formula = "=IFERROR(B33/B34,0)"
ws.Cells(39, 2).NumberFormat = "#,##0"
' KPI 8 - Total Stock In
ws.Cells(40, 1).Value = "Total Stock In"
ws.Cells(40, 2).Formula = "=SUM(C3:C7)"
ws.Cells(40, 2).NumberFormat = "#,##0"
' KPI 9 - Total Current Stock
ws.Cells(41, 1).Value = "Total Current Stock"
ws.Cells(41, 2).Formula = "=SUM(E3:E7)"
ws.Cells(41, 2).NumberFormat = "#,##0"
' KPI 10 - Inventory Turnover
ws.Cells(42, 1).Value = "Inventory Turnover"
ws.Cells(42, 2).Formula = "=IFERROR(B40/IFERROR(B33/B34,1),0)"
ws.Cells(42, 2).NumberFormat = "0.00"
ws.Columns("A:P").AutoFit
ws.Columns("I").ColumnWidth = 22
WaitMs PAUSE_MED
End Sub
'==============================================================
' STEP 3 - DASHBOARD SHEET
' All KPIs now read from Pivot sheet helper cells (B33:B42)
'==============================================================
Private Sub BuildDashboardSheet()
Dim ws As Worksheet
Dim src As Worksheet
Dim pvt As Worksheet
Set ws = GetSheet(SH_DASH)
Set src = Sheets(SH_DATA)
Set pvt = Sheets(SH_PIVOT)
ws.Cells.Clear
Dim shp As Shape
For Each shp In ws.Shapes
shp.Delete
Next shp
ws.Activate
ws.Tab.Color = C_NAVY
ws.Cells.Interior.Color = C_BG
ws.Cells.Font.Name = "Calibri"
ws.Cells.Font.Color = C_TEXT
DoEvents
WaitMs PAUSE_MED
Dim win As Window
For Each win In ThisWorkbook.Windows
win.DisplayGridlines = False
Next win
ws.Columns("A").ColumnWidth = 1.5
Dim c As Long
For c = 2 To 25
ws.Columns(c).ColumnWidth = 9.5
Next c
ws.Columns("Z").ColumnWidth = 1.5
' Row heights
Dim rr As Long
For rr = 1 To 85
ws.Rows(rr).RowHeight = 15
Next rr
ws.Rows(1).RowHeight = 5
ws.Rows(2).RowHeight = 55
ws.Rows(3).RowHeight = 26
ws.Rows(4).RowHeight = 8
' KPI Row 1: rows 5-14
For rr = 5 To 14: ws.Rows(rr).RowHeight = 15: Next rr
ws.Rows(15).RowHeight = 8
' KPI Row 2: rows 16-25
For rr = 16 To 25: ws.Rows(rr).RowHeight = 15: Next rr
ws.Rows(26).RowHeight = 10
ws.Rows(27).RowHeight = 22 ' section bar
ws.Rows(28).RowHeight = 6
For rr = 29 To 48: ws.Rows(rr).RowHeight = 13: Next rr ' chart row 1
ws.Rows(49).RowHeight = 8
For rr = 50 To 69: ws.Rows(rr).RowHeight = 13: Next rr ' chart row 2
ws.Rows(70).RowHeight = 12
ws.Rows(71).RowHeight = 22 ' alert header
For rr = 72 To 81: ws.Rows(rr).RowHeight = 18: Next rr ' alert rows
ws.Rows(82).RowHeight = 10
'-- Header Banner --
Application.StatusBar = "Step 3/5 Drawing header banner..."
DoEvents
Dim titleRng As Range
Set titleRng = ws.Range("B2:S2")
titleRng.Merge
With titleRng
.Value = "INVENTORY MANAGEMENT DASHBOARD" & Chr(10) & _
"Live Data | 5 Warehouses | 5 Suppliers | Real-Time Stock Intelligence"
.WrapText = True
.Interior.Color = C_NAVY
.Font.Color = C_WHITE
.Font.Name = "Calibri"
.VerticalAlignment = xlCenter
.HorizontalAlignment = xlLeft
.IndentLevel = 1
.Characters(1, 31).Font.Size = 18
.Characters(1, 31).Font.Bold = True
.Characters(33, 200).Font.Size = 9
.Characters(33, 200).Font.Color = RGB(150, 175, 215)
End With
Dim dateRng As Range
Set dateRng = ws.Range("T2:Y2")
dateRng.Merge
With dateRng
.Formula = "=""DATA AS OF""&CHAR(10)&TEXT(TODAY(),""dd-mmm-yyyy"")"
.WrapText = True
.Interior.Color = C_DKNAVY
.Font.Color = C_WHITE
.Font.Bold = True
.Font.Size = 11
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
End With
DoEvents
WaitMs PAUSE_LONG
'-- Toolbar --
Application.StatusBar = "Step 3/5 Adding action buttons..."
DoEvents
Call AddActionButtons(ws)
DoEvents
WaitMs PAUSE_MED
'================================================================
' KPI ROW 1 — All formulas point to Pivot!B33:B42
' This means any data change -> Refresh rebuilds Pivot -> Dash updates
'================================================================
Dim pvtN As String
pvtN = pvt.Name
Application.StatusBar = "Step 3/5 KPI 1/8 - Total Inventory Value..."
DoEvents
MakeKPICard ws, 5, 2, "TOTAL INVENTORY VALUE", _
"='" & pvtN & "'!B33", "#,##0", C_NAVY, "Val", "Sum of all stock value"
DoEvents
WaitMs PAUSE_KPI
Application.StatusBar = "Step 3/5 KPI 2/8 - Total SKUs..."
DoEvents
MakeKPICard ws, 5, 8, "TOTAL SKUs", _
"='" & pvtN & "'!B34", "#,##0", C_BLUE, "SKU", "Unique items tracked"
DoEvents
WaitMs PAUSE_KPI
Application.StatusBar = "Step 3/5 KPI 3/8 - Low Stock Items..."
DoEvents
MakeKPICard ws, 5, 14, "LOW STOCK ITEMS", _
"='" & pvtN & "'!B35", "#,##0", C_ORANGE, "Low", "At or below reorder level"
DoEvents
WaitMs PAUSE_KPI
Application.StatusBar = "Step 3/5 KPI 4/8 - Out of Stock..."
DoEvents
MakeKPICard ws, 5, 20, "OUT OF STOCK", _
"='" & pvtN & "'!B36", "#,##0", C_RED, "OOS", "Needs immediate action"
DoEvents
WaitMs PAUSE_KPI
'-- KPI Row 2 --
Application.StatusBar = "Step 3/5 KPI 5/8 - Total Warehouses..."
DoEvents
MakeKPICard ws, 16, 2, "TOTAL WAREHOUSES", _
"='" & pvtN & "'!B37", "#,##0", C_TEAL, "WH", "Active storage locations"
DoEvents
WaitMs PAUSE_KPI
Application.StatusBar = "Step 3/5 KPI 6/8 - Total Suppliers..."
DoEvents
MakeKPICard ws, 16, 8, "TOTAL SUPPLIERS", _
"='" & pvtN & "'!B38", "#,##0", C_PURPLE, "SUP", "Registered vendors"
DoEvents
WaitMs PAUSE_KPI
Application.StatusBar = "Step 3/5 KPI 7/8 - Avg Item Value..."
DoEvents
MakeKPICard ws, 16, 14, "AVG ITEM VALUE", _
"='" & pvtN & "'!B39", "#,##0", C_GREEN, "Avg", "Per SKU, all categories"
DoEvents
WaitMs PAUSE_KPI
Application.StatusBar = "Step 3/5 KPI 8/8 - Inventory Turnover..."
DoEvents
MakeKPICard ws, 16, 20, "INVENTORY TURNOVER", _
"='" & pvtN & "'!B42", "0.00", C_GOLD, "Trn", "Stock-out vs avg value"
DoEvents
WaitMs PAUSE_LONG
'-- Section Bar --
Application.StatusBar = "Step 3/5 Adding section bar..."
DoEvents
Dim secRng As Range
Set secRng = ws.Range("B27:Y27")
secRng.Merge
With secRng
.Value = " ANALYTICS - CHARTS & TRENDS"
.Interior.Color = C_DGREY
.Font.Color = C_WHITE
.Font.Bold = True
.Font.Size = 10
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
End With
DoEvents
WaitMs PAUSE_MED
'-- Charts --
Application.StatusBar = "Step 3/5 Drawing charts..."
DoEvents
Call AddCharts(ws, pvt)
WaitMs PAUSE_LONG
'-- Alert Panel --
Application.StatusBar = "Step 3/5 Building alert panel..."
DoEvents
Call BuildAlertPanel(ws, src)
DoEvents
WaitMs PAUSE_LONG
End Sub
'==============================================================
' KPI CARD BUILDER — Improved Layout
'==============================================================
Private Sub MakeKPICard(ws As Worksheet, r1 As Long, c1 As Long, _
lbl As String, frm As String, fmt As String, _
accent As Long, icon As String, subText As String)
Dim r2 As Long
Dim c2 As Long
r2 = r1 + 9 ' card height = 10 rows
c2 = c1 + 4 ' card width = 5 cols
' ── Card background ──
Dim card As Range
Set card = ws.Range(ws.Cells(r1, c1), ws.Cells(r2, c2))
card.Interior.Color = C_WHITE
card.BorderAround xlContinuous, xlThin, , C_BORDER
' ── Accent top bar (full width, 1 row) ──
Dim topBar As Range
Set topBar = ws.Range(ws.Cells(r1, c1), ws.Cells(r1, c2))
topBar.Merge
With topBar
.Interior.Color = accent
.Value = ""
End With
' ── Icon circle area (rows 2-3, cols 1-2 inside card) ──
Dim iconRng As Range
Set iconRng = ws.Range(ws.Cells(r1 + 1, c1), ws.Cells(r1 + 2, c1 + 1))
iconRng.Merge
With iconRng
.Value = icon
.Interior.Color = accent
.Font.Color = C_WHITE
.Font.Size = 10
.Font.Bold = True
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
End With
' ── Label (rows 2-3, cols 3-5 inside card) ──
Dim lblRng As Range
Set lblRng = ws.Range(ws.Cells(r1 + 1, c1 + 2), ws.Cells(r1 + 2, c2))
lblRng.Merge
With lblRng
.Value = UCase(lbl)
.Font.Size = 7.5
.Font.Bold = True
.Font.Color = C_GREYTXT
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.WrapText = True
.IndentLevel = 1
End With
' ── Divider line ──
With ws.Range(ws.Cells(r1 + 3, c1), ws.Cells(r1 + 3, c2))
.Merge
.Interior.Color = C_BORDER
End With
' ── Big value (rows 4-7 inside card) ──
Dim valRng As Range
Set valRng = ws.Range(ws.Cells(r1 + 4, c1), ws.Cells(r1 + 7, c2))
valRng.Merge
With valRng
.Formula = frm
.NumberFormat = fmt
.Font.Size = 22
.Font.Bold = True
.Font.Color = C_TEXT
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.IndentLevel = 1
End With
' ── Subtitle (rows 8-9 inside card) ──
Dim subRng As Range
Set subRng = ws.Range(ws.Cells(r1 + 8, c1), ws.Cells(r2, c2))
subRng.Merge
With subRng
.Value = subText
.Font.Size = 7.5
.Font.Color = C_GREYTXT
.Font.Italic = True
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.IndentLevel = 1
End With
' ── Accent bottom border ──
With card.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.Weight = xlMedium
.Color = accent
End With
End Sub
'==============================================================
' CHARTS — updated row references to match new layout
'==============================================================
Private Sub AddCharts(ws As Worksheet, pvt As Worksheet)
Dim cht As Chart
'--- Chart 1: Stock by Category ---
Application.StatusBar = "Step 3/5 Chart 1/5: Stock by Category..."
DoEvents
Set cht = PlaceChart(ws, "ChCat", xlColumnClustered, "B29", "I48")
Dim sr1 As Series
Dim sr2 As Series
Set sr1 = cht.SeriesCollection.NewSeries()
sr1.Name = "Current Stock"
sr1.Values = pvt.Range("E3:E7")
sr1.XValues = pvt.Range("A3:A7")
sr1.Interior.Color = C_BLUE
sr1.Border.LineStyle = xlNone
Set sr2 = cht.SeriesCollection.NewSeries()
sr2.Name = "Stock Value"
sr2.Values = pvt.Range("F3:F7")
sr2.XValues = pvt.Range("A3:A7")
sr2.Interior.Color = C_GOLD
sr2.Border.LineStyle = xlNone
sr2.AxisGroup = xlSecondary
StyleCht cht, "Stock Level & Value by Category"
DoEvents
WaitMs PAUSE_CHART
'--- Chart 2: Warehouse Pie ---
Application.StatusBar = "Step 3/5 Chart 2/5: Stock by Warehouse..."
DoEvents
Set cht = PlaceChart(ws, "ChWH", xlPie, "J29", "Q48")
Dim sr3 As Series
Set sr3 = cht.SeriesCollection.NewSeries()
sr3.Name = "Stock Value"
sr3.Values = pvt.Range("K3:K7")
sr3.XValues = pvt.Range("H3:H7")
sr3.HasDataLabels = True
sr3.DataLabels.ShowPercentage = True
sr3.DataLabels.ShowCategoryName = False
sr3.DataLabels.ShowValue = False
sr3.DataLabels.Font.Size = 8
sr3.DataLabels.Font.Bold = True
sr3.DataLabels.Font.Color = C_WHITE
Dim pieColors As Variant
pieColors = Array(C_BLUE, C_GREEN, C_ORANGE, C_PURPLE, C_TEAL)
Dim p As Long
For p = 1 To 5
sr3.Points(p).Interior.Color = pieColors(p - 1)
sr3.Points(p).Border.Color = C_WHITE
Next p
StyleCht cht, "Stock Value by Warehouse"
cht.HasLegend = True
cht.Legend.Position = xlLegendPositionBottom
cht.Legend.Font.Size = 8
DoEvents
WaitMs PAUSE_CHART
'--- Chart 3: Monthly Line ---
Application.StatusBar = "Step 3/5 Chart 3/5: Monthly Trend..."
DoEvents
Set cht = PlaceChart(ws, "ChTrend", xlLineMarkers, "R29", "Y48")
Dim sr4 As Series
Dim sr5 As Series
Set sr4 = cht.SeriesCollection.NewSeries()
sr4.Name = "Stock In"
sr4.Values = pvt.Range("B16:B27")
sr4.XValues = pvt.Range("A16:A27")
sr4.Border.Color = C_GREEN
sr4.Border.Weight = 2.25
sr4.MarkerForegroundColor = C_GREEN
sr4.MarkerBackgroundColor = C_GREEN
sr4.MarkerSize = 5
Set sr5 = cht.SeriesCollection.NewSeries()
sr5.Name = "Stock Out"
sr5.Values = pvt.Range("C16:C27")
sr5.XValues = pvt.Range("A16:A27")
sr5.Border.Color = C_RED
sr5.Border.Weight = 2.25
sr5.MarkerForegroundColor = C_RED
sr5.MarkerBackgroundColor = C_RED
sr5.MarkerSize = 5
StyleCht cht, "Monthly Stock In vs Stock Out"
DoEvents
WaitMs PAUSE_CHART
'--- Chart 4: Supplier Bar ---
Application.StatusBar = "Step 3/5 Chart 4/5: Stock by Supplier..."
DoEvents
Set cht = PlaceChart(ws, "ChSupp", xlBarClustered, "B50", "M69")
Dim sr6 As Series
Set sr6 = cht.SeriesCollection.NewSeries()
sr6.Name = "Stock Value"
sr6.Values = pvt.Range("P3:P7")
sr6.XValues = pvt.Range("M3:M7")
sr6.Interior.Color = C_PURPLE
sr6.Border.LineStyle = xlNone
StyleCht cht, "Stock Value by Supplier"
cht.HasLegend = False
DoEvents
WaitMs PAUSE_CHART
'--- Chart 5: Net Movement ---
Application.StatusBar = "Step 3/5 Chart 5/5: Net Stock Movement..."
DoEvents
Set cht = PlaceChart(ws, "ChNet", xlColumnClustered, "N50", "Y69")
Dim sr7 As Series
Set sr7 = cht.SeriesCollection.NewSeries()
sr7.Name = "Net Movement"
sr7.Values = pvt.Range("D16:D27")
sr7.XValues = pvt.Range("A16:A27")
sr7.Interior.Color = C_TEAL
sr7.Border.LineStyle = xlNone
StyleCht cht, "Monthly Net Stock Movement"
cht.HasLegend = False
DoEvents
WaitMs PAUSE_CHART
End Sub
Private Function PlaceChart(ws As Worksheet, nm As String, _
ctype As XlChartType, topLeftCell As String, _
bottomRightCell As String) As Chart
Dim r1 As Range
Dim r2 As Range
Set r1 = ws.Range(topLeftCell)
Set r2 = ws.Range(bottomRightCell)
Dim L As Double, T As Double, W As Double, H As Double
L = r1.Left + 2
T = r1.Top + 2
W = (r2.Left + r2.Width) - r1.Left - 4
H = (r2.Top + r2.Height) - r1.Top - 4
Dim co As ChartObject
Set co = ws.ChartObjects.Add(L, T, W, H)
co.Name = nm
co.Chart.ChartType = ctype
Set PlaceChart = co.Chart
End Function
Private Sub StyleCht(cht As Chart, ttl As String)
On Error Resume Next
With cht
.HasTitle = True
.ChartTitle.Text = ttl
.ChartTitle.Font.Size = 10
.ChartTitle.Font.Bold = True
.ChartTitle.Font.Name = "Calibri"
.ChartTitle.Font.Color = C_TEXT
.ChartArea.Format.Fill.ForeColor.RGB = C_WHITE
.ChartArea.Format.Line.Visible = msoFalse
.PlotArea.Format.Fill.ForeColor.RGB = C_WHITE
.PlotArea.Format.Line.Visible = msoFalse
If .HasLegend Then
.Legend.Font.Size = 8
.Legend.Font.Name = "Calibri"
End If
Dim axV As Axis
Dim axC As Axis
Set axV = .Axes(xlValue)
axV.Format.Line.ForeColor.RGB = C_BORDER
axV.TickLabels.Font.Size = 8
axV.TickLabels.Font.Color = C_GREYTXT
axV.MajorGridlines.Format.Line.ForeColor.RGB = C_BORDER
Set axC = .Axes(xlCategory)
axC.Format.Line.ForeColor.RGB = C_BORDER
axC.TickLabels.Font.Size = 8
axC.TickLabels.Font.Color = C_GREYTXT
End With
On Error GoTo 0
End Sub
'==============================================================
' ALERT PANEL — updated row references
'==============================================================
Private Sub BuildAlertPanel(ws As Worksheet, src As Worksheet)
Dim lastR As Long
lastR = GetLastRow(src)
Dim oos As Long
Dim low As Long
oos = 0
low = 0
Dim j As Long
Dim cs As Double
Dim rl As Double
For j = 2 To lastR
cs = Val(src.Cells(j, 10).Value)
rl = Val(src.Cells(j, 11).Value)
If cs = 0 Then
oos = oos + 1
ElseIf rl > 0 And cs <= rl Then
low = low + 1
End If
Next j
Application.StatusBar = "Step 3/5 Alert Panel: drawing header..."
DoEvents
Dim tRng As Range
Set tRng = ws.Range("B71:Q71")
tRng.Merge
With tRng
.Value = " LIVE INVENTORY ALERTS"
.Interior.Color = C_RED
.Font.Color = C_WHITE
.Font.Bold = True
.Font.Size = 10
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
End With
DoEvents
WaitMs PAUSE_SHORT
Dim sRng As Range
Set sRng = ws.Range("R71:Y71")
sRng.Merge
With sRng
.Value = "Out of Stock: " & oos & " | Low Stock: " & low
.Interior.Color = C_DKNAVY
.Font.Color = RGB(255, 210, 210)
.Font.Bold = True
.Font.Size = 9
.HorizontalAlignment = xlRight
.IndentLevel = 1
.VerticalAlignment = xlCenter
End With
DoEvents
WaitMs PAUSE_SHORT
Dim ar As Long
Dim cnt As Integer
ar = 72
cnt = 0
Dim rowRng As Range
For j = 2 To lastR
If cnt >= 10 Then Exit For
cs = Val(src.Cells(j, 10).Value)
rl = Val(src.Cells(j, 11).Value)
If cs = 0 Then
Application.StatusBar = "Step 3/5 Alert " & cnt + 1 & ": OUT OF STOCK - " & src.Cells(j, 2).Value
DoEvents
Set rowRng = ws.Range(ws.Cells(ar, 2), ws.Cells(ar, 25))
rowRng.Merge
rowRng.Value = " OUT OF STOCK - " & src.Cells(j, 2).Value & _
" | Warehouse: " & src.Cells(j, 5).Value & _
" | Reorder Level: " & rl
rowRng.Font.Color = C_ALRTREDT
rowRng.Font.Bold = True
rowRng.Font.Size = 9
rowRng.Interior.Color = C_ALRTRED
rowRng.HorizontalAlignment = xlLeft
rowRng.VerticalAlignment = xlCenter
DoEvents
WaitMs PAUSE_ALERT
ar = ar + 1
cnt = cnt + 1
ElseIf rl > 0 And cs <= rl Then
Application.StatusBar = "Step 3/5 Alert " & cnt + 1 & ": LOW STOCK - " & src.Cells(j, 2).Value
DoEvents
Set rowRng = ws.Range(ws.Cells(ar, 2), ws.Cells(ar, 25))
rowRng.Merge
rowRng.Value = " LOW STOCK - " & src.Cells(j, 2).Value & _
" | Stock: " & cs & " / Reorder: " & rl & _
" | Warehouse: " & src.Cells(j, 5).Value
rowRng.Font.Color = C_ALRTAMBT
rowRng.Font.Bold = False
rowRng.Font.Size = 9
rowRng.Interior.Color = C_ALRTAMB
rowRng.HorizontalAlignment = xlLeft
rowRng.VerticalAlignment = xlCenter
DoEvents
WaitMs PAUSE_ALERT
ar = ar + 1
cnt = cnt + 1
End If
Next j
If cnt = 0 Then
Set rowRng = ws.Range(ws.Cells(72, 2), ws.Cells(72, 25))
rowRng.Merge
rowRng.Value = " All stock levels are healthy. No alerts at this time."
rowRng.Font.Color = C_ALRTGRNT
rowRng.Font.Bold = True
rowRng.Interior.Color = C_ALRTGRN
rowRng.HorizontalAlignment = xlLeft
rowRng.VerticalAlignment = xlCenter
ar = 73
End If
Dim k As Long
For k = ar To 81
ws.Range(ws.Cells(k, 2), ws.Cells(k, 25)).Interior.Color = C_WHITE
Next k
End Sub
'==============================================================
' ACTION BUTTONS
'==============================================================
Private Sub AddActionButtons(ws As Worksheet)
Dim shp As Shape
For Each shp In ws.Shapes
If Left(shp.Name, 3) = "Btn" Then shp.Delete
Next shp
Dim names(0 To 5) As String
Dim macros(0 To 5) As String
Dim colors(0 To 5) As Long
Dim startCol(0 To 5) As String
Dim endCol(0 To 5) As String
names(0) = "REFRESH": macros(0) = "RefreshDashboard": colors(0) = C_BLUE
names(1) = "BACKUP": macros(1) = "BackupWorkbook": colors(1) = C_GREEN
names(2) = "EXPORT PDF": macros(2) = "ExportToPDF": colors(2) = C_TEAL
names(3) = "EMAIL": macros(3) = "EmailReport": colors(3) = C_PURPLE
names(4) = "VIEW ALERTS": macros(4) = "ShowAllAlerts": colors(4) = C_RED
names(5) = "SETTINGS": macros(5) = "OpenSettings": colors(5) = C_DGREY
startCol(0) = "B": endCol(0) = "E"
startCol(1) = "F": endCol(1) = "I"
startCol(2) = "J": endCol(2) = "M"
startCol(3) = "N": endCol(3) = "Q"
startCol(4) = "R": endCol(4) = "U"
startCol(5) = "V": endCol(5) = "Y"
Dim b As Integer
Dim r1 As Range
Dim r2 As Range
Dim btn As Shape
For b = 0 To 5
Set r1 = ws.Range(startCol(b) & "3")
Set r2 = ws.Range(endCol(b) & "3")
Set btn = ws.Shapes.AddShape(msoShapeRoundedRectangle, _
r1.Left + 3, r1.Top + 3, _
(r2.Left + r2.Width) - r1.Left - 6, _
r1.Height - 6)
With btn
.Name = "Btn" & b
.Fill.ForeColor.RGB = colors(b)
.Line.Visible = msoFalse
.TextFrame2.TextRange.Text = names(b)
.TextFrame2.TextRange.Font.Size = 9
.TextFrame2.TextRange.Font.Bold = msoTrue
.TextFrame2.TextRange.Font.Fill.ForeColor.RGB = C_WHITE
.TextFrame2.TextRange.Font.Name = "Calibri"
.TextFrame2.VerticalAnchor = msoAnchorMiddle
.TextFrame2.TextRange.ParagraphFormat.Alignment = msoAlignCenter
.OnAction = macros(b)
End With
Next b
End Sub
'==============================================================
' STEP 4 - SETTINGS SHEET
'==============================================================
Private Sub BuildSettingsSheet()
Dim ws As Worksheet
Set ws = GetSheet(SH_SETTINGS)
ws.Tab.Color = C_PURPLE
If ws.Cells(2, 1).Value <> "" Then Exit Sub
ws.Cells(1, 1).Value = "SETTING"
ws.Cells(1, 2).Value = "VALUE"
ws.Cells(1, 3).Value = "DESCRIPTION"
With ws.Range("A1:C1")
.Font.Bold = True
.Font.Color = C_WHITE
.Interior.Color = C_NAVY
End With
Dim cfg(0 To 11, 0 To 2) As String
cfg(0, 0) = "AutoRefreshMinutes": cfg(0, 1) = "30": cfg(0, 2) = "Auto-refresh interval in minutes"
cfg(1, 0) = "EmailTo": cfg(1, 1) = "inventory@company.com": cfg(1, 2) = "Primary email for reports"
cfg(2, 0) = "EmailCC": cfg(2, 1) = "manager@company.com": cfg(2, 2) = "CC email for reports"
cfg(3, 0) = "CompanyName": cfg(3, 1) = "My Company": cfg(3, 2) = "Company name for reports"
cfg(4, 0) = "BackupFolder": cfg(4, 1) = Environ("USERPROFILE") & "\Documents\": cfg(4, 2) = "Backup save location"
cfg(5, 0) = "PDFFolder": cfg(5, 1) = Environ("USERPROFILE") & "\Documents\": cfg(5, 2) = "PDF export location"
cfg(6, 0) = "LowStockThreshold%": cfg(6, 1) = "100": cfg(6, 2) = "Alert when stock at or below reorder"
cfg(7, 0) = "CurrencySymbol": cfg(7, 1) = "Rs.": cfg(7, 2) = "Currency for display"
cfg(8, 0) = "AdminPassword": cfg(8, 1) = "Admin@123": cfg(8, 2) = "Settings password"
cfg(9, 0) = "AuditEnabled": cfg(9, 1) = "TRUE": cfg(9, 2) = "Log all actions"
cfg(10, 0) = "LastBackup": cfg(10, 1) = "Never": cfg(10, 2) = "Last backup timestamp"
cfg(11, 0) = "Version": cfg(11, 1) = "2.0.0": cfg(11, 2) = "Dashboard version"
Dim r As Integer
For r = 0 To 11
ws.Cells(r + 2, 1).Value = cfg(r, 0)
ws.Cells(r + 2, 2).Value = cfg(r, 1)
ws.Cells(r + 2, 3).Value = cfg(r, 2)
If r Mod 2 = 0 Then
ws.Range(ws.Cells(r + 2, 1), ws.Cells(r + 2, 3)).Interior.Color = C_LGREY
End If
Next r
ws.Columns("A:C").AutoFit
End Sub
'==============================================================
' STEP 5 - AUDIT TRAIL
'==============================================================
Private Sub BuildAuditSheet()
Dim ws As Worksheet
Set ws = GetSheet(SH_AUDIT)
ws.Tab.Color = C_DGREY
If ws.Cells(1, 1).Value <> "" Then Exit Sub
ws.Cells(1, 1).Value = "Timestamp"
ws.Cells(1, 2).Value = "User"
ws.Cells(1, 3).Value = "Action"
ws.Cells(1, 4).Value = "Detail"
ws.Cells(1, 5).Value = "Workbook"
With ws.Range("A1:E1")
.Font.Bold = True
.Font.Color = C_WHITE
.Interior.Color = C_NAVY
End With
ws.Rows(1).RowHeight = 24
ws.Columns("A:E").AutoFit
End Sub
Public Sub AddAuditRow(act As String, det As String)
On Error Resume Next
Dim ws As Worksheet
Set ws = GetSheet(SH_AUDIT)
Dim nr As Long
nr = GetLastRow(ws) + 1
ws.Cells(nr, 1).Value = Now()
ws.Cells(nr, 1).NumberFormat = "dd-mmm-yyyy hh:mm:ss"
ws.Cells(nr, 2).Value = Environ("USERNAME")
ws.Cells(nr, 3).Value = act
ws.Cells(nr, 4).Value = det
ws.Cells(nr, 5).Value = ThisWorkbook.Name
End Sub
'==============================================================
' BUTTON ACTIONS
'==============================================================
Public Sub RefreshDashboard()
AddAuditRow "REFRESH", "Manual refresh by " & Environ("USERNAME")
BuildInventoryDashboard
End Sub
Public Sub BackupWorkbook()
On Error GoTo Err1
Dim folder As String
folder = GetSetting("BackupFolder")
If folder = "" Then folder = Environ("USERPROFILE") & "\Documents\"
If Right(folder, 1) <> "\" Then folder = folder & "\"
If Dir(folder, vbDirectory) = "" Then MkDir folder
Dim fn As String
fn = folder & "INV_Backup_" & Format(Now, "YYYYMMDD_HHMMSS") & ".xlsm"
Application.DisplayAlerts = False
ThisWorkbook.SaveCopyAs fn
Application.DisplayAlerts = True
SetSetting "LastBackup", Format(Now, "dd-mmm-yyyy hh:mm")
AddAuditRow "BACKUP", fn
MsgBox "Backup saved:" & vbCrLf & fn, vbInformation, "Inventory ERP v2"
Exit Sub
Err1:
MsgBox "Backup failed: " & Err.Description, vbCritical, "Inventory ERP v2"
End Sub
Public Sub ExportToPDF()
On Error GoTo Err2
Dim folder As String
folder = GetSetting("PDFFolder")
If folder = "" Then folder = Environ("USERPROFILE") & "\Documents\"
If Right(folder, 1) <> "\" Then folder = folder & "\"
If Dir(folder, vbDirectory) = "" Then MkDir folder
Dim fn As String
fn = folder & "INV_Dashboard_" & Format(Now, "YYYYMMDD_HHMMSS") & ".pdf"
Sheets(SH_DASH).ExportAsFixedFormat _
Type:=xlTypePDF, Filename:=fn, _
Quality:=xlQualityStandard, IncludeDocProperties:=True
AddAuditRow "PDF", fn
MsgBox "PDF saved:" & vbCrLf & fn, vbInformation, "Inventory ERP v2"
Shell "explorer.exe """ & fn & """", vbNormalFocus
Exit Sub
Err2:
MsgBox "PDF export failed: " & Err.Description, vbCritical, "Inventory ERP v2"
End Sub
Public Sub EmailReport()
On Error GoTo Err3
Dim eTo As String
Dim eCC As String
eTo = GetSetting("EmailTo")
eCC = GetSetting("EmailCC")
If eTo = "" Then
MsgBox "Set EmailTo in Settings sheet first.", vbExclamation, "Inventory ERP v2"
Exit Sub
End If
Dim tmp As String
tmp = Environ("TEMP") & "\INV_Report_" & Format(Now, "YYYYMMDD_HHMMSS") & ".pdf"
Sheets(SH_DASH).ExportAsFixedFormat xlTypePDF, tmp
Dim ol As Object
Dim ml As Object
Set ol = CreateObject("Outlook.Application")
Set ml = ol.CreateItem(0)
With ml
.To = eTo
.CC = eCC
.Subject = GetSetting("CompanyName") & " - Inventory Report - " & Format(Date, "dd-mmm-yyyy")
.Body = "Dear Team," & vbCrLf & vbCrLf & _
"Please find the Inventory Report attached." & vbCrLf & _
"Generated: " & Format(Now, "dd-mmm-yyyy hh:mm") & vbCrLf & vbCrLf & _
"Regards," & vbCrLf & Environ("USERNAME")
.Attachments.Add tmp
.Display
End With
AddAuditRow "EMAIL", "Report drafted to " & eTo
Exit Sub
Err3:
MsgBox "Email failed: " & Err.Description & vbCrLf & "Ensure Outlook is installed.", _
vbCritical, "Inventory ERP v2"
End Sub
Public Sub ShowAllAlerts()
Dim src As Worksheet
Set src = Sheets(SH_DATA)
Dim lastR As Long
lastR = GetLastRow(src)
Dim msg As String
Dim oos As Integer
Dim low As Integer
oos = 0: low = 0: msg = ""
Dim j As Long
Dim cs As Double
Dim rl As Double
For j = 2 To lastR
cs = Val(src.Cells(j, 10).Value)
rl = Val(src.Cells(j, 11).Value)
If cs = 0 Then
msg = msg & "[OUT OF STOCK] " & src.Cells(j, 2).Value & " | " & src.Cells(j, 5).Value & vbCrLf
oos = oos + 1
ElseIf rl > 0 And cs <= rl Then
msg = msg & "[LOW STOCK] " & src.Cells(j, 2).Value & " Stock=" & cs & " Reorder=" & rl & vbCrLf
low = low + 1
End If
Next j
Dim out As String
out = "INVENTORY ALERT SUMMARY" & vbCrLf & String(40, "-") & vbCrLf & _
"Out of Stock : " & oos & vbCrLf & "Low Stock : " & low & vbCrLf & _
String(40, "-") & vbCrLf
If msg = "" Then out = out & "All items are well stocked!" Else out = out & msg
AddAuditRow "ALERTS_VIEWED", "OOS=" & oos & " Low=" & low
MsgBox out, vbExclamation, "Inventory Alerts - ERP v2"
End Sub
Public Sub OpenSettings()
Dim pwd As String
Dim stored As String
pwd = InputBox("Enter Admin Password:", "Settings Access", "")
If pwd = "" Then Exit Sub
stored = GetSetting("AdminPassword")
If pwd <> stored Then
MsgBox "Incorrect password.", vbCritical, "Inventory ERP v2"
AddAuditRow "AUTH_FAIL", "Wrong password by " & Environ("USERNAME")
Exit Sub
End If
AddAuditRow "SETTINGS", "Settings opened by " & Environ("USERNAME")
Sheets(SH_SETTINGS).Activate
End Sub
Public Sub ScheduleAutoRefresh()
Dim mins As Integer
mins = Val(GetSetting("AutoRefreshMinutes"))
If mins <= 0 Then mins = 30
Application.OnTime Now + TimeSerial(0, mins, 0), "RefreshDashboard"
MsgBox "Auto-refresh set for every " & mins & " minutes.", vbInformation, "Inventory ERP v2"
End Sub
'==============================================================
' UTILITY FUNCTIONS
'==============================================================
Private Function GetSheet(nm As String) As Worksheet
Dim ws As Worksheet
On Error Resume Next
Set ws = Sheets(nm)
On Error GoTo 0
If ws Is Nothing Then
Set ws = Sheets.Add(After:=Sheets(Sheets.Count))
ws.Name = nm
End If
Set GetSheet = ws
End Function
Private Function GetLastRow(ws As Worksheet) As Long
Dim lr As Long
lr = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row
If lr < 1 Then lr = 1
GetLastRow = lr
End Function
Private Sub WritePivotTitle(ws As Worksheet, r As Long, c As Integer, ttl As String)
Dim rng As Range
Set rng = ws.Range(ws.Cells(r, c), ws.Cells(r, c + 7))
rng.Merge
With rng
.Value = " " & ttl
.Interior.Color = C_NAVY
.Font.Color = C_WHITE
.Font.Bold = True
.Font.Size = 10
.Font.Name = "Calibri"
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlCenter
.RowHeight = 22
End With
End Sub
Private Sub StylePivHead(ws As Worksheet, r As Long, c1 As Integer, c2 As Integer)
Dim c As Integer
For c = c1 To c2
With ws.Cells(r, c)
.Interior.Color = C_DGREY
.Font.Color = C_WHITE
.Font.Bold = True
.Font.Size = 9
.HorizontalAlignment = xlCenter
.RowHeight = 20
End With
Next c
End Sub
Private Sub StyleTotRow(ws As Worksheet, r As Long, c1 As Integer, c2 As Integer)
With ws.Range(ws.Cells(r, c1), ws.Cells(r, c2))
.Interior.Color = C_NAVY
.Font.Color = C_WHITE
.Font.Bold = True
End With
End Sub
Private Function GetSetting(key As String) As String
On Error Resume Next
Dim ws As Worksheet
Set ws = Sheets(SH_SETTINGS)
Dim i As Long
For i = 2 To 20
If ws.Cells(i, 1).Value = key Then
GetSetting = CStr(ws.Cells(i, 2).Value)
Exit Function
End If
Next i
GetSetting = ""
End Function
Private Sub SetSetting(key As String, val As String)
On Error Resume Next
Dim ws As Worksheet
Set ws = Sheets(SH_SETTINGS)
Dim i As Long
For i = 2 To 20
If ws.Cells(i, 1).Value = key Then
ws.Cells(i, 2).Value = val
Exit Sub
End If
Next i
End Sub
'==============================================================
' WORKBOOK EVENTS - PASTE INTO "ThisWorkbook" MODULE
'==============================================================
' Private Sub Workbook_Open()
' BuildInventoryDashboard
' End Sub
'
' Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
' AddAuditRow "SAVE", "Saved by " & Environ("USERNAME")
' End Sub
'
' Private Sub Workbook_BeforeClose(Cancel As Boolean)
' Application.StatusBar = False
' End SubWhat Happens When You Click the Dashboard Button?
The most exciting part of this project is the automation process.
After clicking the Dashboard button, the VBA code immediately starts working in the background.
The automation performs several actions:
Step 1: Raw Data Processing
The system begins by organizing and formatting the source data.
Raw inventory files often contain inconsistent formatting, blank spaces, duplicate entries, and other issues that affect reporting accuracy.
The VBA code automatically prepares the data so that it is ready for analysis.
This eliminates the need for manual data cleaning every time a new dataset is imported.
Step 2: Automatic Pivot Table Creation
Once the data is ready, VBA generates multiple Pivot Tables automatically.
Pivot Tables are powerful analytical tools in Excel, but creating them manually can take considerable time.
The automation creates all required Pivot Tables instantly, ensuring consistency and accuracy throughout the dashboard.
Step 3: KPI Calculation
Business leaders need quick access to key metrics.
The dashboard automatically calculates important KPIs including:
- Total Product Quantity
- Total Inventory Value
- Total Sales
- Total Purchases
- Product Count
- Stock Availability Status
Instead of manually creating formulas, everything is generated automatically.
Step 4: Chart Generation
Visual representation is essential for understanding business performance.
The VBA automation creates professional charts that display:
- Purchase vs Sales Comparison
- Top Selling Products
- Inventory Distribution
- Category Performance
- Product Trends
These charts help decision-makers identify patterns and opportunities much faster than reviewing rows of data.
Step 5: Dashboard Formatting
A dashboard is only effective if it is easy to read.
The VBA code automatically formats:
- KPI cards
- Titles
- Headers
- Tables
- Charts
- Dashboard layout
The result is a polished and professional dashboard that looks like a premium business intelligence report.
Key Features of the Inventory Dashboard
Total Inventory Value Tracking
Inventory value is one of the most important metrics for any business.
The dashboard instantly calculates the total value of inventory available in stock.
This allows business owners to understand how much capital is currently tied up in inventory and make informed purchasing decisions.
Low Stock Alerts
Running out of stock can lead to lost sales and dissatisfied customers.
The dashboard automatically identifies products that are approaching critical stock levels.
Managers can quickly identify which products need replenishment before shortages occur.
Sales Performance Monitoring
Understanding sales trends is critical for growth.
The dashboard provides a clear view of total sales and product performance, helping businesses identify high-performing products and categories.
Purchase vs Sales Analysis
One of the most useful visualizations in the dashboard compares purchases with sales.
This analysis helps businesses understand whether inventory levels are aligned with demand.
It can also highlight overstocking or understocking situations before they become costly problems.
Top Selling Product Analysis
Not all products contribute equally to revenue.
The dashboard automatically highlights the best-performing products.
This insight helps businesses focus marketing efforts, optimize inventory levels, and improve profitability.
One-Click Refresh
Perhaps the most powerful feature is the refresh capability.
Whenever new inventory data becomes available, users simply click a button.
The dashboard automatically rebuilds itself using the latest information.
There is no need to recreate reports, charts, or Pivot Tables manually.
Benefits of VBA Automation
Many Excel users underestimate the power of VBA.
While Excel itself is an excellent analytical tool, VBA transforms Excel into a powerful automation platform.
Here are some of the biggest benefits of using VBA automation:
Significant Time Savings
Tasks that normally take hours can be completed in seconds.
The dashboard creation process that once required extensive manual effort now finishes in approximately 25 seconds.
Reduced Human Error
Manual reporting often introduces mistakes.
Automation ensures that the same process is executed consistently every time.
Professional Reporting
The dashboard creates a polished and visually appealing report that can be shared with managers, clients, and stakeholders.
Improved Productivity
Instead of spending time creating reports, users can focus on analyzing insights and making decisions.
Scalability
As data grows, the automation continues to perform efficiently without requiring additional effort from the user.
Who Can Use This Dashboard?
This inventory dashboard is suitable for a wide range of users including:
Small Business Owners
Business owners can monitor stock levels, sales, and inventory value from a single dashboard.
Warehouse Managers
Warehouse teams can quickly identify low-stock products and inventory trends.
Retail Businesses
Retail stores can analyze product performance and improve inventory planning.
Inventory Analysts
Analysts can save time by automating repetitive reporting tasks.
Excel Professionals
Excel enthusiasts can learn advanced VBA techniques by studying the dashboard automation process.
Why Businesses Are Moving Toward Automated Dashboards
Modern businesses need faster access to information.
Manual reporting methods are becoming increasingly difficult to justify when automation can deliver the same results within seconds.
Automated dashboards provide:
- Faster reporting
- Better accuracy
- Consistent results
- Improved decision-making
- Greater operational efficiency
As organizations continue to embrace digital transformation, Excel VBA remains one of the most accessible and cost-effective automation tools available.
Final Thoughts
This project demonstrates how powerful Excel VBA can be when applied to real business challenges.
What starts as a simple inventory dataset is transformed into a complete business dashboard through automation.
With a single click, the system processes raw data, creates Pivot Tables, calculates KPIs, generates charts, formats reports, and delivers meaningful business insights in approximately 25 seconds.
For businesses looking to save time, reduce manual effort, and improve reporting accuracy, automated dashboards like this can provide tremendous value.
If you’re interested in learning how this dashboard was built and want access to the VBA code, simply comment “ERP” and I’ll share the code with you.
Automation is not just about saving time—it’s about creating smarter systems that help businesses make better decisions every day.


Pingback: Inventory Management Is Broken for Many Businesses — This Excel VBA Dashboard Changes Everything 2026 - Excel AI Tools and SEO Guides
ERP