npx skills add ...
npx skills add reason-machines/data-skills --skill power-bi-sales-analytics-dashboard
Build interactive Power BI sales dashboards with regional analysis, profit tracking, and predictive insights using the SalesPulse 360 framework
npx skills add reason-machines/data-skills --skill power-bi-sales-analytics-dashboard
Skill by ara.so — Data Skills collection.
SalesPulse 360 is a comprehensive Power BI dashboard framework for retail and sales analytics. It transforms raw sales data into interactive visualizations with regional analysis, profit tracking, multi-dimensional slicing, predictive forecasting, and automated alerts. Built for the Global Superstore dataset, it provides a blueprint for creating production-ready business intelligence dashboards.
Key Capabilities:
In Power BI Desktop, configure the data source path:
For live database connections:
Use environment variables for credentials:
${Env:SQL_SERVER}${Env:SQL_DATABASE}Create a Config table with thresholds:
Define roles for regional data access:
Apply RLS in Modeling > Manage Roles > Create Role > Add DAX filter.
Create a Language table:
Use field parameters to switch labels dynamically.
Sales[City] or Sales[State][Total Sales][Profit Margin %][Regional Performance Index]Sales[Category] > Sales[Sub-Category][Total Profit][Profit Margin %] with conditional formattingDateDim[Date] (Month hierarchy)[Total Sales][Total Profit][Profit Margin %] < 0.15 → Red[Profit Margin %] >= 0.15 AND < 0.25 → Yellow[Profit Margin %] >= 0.25 → GreenInsert a Text Box or Card visual with this measure.
Sales[Product Name]Add a slicer for the What-If parameter to simulate scenarios.
Pass as URL parameter to second report:
Issue: Scheduled refresh fails with "Unable to connect to data source"
Solutions:
Issue: Dashboard loads slowly with large datasets
Solutions:
Issue: YoY growth showing incorrect values
Solutions:
REMOVEFILTERS() in calculate to clear unwanted filters:Issue: Users see all data despite RLS configuration
Solutions:
Issue: Forecast line missing from time series chart
Solutions:
Issue: Dashboard labels remain in English despite language selection
Solutions:
License: MIT
Repository: https://github.com/MahbubNibir/power-bi-retail-analytics-viz
# Open the main dashboard file
start salespulse360.pbix # Windows
open salespulse360.pbix # macOS// Power Query M - Data source configuration
let
Source = Csv.Document(
File.Contents("C:\data\global_superstore.csv"),
[Delimiter=",", Columns=21, Encoding=65001, QuoteStyle=QuoteStyle.None]
),
PromotedHeaders = Table.PromoteHeaders(Source, [PromoteAllScalars=true])
in
PromotedHeaders// Power Query M - SQL Server connection
let
Source = Sql.Database(
"YOUR_SERVER_NAME",
"SalesDB",
[Query="SELECT * FROM dbo.Sales WHERE OrderDate >= '2011-01-01'"]
)
in
Source// Power Query M - Create date dimension
let
StartDate = #date(2011, 1, 1),
EndDate = #date(2025, 12, 31),
NumberOfDays = Duration.Days(EndDate - StartDate) + 1,
DateList = List.Dates(StartDate, NumberOfDays, #duration(1,0,0,0)),
TableFromList = Table.FromList(DateList, Splitter.SplitByNothing()),
ChangedType = Table.TransformColumnTypes(TableFromList, {{"Column1", type date}}),
RenamedColumns = Table.RenameColumns(ChangedType, {{"Column1", "Date"}}),
// Add calculated columns
AddYear = Table.AddColumn(RenamedColumns, "Year", each Date.Year([Date]), Int64.Type),
AddQuarter = Table.AddColumn(AddYear, "Quarter", each "Q" & Text.From(Date.QuarterOfYear([Date]))),
AddMonth = Table.AddColumn(AddQuarter, "Month", each Date.MonthName([Date])),
AddWeek = Table.AddColumn(AddMonth, "WeekOfYear", each Date.WeekOfYear([Date]), Int64.Type),
AddDayOfWeek = Table.AddColumn(AddWeek, "DayOfWeek", each Date.DayOfWeekName([Date]))
in
AddDayOfWeek// Power Query M - Add profit margin percentage
let
Source = Sales,
AddProfitMargin = Table.AddColumn(
Source,
"ProfitMargin",
each if [Sales] <> 0 then [Profit] / [Sales] else 0,
type number
),
FormatPercentage = Table.TransformColumns(
AddProfitMargin,
{{"ProfitMargin", each Number.Round(_, 4), type number}}
)
in
FormatPercentage// Total Sales measure
Total Sales = SUM(Sales[Sales])
// Total Profit measure
Total Profit = SUM(Sales[Profit])
// Average Order Value
Avg Order Value = DIVIDE([Total Sales], DISTINCTCOUNT(Sales[Order ID]), 0)
// Profit Margin %
Profit Margin % = DIVIDE([Total Profit], [Total Sales], 0)
// Sales Growth YoY
Sales Growth YoY =
VAR CurrentYearSales = [Total Sales]
VAR PreviousYearSales = CALCULATE(
[Total Sales],
DATEADD(DateDim[Date], -1, YEAR)
)
RETURN
DIVIDE(
CurrentYearSales - PreviousYearSales,
PreviousYearSales,
0
)// 12-month rolling sales
MAT Sales =
CALCULATE(
[Total Sales],
DATESINPERIOD(
DateDim[Date],
LASTDATE(DateDim[Date]),
-12,
MONTH
)
)// Regional performance vs global average
Regional Performance Index =
VAR RegionalMargin = [Profit Margin %]
VAR GlobalMargin = CALCULATE(
[Profit Margin %],
ALL(Sales[Region])
)
RETURN
DIVIDE(RegionalMargin, GlobalMargin, 0)// Alert when margin drops below threshold
Margin Alert =
VAR CurrentMargin = [Profit Margin %]
VAR Threshold = 0.15 // 15% threshold - make this a parameter table value
RETURN
IF(
CurrentMargin < Threshold,
"⚠️ Low Margin",
"✓ On Track"
)// Sales forecast using historical trend
Forecasted Sales =
VAR HistoricalAvg = CALCULATE(
[Total Sales],
DATESINPERIOD(DateDim[Date], MAX(DateDim[Date]), -6, MONTH)
)
VAR GrowthRate = [Sales Growth YoY]
RETURN
HistoricalAvg * (1 + GrowthRate)// DAX table for configuration
Config = DATATABLE(
"Parameter", STRING,
"Value", NUMBER,
{
{"ProfitMarginThreshold", 0.15},
{"ReturnRateWarning", 0.08},
{"RollingAverageDays", 90}
}
)
// Reference in measures
Profit Threshold =
LOOKUPVALUE(Config[Value], Config[Parameter], "ProfitMarginThreshold")// RLS filter for Regional Managers
[Region] = USERNAME()
// RLS filter for specific email mapping
VAR UserEmail = USERPRINCIPALNAME()
VAR UserRegion = LOOKUPVALUE(
UserMapping[Region],
UserMapping[Email],
UserEmail
)
RETURN [Region] = UserRegionLanguage = DATATABLE(
"LanguageCode", STRING,
"LanguageName", STRING,
"DateFormat", STRING,
"CurrencySymbol", STRING,
{
{"en-US", "English", "MM/DD/YYYY", "$"},
{"es-ES", "Spanish", "DD/MM/YYYY", "€"},
{"zh-CN", "Chinese", "YYYY-MM-DD", "¥"},
{"ja-JP", "Japanese", "YYYY/MM/DD", "¥"}
}
)// Natural language insight generator
Sales Insight =
VAR CurrentSales = [Total Sales]
VAR PrevSales = CALCULATE([Total Sales], PREVIOUSMONTH(DateDim[Date]))
VAR Change = DIVIDE(CurrentSales - PrevSales, PrevSales, 0)
VAR ChangeText = IF(Change >= 0, "increased", "declined")
VAR ChangePercent = FORMAT(ABS(Change), "0.0%")
VAR TopRegion = TOPN(1, VALUES(Sales[Region]), [Total Sales], DESC)
RETURN
"Sales have " & ChangeText & " by " & ChangePercent &
" this period. The " & TopRegion & " region is the top performer."<!-- HTML embedding example -->
<!DOCTYPE html>
<html>
<head>
<title>Sales Dashboard</title>
<script src="https://cdn.jsdelivr.net/npm/powerbi-client@2.20.0/dist/powerbi.min.js"></script>
</head>
<body>
<div id="embedContainer" style="height:600px;"></div>
<script>
const embedConfig = {
type: 'report',
id: 'YOUR_REPORT_ID',
embedUrl: 'https://app.powerbi.com/reportEmbed',
accessToken: process.env.POWERBI_ACCESS_TOKEN,
settings: {
filterPaneEnabled: false,
navContentPaneEnabled: true
}
};
const reportContainer = document.getElementById('embedContainer');
const report = powerbi.embed(reportContainer, embedConfig);
</script>
</body>
</html>// Create What-If parameter
What-If Discount % =
GENERATESERIES(0, 0.5, 0.05) // 0% to 50% in 5% increments
// Adjusted profit with discount
Adjusted Profit =
[Total Profit] - ([Total Sales] * 'What-If Discount %'[Value])// In source report, create measure for selection
Selected Region =
IF(
HASONEVALUE(Sales[Region]),
VALUES(Sales[Region]),
BLANK()
)https://app.powerbi.com/groups/WORKSPACE_ID/reports/REPORT_ID?filter=Sales/Region eq 'West'// Power Query - Aggregate before import
let
Source = Sales,
Grouped = Table.Group(
Source,
{"Order Date", "Region", "Category"},
{
{"Total Sales", each List.Sum([Sales]), type number},
{"Total Profit", each List.Sum([Profit]), type number}
}
)
in
GroupedTotal Sales (No Filters) = CALCULATE([Total Sales], REMOVEFILTERS())// Dynamic label example
Sales Label =
SWITCH(
SELECTEDVALUE(Language[LanguageCode]),
"es-ES", "Ventas",
"zh-CN", "销售额",
"ja-JP", "売上高",
"Sales" // Default English
)