@luquimbo/bi-superpowers 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +8 -0
- package/.mcp.json +25 -0
- package/AGENTS.md +244 -0
- package/CHANGELOG.md +265 -0
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/bin/build-plugin.js +30 -0
- package/bin/cli.js +1064 -0
- package/bin/commands/add.js +533 -0
- package/bin/commands/add.test.js +77 -0
- package/bin/commands/build-desktop.js +166 -0
- package/bin/commands/changelog.js +443 -0
- package/bin/commands/diff.js +325 -0
- package/bin/commands/lint.js +419 -0
- package/bin/commands/lint.test.js +103 -0
- package/bin/commands/mcp-setup.js +246 -0
- package/bin/commands/pull.js +287 -0
- package/bin/commands/pull.test.js +36 -0
- package/bin/commands/push.js +231 -0
- package/bin/commands/push.test.js +14 -0
- package/bin/commands/search.js +344 -0
- package/bin/commands/search.test.js +115 -0
- package/bin/commands/setup.js +545 -0
- package/bin/commands/setup.test.js +46 -0
- package/bin/commands/sync-profile.js +405 -0
- package/bin/commands/sync-profile.test.js +14 -0
- package/bin/commands/sync-source.js +418 -0
- package/bin/commands/sync-source.test.js +14 -0
- package/bin/commands/watch.js +206 -0
- package/bin/lib/generators/claude-plugin.js +266 -0
- package/bin/lib/generators/claude-plugin.test.js +110 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +282 -0
- package/bin/lib/licensing/index.js +35 -0
- package/bin/lib/licensing/storage.js +364 -0
- package/bin/lib/licensing/storage.test.js +55 -0
- package/bin/lib/licensing/validator.js +213 -0
- package/bin/lib/licensing/validator.test.js +137 -0
- package/bin/lib/microsoft-mcp.js +176 -0
- package/bin/lib/microsoft-mcp.test.js +106 -0
- package/bin/lib/skills.js +84 -0
- package/bin/mcp/powerbi-modeling-launcher.js +38 -0
- package/bin/postinstall.js +44 -0
- package/bin/utils/errors.js +159 -0
- package/bin/utils/git.js +298 -0
- package/bin/utils/logger.js +142 -0
- package/bin/utils/mcp-detect.js +274 -0
- package/bin/utils/mcp-detect.test.js +105 -0
- package/bin/utils/pbix.js +305 -0
- package/bin/utils/pbix.test.js +37 -0
- package/bin/utils/profiles.js +312 -0
- package/bin/utils/projects.js +168 -0
- package/bin/utils/readline.js +206 -0
- package/bin/utils/readline.test.js +47 -0
- package/bin/utils/tui.js +314 -0
- package/bin/utils/tui.test.js +127 -0
- package/commands/contributions.md +265 -0
- package/commands/data-model-design.md +468 -0
- package/commands/dax-doctor.md +248 -0
- package/commands/fabric-scripts.md +452 -0
- package/commands/migration-assistant.md +290 -0
- package/commands/model-documenter.md +242 -0
- package/commands/pbi-connect.md +239 -0
- package/commands/project-kickoff.md +905 -0
- package/commands/report-layout.md +296 -0
- package/commands/rls-design.md +533 -0
- package/commands/theme-tweaker.md +624 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +37 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +95 -0
- package/docs/openrouter-free-models.md +92 -0
- package/library/examples/README.md +151 -0
- package/library/examples/finance-reporting/README.md +351 -0
- package/library/examples/finance-reporting/data-model.md +267 -0
- package/library/examples/finance-reporting/measures.dax +557 -0
- package/library/examples/hr-analytics/README.md +371 -0
- package/library/examples/hr-analytics/data-model.md +315 -0
- package/library/examples/hr-analytics/measures.dax +460 -0
- package/library/examples/marketing-analytics/README.md +37 -0
- package/library/examples/marketing-analytics/data-model.md +62 -0
- package/library/examples/marketing-analytics/measures.dax +110 -0
- package/library/examples/retail-analytics/README.md +439 -0
- package/library/examples/retail-analytics/data-model.md +288 -0
- package/library/examples/retail-analytics/measures.dax +481 -0
- package/library/examples/supply-chain/README.md +37 -0
- package/library/examples/supply-chain/data-model.md +69 -0
- package/library/examples/supply-chain/measures.dax +77 -0
- package/library/examples/udf-library/README.md +228 -0
- package/library/examples/udf-library/functions.dax +571 -0
- package/library/snippets/dax/README.md +292 -0
- package/library/snippets/dax/business-domains.md +576 -0
- package/library/snippets/dax/calculate-patterns.md +276 -0
- package/library/snippets/dax/calculation-groups.md +489 -0
- package/library/snippets/dax/error-handling.md +495 -0
- package/library/snippets/dax/iterators-and-aggregations.md +474 -0
- package/library/snippets/dax/kpis-and-metrics.md +293 -0
- package/library/snippets/dax/rankings-and-topn.md +235 -0
- package/library/snippets/dax/security-patterns.md +413 -0
- package/library/snippets/dax/text-and-formatting.md +316 -0
- package/library/snippets/dax/time-intelligence.md +196 -0
- package/library/snippets/dax/user-defined-functions.md +477 -0
- package/library/snippets/dax/virtual-tables.md +546 -0
- package/library/snippets/excel-formulas/README.md +84 -0
- package/library/snippets/excel-formulas/aggregations.md +330 -0
- package/library/snippets/excel-formulas/dates-and-times.md +361 -0
- package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
- package/library/snippets/excel-formulas/lookups.md +169 -0
- package/library/snippets/excel-formulas/text-functions.md +363 -0
- package/library/snippets/governance/naming-conventions.md +97 -0
- package/library/snippets/governance/review-checklists.md +107 -0
- package/library/snippets/power-query/README.md +389 -0
- package/library/snippets/power-query/api-integration.md +707 -0
- package/library/snippets/power-query/connections.md +434 -0
- package/library/snippets/power-query/data-cleaning.md +298 -0
- package/library/snippets/power-query/error-handling.md +526 -0
- package/library/snippets/power-query/parameters.md +350 -0
- package/library/snippets/power-query/performance.md +506 -0
- package/library/snippets/power-query/transformations.md +330 -0
- package/library/snippets/report-design/accessibility.md +78 -0
- package/library/snippets/report-design/chart-selection.md +54 -0
- package/library/snippets/report-design/layout-patterns.md +87 -0
- package/library/templates/data-models/README.md +93 -0
- package/library/templates/data-models/finance-model.md +627 -0
- package/library/templates/data-models/retail-star-schema.md +473 -0
- package/library/templates/excel/README.md +83 -0
- package/library/templates/excel/budget-tracker.md +432 -0
- package/library/templates/excel/data-entry-form.md +533 -0
- package/library/templates/power-bi/README.md +72 -0
- package/library/templates/power-bi/finance-report.md +449 -0
- package/library/templates/power-bi/kpi-scorecard.md +461 -0
- package/library/templates/power-bi/sales-dashboard.md +281 -0
- package/library/themes/excel/README.md +436 -0
- package/library/themes/power-bi/README.md +271 -0
- package/library/themes/power-bi/accessible.json +307 -0
- package/library/themes/power-bi/bi-superpowers-default.json +858 -0
- package/library/themes/power-bi/corporate-blue.json +291 -0
- package/library/themes/power-bi/dark-mode.json +291 -0
- package/library/themes/power-bi/minimal.json +292 -0
- package/library/themes/power-bi/print-friendly.json +309 -0
- package/package.json +93 -0
- package/skills/contributions/SKILL.md +267 -0
- package/skills/data-model-design/SKILL.md +470 -0
- package/skills/data-modeling/SKILL.md +254 -0
- package/skills/data-quality/SKILL.md +664 -0
- package/skills/dax/SKILL.md +708 -0
- package/skills/dax-doctor/SKILL.md +250 -0
- package/skills/dax-udf/SKILL.md +489 -0
- package/skills/deployment/SKILL.md +320 -0
- package/skills/excel-formulas/SKILL.md +463 -0
- package/skills/fabric-scripts/SKILL.md +454 -0
- package/skills/fast-standard/SKILL.md +509 -0
- package/skills/governance/SKILL.md +205 -0
- package/skills/migration-assistant/SKILL.md +292 -0
- package/skills/model-documenter/SKILL.md +244 -0
- package/skills/pbi-connect/SKILL.md +241 -0
- package/skills/power-query/SKILL.md +406 -0
- package/skills/project-kickoff/SKILL.md +907 -0
- package/skills/query-performance/SKILL.md +480 -0
- package/skills/report-design/SKILL.md +207 -0
- package/skills/report-layout/SKILL.md +298 -0
- package/skills/rls-design/SKILL.md +535 -0
- package/skills/semantic-model/SKILL.md +237 -0
- package/skills/testing-validation/SKILL.md +643 -0
- package/skills/theme-tweaker/SKILL.md +626 -0
- package/src/content/base.md +237 -0
- package/src/content/mcp-requirements.json +69 -0
- package/src/content/routing.md +203 -0
- package/src/content/skills/contributions.md +259 -0
- package/src/content/skills/data-model-design.md +462 -0
- package/src/content/skills/data-modeling.md +246 -0
- package/src/content/skills/data-quality.md +656 -0
- package/src/content/skills/dax-doctor.md +242 -0
- package/src/content/skills/dax-udf.md +481 -0
- package/src/content/skills/dax.md +700 -0
- package/src/content/skills/deployment.md +312 -0
- package/src/content/skills/excel-formulas.md +455 -0
- package/src/content/skills/fabric-scripts.md +446 -0
- package/src/content/skills/fast-standard.md +501 -0
- package/src/content/skills/governance.md +197 -0
- package/src/content/skills/migration-assistant.md +284 -0
- package/src/content/skills/model-documenter.md +236 -0
- package/src/content/skills/pbi-connect.md +233 -0
- package/src/content/skills/power-query.md +398 -0
- package/src/content/skills/project-kickoff.md +899 -0
- package/src/content/skills/query-performance.md +472 -0
- package/src/content/skills/report-design.md +199 -0
- package/src/content/skills/report-layout.md +290 -0
- package/src/content/skills/rls-design.md +527 -0
- package/src/content/skills/semantic-model.md +229 -0
- package/src/content/skills/testing-validation.md +635 -0
- package/src/content/skills/theme-tweaker.md +618 -0
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// RETAIL ANALYTICS - DAX MEASURE LIBRARY
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Organized by category for easy navigation and maintenance
|
|
5
|
+
// All measures follow BI Agent Superpowers naming conventions
|
|
6
|
+
// ============================================================================
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
// ----------------------------------------------------------------------------
|
|
10
|
+
// BASE MEASURES
|
|
11
|
+
// ----------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
Revenue =
|
|
14
|
+
SUM(FactSales[Amount])
|
|
15
|
+
|
|
16
|
+
Cost =
|
|
17
|
+
SUMX(
|
|
18
|
+
FactSales,
|
|
19
|
+
FactSales[Quantity] * RELATED(DimProduct[UnitCost])
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
Profit =
|
|
23
|
+
[Revenue] - [Cost]
|
|
24
|
+
|
|
25
|
+
Profit Margin % =
|
|
26
|
+
DIVIDE([Profit], [Revenue])
|
|
27
|
+
|
|
28
|
+
Quantity =
|
|
29
|
+
SUM(FactSales[Quantity])
|
|
30
|
+
|
|
31
|
+
Transactions =
|
|
32
|
+
COUNTROWS(FactSales)
|
|
33
|
+
|
|
34
|
+
Avg Order Value =
|
|
35
|
+
DIVIDE([Revenue], [Transactions])
|
|
36
|
+
|
|
37
|
+
Avg Unit Price =
|
|
38
|
+
DIVIDE([Revenue], [Quantity])
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
// ----------------------------------------------------------------------------
|
|
42
|
+
// TIME INTELLIGENCE - YEAR-TO-DATE
|
|
43
|
+
// ----------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
Revenue YTD =
|
|
46
|
+
TOTALYTD([Revenue], DimDate[Date])
|
|
47
|
+
|
|
48
|
+
Profit YTD =
|
|
49
|
+
TOTALYTD([Profit], DimDate[Date])
|
|
50
|
+
|
|
51
|
+
Quantity YTD =
|
|
52
|
+
TOTALYTD([Quantity], DimDate[Date])
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
// ----------------------------------------------------------------------------
|
|
56
|
+
// TIME INTELLIGENCE - PRIOR YEAR
|
|
57
|
+
// ----------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
Revenue PY =
|
|
60
|
+
CALCULATE(
|
|
61
|
+
[Revenue],
|
|
62
|
+
SAMEPERIODLASTYEAR(DimDate[Date])
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
Profit PY =
|
|
66
|
+
CALCULATE(
|
|
67
|
+
[Profit],
|
|
68
|
+
SAMEPERIODLASTYEAR(DimDate[Date])
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
Revenue YTD PY =
|
|
72
|
+
CALCULATE(
|
|
73
|
+
[Revenue YTD],
|
|
74
|
+
SAMEPERIODLASTYEAR(DimDate[Date])
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
// ----------------------------------------------------------------------------
|
|
79
|
+
// TIME INTELLIGENCE - GROWTH RATES
|
|
80
|
+
// ----------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
Revenue YoY % =
|
|
83
|
+
VAR _Current = [Revenue]
|
|
84
|
+
VAR _PY = [Revenue PY]
|
|
85
|
+
RETURN
|
|
86
|
+
DIVIDE(_Current - _PY, _PY)
|
|
87
|
+
|
|
88
|
+
Revenue YoY Var =
|
|
89
|
+
[Revenue] - [Revenue PY]
|
|
90
|
+
|
|
91
|
+
Profit YoY % =
|
|
92
|
+
VAR _Current = [Profit]
|
|
93
|
+
VAR _PY = [Profit PY]
|
|
94
|
+
RETURN
|
|
95
|
+
DIVIDE(_Current - _PY, _PY)
|
|
96
|
+
|
|
97
|
+
Revenue YTD YoY % =
|
|
98
|
+
VAR _Current = [Revenue YTD]
|
|
99
|
+
VAR _PY = [Revenue YTD PY]
|
|
100
|
+
RETURN
|
|
101
|
+
DIVIDE(_Current - _PY, _PY)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
// ----------------------------------------------------------------------------
|
|
105
|
+
// TIME INTELLIGENCE - ROLLING PERIODS
|
|
106
|
+
// ----------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
Revenue R3M =
|
|
109
|
+
CALCULATE(
|
|
110
|
+
[Revenue],
|
|
111
|
+
DATESINPERIOD(DimDate[Date], MAX(DimDate[Date]), -3, MONTH)
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
Revenue R12M =
|
|
115
|
+
CALCULATE(
|
|
116
|
+
[Revenue],
|
|
117
|
+
DATESINPERIOD(DimDate[Date], MAX(DimDate[Date]), -12, MONTH)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
Revenue R3M Avg =
|
|
121
|
+
AVERAGEX(
|
|
122
|
+
DATESINPERIOD(DimDate[Date], MAX(DimDate[Date]), -3, MONTH),
|
|
123
|
+
[Revenue]
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
// ----------------------------------------------------------------------------
|
|
128
|
+
// TIME INTELLIGENCE - MONTH COMPARISONS
|
|
129
|
+
// ----------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
Revenue PM =
|
|
132
|
+
CALCULATE(
|
|
133
|
+
[Revenue],
|
|
134
|
+
PREVIOUSMONTH(DimDate[Date])
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
Revenue MoM % =
|
|
138
|
+
VAR _Current = [Revenue]
|
|
139
|
+
VAR _PM = [Revenue PM]
|
|
140
|
+
RETURN
|
|
141
|
+
DIVIDE(_Current - _PM, _PM)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
// ----------------------------------------------------------------------------
|
|
145
|
+
// RANKINGS
|
|
146
|
+
// ----------------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
Product Rank =
|
|
149
|
+
IF(
|
|
150
|
+
HASONEVALUE(DimProduct[ProductName]),
|
|
151
|
+
RANKX(
|
|
152
|
+
ALL(DimProduct[ProductName]),
|
|
153
|
+
[Revenue],
|
|
154
|
+
,
|
|
155
|
+
DESC,
|
|
156
|
+
DENSE
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
Store Rank =
|
|
161
|
+
IF(
|
|
162
|
+
HASONEVALUE(DimStore[StoreName]),
|
|
163
|
+
RANKX(
|
|
164
|
+
ALL(DimStore[StoreName]),
|
|
165
|
+
[Revenue],
|
|
166
|
+
,
|
|
167
|
+
DESC,
|
|
168
|
+
DENSE
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
Customer Rank =
|
|
173
|
+
IF(
|
|
174
|
+
HASONEVALUE(DimCustomer[CustomerName]),
|
|
175
|
+
RANKX(
|
|
176
|
+
ALL(DimCustomer[CustomerName]),
|
|
177
|
+
[Revenue],
|
|
178
|
+
,
|
|
179
|
+
DESC,
|
|
180
|
+
DENSE
|
|
181
|
+
)
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
Category Rank =
|
|
185
|
+
IF(
|
|
186
|
+
HASONEVALUE(DimProduct[Category]),
|
|
187
|
+
RANKX(
|
|
188
|
+
ALL(DimProduct[Category]),
|
|
189
|
+
[Revenue],
|
|
190
|
+
,
|
|
191
|
+
DESC,
|
|
192
|
+
DENSE
|
|
193
|
+
)
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
// ----------------------------------------------------------------------------
|
|
198
|
+
// TOP N CALCULATIONS
|
|
199
|
+
// ----------------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
Revenue Top 10 Products =
|
|
202
|
+
CALCULATE(
|
|
203
|
+
[Revenue],
|
|
204
|
+
TOPN(10, ALL(DimProduct[ProductName]), [Revenue], DESC)
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
Revenue Top 5 Customers =
|
|
208
|
+
CALCULATE(
|
|
209
|
+
[Revenue],
|
|
210
|
+
TOPN(5, ALL(DimCustomer[CustomerName]), [Revenue], DESC)
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
Revenue Top 3 Stores =
|
|
214
|
+
CALCULATE(
|
|
215
|
+
[Revenue],
|
|
216
|
+
TOPN(3, ALL(DimStore[StoreName]), [Revenue], DESC)
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
// Percentage of top 10 products
|
|
220
|
+
Top 10 Products % =
|
|
221
|
+
DIVIDE(
|
|
222
|
+
[Revenue Top 10 Products],
|
|
223
|
+
CALCULATE([Revenue], ALL(DimProduct))
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
// ----------------------------------------------------------------------------
|
|
228
|
+
// PERCENTAGES & RATIOS
|
|
229
|
+
// ----------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
Revenue % of Total =
|
|
232
|
+
DIVIDE(
|
|
233
|
+
[Revenue],
|
|
234
|
+
CALCULATE([Revenue], ALL(FactSales))
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
Revenue % of Category =
|
|
238
|
+
DIVIDE(
|
|
239
|
+
[Revenue],
|
|
240
|
+
CALCULATE([Revenue], ALLEXCEPT(DimProduct, DimProduct[Category]))
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
Revenue % of Store =
|
|
244
|
+
DIVIDE(
|
|
245
|
+
[Revenue],
|
|
246
|
+
CALCULATE([Revenue], ALLEXCEPT(DimStore, DimStore[StoreName]))
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
Revenue % of Region =
|
|
250
|
+
DIVIDE(
|
|
251
|
+
[Revenue],
|
|
252
|
+
CALCULATE([Revenue], ALLEXCEPT(DimStore, DimStore[Region]))
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
// ----------------------------------------------------------------------------
|
|
257
|
+
// CUSTOMER METRICS
|
|
258
|
+
// ----------------------------------------------------------------------------
|
|
259
|
+
|
|
260
|
+
Customer Count =
|
|
261
|
+
DISTINCTCOUNT(FactSales[CustomerKey])
|
|
262
|
+
|
|
263
|
+
New Customers =
|
|
264
|
+
VAR _CurrentPeriodStart = MIN(DimDate[Date])
|
|
265
|
+
RETURN
|
|
266
|
+
CALCULATE(
|
|
267
|
+
DISTINCTCOUNT(FactSales[CustomerKey]),
|
|
268
|
+
FILTER(
|
|
269
|
+
ALL(DimCustomer),
|
|
270
|
+
DimCustomer[JoinDate] >= _CurrentPeriodStart
|
|
271
|
+
)
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
Repeat Customers =
|
|
275
|
+
VAR _CustomersThisPeriod = VALUES(FactSales[CustomerKey])
|
|
276
|
+
VAR _CustomersWithHistory =
|
|
277
|
+
FILTER(
|
|
278
|
+
_CustomersThisPeriod,
|
|
279
|
+
CALCULATE(
|
|
280
|
+
COUNTROWS(FactSales),
|
|
281
|
+
ALLEXCEPT(FactSales, FactSales[CustomerKey]),
|
|
282
|
+
DimDate[Date] < MIN(DimDate[Date])
|
|
283
|
+
) > 0
|
|
284
|
+
)
|
|
285
|
+
RETURN
|
|
286
|
+
COUNTROWS(_CustomersWithHistory)
|
|
287
|
+
|
|
288
|
+
Revenue per Customer =
|
|
289
|
+
DIVIDE([Revenue], [Customer Count])
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
// ----------------------------------------------------------------------------
|
|
293
|
+
// PRODUCT METRICS
|
|
294
|
+
// ----------------------------------------------------------------------------
|
|
295
|
+
|
|
296
|
+
Product Count =
|
|
297
|
+
DISTINCTCOUNT(FactSales[ProductKey])
|
|
298
|
+
|
|
299
|
+
Active Products =
|
|
300
|
+
CALCULATE(
|
|
301
|
+
DISTINCTCOUNT(DimProduct[ProductKey]),
|
|
302
|
+
DimProduct[IsActive] = TRUE()
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
Units per Transaction =
|
|
306
|
+
DIVIDE([Quantity], [Transactions])
|
|
307
|
+
|
|
308
|
+
Basket Size =
|
|
309
|
+
AVERAGEX(
|
|
310
|
+
VALUES(FactSales[SalesKey]),
|
|
311
|
+
CALCULATE(DISTINCTCOUNT(FactSales[ProductKey]))
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
// ----------------------------------------------------------------------------
|
|
316
|
+
// STORE METRICS
|
|
317
|
+
// ----------------------------------------------------------------------------
|
|
318
|
+
|
|
319
|
+
Store Count =
|
|
320
|
+
DISTINCTCOUNT(FactSales[StoreKey])
|
|
321
|
+
|
|
322
|
+
Revenue per SqFt =
|
|
323
|
+
DIVIDE(
|
|
324
|
+
[Revenue],
|
|
325
|
+
SUM(DimStore[SquareFeet])
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
Revenue per Employee =
|
|
329
|
+
DIVIDE(
|
|
330
|
+
[Revenue],
|
|
331
|
+
SUM(DimStore[EmployeeCount])
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
// ----------------------------------------------------------------------------
|
|
336
|
+
// CONDITIONAL FORMATTING MEASURES
|
|
337
|
+
// ----------------------------------------------------------------------------
|
|
338
|
+
|
|
339
|
+
Revenue YoY Color =
|
|
340
|
+
VAR _YoY = [Revenue YoY %]
|
|
341
|
+
RETURN
|
|
342
|
+
SWITCH(
|
|
343
|
+
TRUE(),
|
|
344
|
+
ISBLANK(_YoY), "#A3A3A3", // Neutral gray
|
|
345
|
+
_YoY >= 0.1, "#166534", // Dark green - exceeds 10%
|
|
346
|
+
_YoY >= 0, "#22C55E", // Green - positive
|
|
347
|
+
_YoY >= -0.1, "#EAB308", // Yellow - slightly down
|
|
348
|
+
"#991B1B" // Dark red - down >10%
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
Profit Margin Color =
|
|
352
|
+
VAR _Margin = [Profit Margin %]
|
|
353
|
+
RETURN
|
|
354
|
+
SWITCH(
|
|
355
|
+
TRUE(),
|
|
356
|
+
ISBLANK(_Margin), "#A3A3A3",
|
|
357
|
+
_Margin >= 0.25, "#166534", // High margin
|
|
358
|
+
_Margin >= 0.15, "#22C55E", // Target margin
|
|
359
|
+
_Margin >= 0.10, "#EAB308", // Low margin
|
|
360
|
+
"#991B1B" // Critical margin
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
Trend Indicator =
|
|
364
|
+
VAR _YoY = [Revenue YoY %]
|
|
365
|
+
RETURN
|
|
366
|
+
SWITCH(
|
|
367
|
+
TRUE(),
|
|
368
|
+
ISBLANK(_YoY), "•",
|
|
369
|
+
_YoY >= 0.1, "▲▲",
|
|
370
|
+
_YoY >= 0, "▲",
|
|
371
|
+
_YoY >= -0.1, "▼",
|
|
372
|
+
"▼▼"
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
// ----------------------------------------------------------------------------
|
|
377
|
+
// DISPLAY / HELPER MEASURES
|
|
378
|
+
// ----------------------------------------------------------------------------
|
|
379
|
+
|
|
380
|
+
Revenue Display =
|
|
381
|
+
VAR _Value = [Revenue]
|
|
382
|
+
RETURN
|
|
383
|
+
IF(
|
|
384
|
+
_Value >= 1000000,
|
|
385
|
+
FORMAT(_Value / 1000000, "$#,##0.0") & "M",
|
|
386
|
+
IF(
|
|
387
|
+
_Value >= 1000,
|
|
388
|
+
FORMAT(_Value / 1000, "$#,##0.0") & "K",
|
|
389
|
+
FORMAT(_Value, "$#,##0")
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
Revenue YoY Display =
|
|
394
|
+
VAR _YoY = [Revenue YoY %]
|
|
395
|
+
RETURN
|
|
396
|
+
IF(
|
|
397
|
+
ISBLANK(_YoY),
|
|
398
|
+
"--",
|
|
399
|
+
IF(_YoY >= 0, "+", "") & FORMAT(_YoY, "0.0%")
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
Selected Period =
|
|
403
|
+
VAR _MinDate = MIN(DimDate[Date])
|
|
404
|
+
VAR _MaxDate = MAX(DimDate[Date])
|
|
405
|
+
RETURN
|
|
406
|
+
FORMAT(_MinDate, "MMM D, YYYY") & " - " & FORMAT(_MaxDate, "MMM D, YYYY")
|
|
407
|
+
|
|
408
|
+
Last Refresh =
|
|
409
|
+
"Last updated: " & FORMAT(NOW(), "MMM D, YYYY h:mm AM/PM")
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
// ----------------------------------------------------------------------------
|
|
413
|
+
// DATA QUALITY CHECKS
|
|
414
|
+
// ----------------------------------------------------------------------------
|
|
415
|
+
|
|
416
|
+
_Data Quality Sales =
|
|
417
|
+
VAR _TotalRows = COUNTROWS(FactSales)
|
|
418
|
+
VAR _NullAmount = CALCULATE(COUNTROWS(FactSales), ISBLANK(FactSales[Amount]))
|
|
419
|
+
VAR _NegativeAmount = CALCULATE(COUNTROWS(FactSales), FactSales[Amount] < 0)
|
|
420
|
+
RETURN
|
|
421
|
+
"Total: " & _TotalRows &
|
|
422
|
+
" | Null Amounts: " & _NullAmount &
|
|
423
|
+
" | Negative: " & _NegativeAmount
|
|
424
|
+
|
|
425
|
+
_Missing Keys =
|
|
426
|
+
VAR _OrphanProducts =
|
|
427
|
+
COUNTROWS(
|
|
428
|
+
FILTER(
|
|
429
|
+
FactSales,
|
|
430
|
+
ISBLANK(RELATED(DimProduct[ProductName]))
|
|
431
|
+
)
|
|
432
|
+
)
|
|
433
|
+
VAR _OrphanCustomers =
|
|
434
|
+
COUNTROWS(
|
|
435
|
+
FILTER(
|
|
436
|
+
FactSales,
|
|
437
|
+
ISBLANK(RELATED(DimCustomer[CustomerName]))
|
|
438
|
+
)
|
|
439
|
+
)
|
|
440
|
+
RETURN
|
|
441
|
+
"Orphan Products: " & _OrphanProducts &
|
|
442
|
+
" | Orphan Customers: " & _OrphanCustomers
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
// ============================================================================
|
|
446
|
+
// MEASURE ORGANIZATION
|
|
447
|
+
// ============================================================================
|
|
448
|
+
// Create Display Folders in Power BI:
|
|
449
|
+
//
|
|
450
|
+
// 📊 Base Metrics
|
|
451
|
+
// - Revenue, Cost, Profit, Profit Margin %, Quantity, Transactions, AOV
|
|
452
|
+
//
|
|
453
|
+
// 📅 Time Intelligence
|
|
454
|
+
// - YTD: Revenue YTD, Profit YTD, Quantity YTD
|
|
455
|
+
// - Prior Year: Revenue PY, Profit PY, Revenue YTD PY
|
|
456
|
+
// - Growth: Revenue YoY %, Revenue YoY Var, Profit YoY %, Revenue YTD YoY %
|
|
457
|
+
// - Rolling: Revenue R3M, Revenue R12M, Revenue R3M Avg
|
|
458
|
+
// - Month: Revenue PM, Revenue MoM %
|
|
459
|
+
//
|
|
460
|
+
// 🏆 Rankings
|
|
461
|
+
// - Product Rank, Store Rank, Customer Rank, Category Rank
|
|
462
|
+
//
|
|
463
|
+
// 🎯 Top N
|
|
464
|
+
// - Revenue Top 10 Products, Revenue Top 5 Customers, Revenue Top 3 Stores
|
|
465
|
+
//
|
|
466
|
+
// 📈 Percentages
|
|
467
|
+
// - Revenue % of Total, Revenue % of Category, Revenue % of Store
|
|
468
|
+
//
|
|
469
|
+
// 👤 Customer
|
|
470
|
+
// - Customer Count, New Customers, Repeat Customers, Revenue per Customer
|
|
471
|
+
//
|
|
472
|
+
// 🏪 Store
|
|
473
|
+
// - Store Count, Revenue per SqFt, Revenue per Employee
|
|
474
|
+
//
|
|
475
|
+
// 🎨 Formatting
|
|
476
|
+
// - Revenue YoY Color, Profit Margin Color, Trend Indicator
|
|
477
|
+
//
|
|
478
|
+
// 🔧 Helpers (Hidden)
|
|
479
|
+
// - Revenue Display, Selected Period, Last Refresh
|
|
480
|
+
// - _Data Quality Sales, _Missing Keys
|
|
481
|
+
// ============================================================================
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Supply Chain Analytics Example
|
|
2
|
+
|
|
3
|
+
Reference implementation for a supply chain Power BI model.
|
|
4
|
+
|
|
5
|
+
## Business Context
|
|
6
|
+
|
|
7
|
+
Track inventory levels, supplier performance, lead times, and fulfillment rates across warehouses and distribution centers.
|
|
8
|
+
|
|
9
|
+
## Key Metrics
|
|
10
|
+
|
|
11
|
+
| Metric | Description |
|
|
12
|
+
|--------|-------------|
|
|
13
|
+
| Fill Rate | % of orders fulfilled completely |
|
|
14
|
+
| Inventory Turnover | How often inventory is sold and replaced |
|
|
15
|
+
| Days of Supply | Days of inventory remaining at current demand |
|
|
16
|
+
| On-Time Delivery | % of orders delivered by promised date |
|
|
17
|
+
| Supplier Lead Time | Average days from PO to receipt |
|
|
18
|
+
| Stockout Rate | % of SKUs with zero inventory |
|
|
19
|
+
| Carrying Cost | Cost to hold inventory per unit per period |
|
|
20
|
+
|
|
21
|
+
## Data Model
|
|
22
|
+
|
|
23
|
+
See [data-model.md](data-model.md) for the complete star schema design.
|
|
24
|
+
|
|
25
|
+
## Files
|
|
26
|
+
|
|
27
|
+
| File | Purpose |
|
|
28
|
+
|------|---------|
|
|
29
|
+
| `data-model.md` | Star schema with tables and relationships |
|
|
30
|
+
| `measures.dax` | Core DAX measures for supply chain KPIs |
|
|
31
|
+
|
|
32
|
+
## Report Pages
|
|
33
|
+
|
|
34
|
+
1. **Executive Summary** — KPI cards, fill rate trend, top suppliers
|
|
35
|
+
2. **Inventory Health** — Stock levels by warehouse, days of supply heatmap
|
|
36
|
+
3. **Supplier Scorecard** — Lead time, quality, on-time delivery by supplier
|
|
37
|
+
4. **Demand vs Supply** — Forecast accuracy, stockout risk analysis
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Supply Chain Data Model
|
|
2
|
+
|
|
3
|
+
## Star Schema
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
┌─────────────┐
|
|
7
|
+
│ DimDate │
|
|
8
|
+
│─────────────│
|
|
9
|
+
│ DateKey (PK)│
|
|
10
|
+
│ Date │
|
|
11
|
+
│ Month │
|
|
12
|
+
│ Quarter │
|
|
13
|
+
│ Year │
|
|
14
|
+
│ FiscalMonth │
|
|
15
|
+
│ FiscalYear │
|
|
16
|
+
└──────┬──────┘
|
|
17
|
+
│
|
|
18
|
+
┌─────────────┐ ┌───────┴───────┐ ┌──────────────┐
|
|
19
|
+
│ DimSupplier │ │ FactInventory │ │ DimWarehouse │
|
|
20
|
+
│─────────────│ │───────────────│ │──────────────│
|
|
21
|
+
│ SupplierKey │◄───│ SupplierKey │───►│ WarehouseKey │
|
|
22
|
+
│ SupplierName│ │ WarehouseKey │ │ WarehouseName│
|
|
23
|
+
│ Country │ │ ProductKey │ │ Region │
|
|
24
|
+
│ LeadTimeDays│ │ DateKey │ │ Capacity │
|
|
25
|
+
│ Rating │ │ QuantityOnHand│ │ Type │
|
|
26
|
+
└─────────────┘ │ QuantityOnOrder│ └──────────────┘
|
|
27
|
+
│ ReorderPoint │
|
|
28
|
+
┌─────────────┐ │ UnitCost │ ┌──────────────┐
|
|
29
|
+
│ DimProduct │ │ DaysOfSupply │ │ FactOrders │
|
|
30
|
+
│─────────────│ └───────────────┘ │──────────────│
|
|
31
|
+
│ ProductKey │◄────────────────────────│ ProductKey │
|
|
32
|
+
│ ProductName │ │ │ CustomerKey │
|
|
33
|
+
│ Category │ │ │ DateKey │
|
|
34
|
+
│ SubCategory │ ▼ │ WarehouseKey │
|
|
35
|
+
│ SKU │ ┌───────────────┐ │ Quantity │
|
|
36
|
+
│ UnitWeight │ │FactPurchaseOrder│ │ ShipDate │
|
|
37
|
+
│ IsActive │ │───────────────│ │ PromisedDate │
|
|
38
|
+
└─────────────┘ │ POKey (PK) │ │ IsOnTime │
|
|
39
|
+
│ SupplierKey │ │ IsFilled │
|
|
40
|
+
│ ProductKey │ └──────────────┘
|
|
41
|
+
│ DateKey │
|
|
42
|
+
│ Quantity │
|
|
43
|
+
│ UnitCost │
|
|
44
|
+
│ ReceivedDate │
|
|
45
|
+
│ LeadTimeDays │
|
|
46
|
+
└───────────────┘
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Relationships
|
|
50
|
+
|
|
51
|
+
| From | To | Cardinality | Direction |
|
|
52
|
+
|------|----|-------------|-----------|
|
|
53
|
+
| FactInventory[DateKey] | DimDate[DateKey] | Many-to-One | Single |
|
|
54
|
+
| FactInventory[ProductKey] | DimProduct[ProductKey] | Many-to-One | Single |
|
|
55
|
+
| FactInventory[SupplierKey] | DimSupplier[SupplierKey] | Many-to-One | Single |
|
|
56
|
+
| FactInventory[WarehouseKey] | DimWarehouse[WarehouseKey] | Many-to-One | Single |
|
|
57
|
+
| FactOrders[DateKey] | DimDate[DateKey] | Many-to-One | Single |
|
|
58
|
+
| FactOrders[ProductKey] | DimProduct[ProductKey] | Many-to-One | Single |
|
|
59
|
+
| FactOrders[WarehouseKey] | DimWarehouse[WarehouseKey] | Many-to-One | Single |
|
|
60
|
+
| FactPurchaseOrder[DateKey] | DimDate[DateKey] | Many-to-One | Single |
|
|
61
|
+
| FactPurchaseOrder[ProductKey] | DimProduct[ProductKey] | Many-to-One | Single |
|
|
62
|
+
| FactPurchaseOrder[SupplierKey] | DimSupplier[SupplierKey] | Many-to-One | Single |
|
|
63
|
+
|
|
64
|
+
## Notes
|
|
65
|
+
|
|
66
|
+
- `FactInventory` is a periodic snapshot (daily snapshot of stock levels)
|
|
67
|
+
- `FactOrders` tracks customer orders and fulfillment
|
|
68
|
+
- `FactPurchaseOrder` tracks supplier orders and lead times
|
|
69
|
+
- `DaysOfSupply` in FactInventory is pre-calculated for performance
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Supply Chain KPI Measures
|
|
2
|
+
// ========================
|
|
3
|
+
// Core measures for supply chain analytics model.
|
|
4
|
+
|
|
5
|
+
// --- Inventory Metrics ---
|
|
6
|
+
|
|
7
|
+
// Total units currently in stock across all warehouses
|
|
8
|
+
TotalOnHand =
|
|
9
|
+
SUM(FactInventory[QuantityOnHand])
|
|
10
|
+
|
|
11
|
+
// Total units on order from suppliers
|
|
12
|
+
TotalOnOrder =
|
|
13
|
+
SUM(FactInventory[QuantityOnOrder])
|
|
14
|
+
|
|
15
|
+
// Inventory turnover: how many times inventory is sold and replaced
|
|
16
|
+
// Higher is better — indicates efficient inventory management
|
|
17
|
+
InventoryTurnover =
|
|
18
|
+
VAR _COGS = SUM(FactOrders[Quantity]) * AVERAGE(FactInventory[UnitCost])
|
|
19
|
+
VAR _AvgInventory = AVERAGE(FactInventory[QuantityOnHand]) * AVERAGE(FactInventory[UnitCost])
|
|
20
|
+
RETURN DIVIDE(_COGS, _AvgInventory)
|
|
21
|
+
|
|
22
|
+
// Average days of supply remaining at current demand rate
|
|
23
|
+
AvgDaysOfSupply =
|
|
24
|
+
AVERAGE(FactInventory[DaysOfSupply])
|
|
25
|
+
|
|
26
|
+
// Percentage of SKUs with zero inventory (stockout)
|
|
27
|
+
StockoutRate =
|
|
28
|
+
VAR _TotalSKUs = DISTINCTCOUNT(FactInventory[ProductKey])
|
|
29
|
+
VAR _StockoutSKUs =
|
|
30
|
+
CALCULATE(
|
|
31
|
+
DISTINCTCOUNT(FactInventory[ProductKey]),
|
|
32
|
+
FactInventory[QuantityOnHand] = 0
|
|
33
|
+
)
|
|
34
|
+
RETURN DIVIDE(_StockoutSKUs, _TotalSKUs)
|
|
35
|
+
|
|
36
|
+
// --- Fulfillment Metrics ---
|
|
37
|
+
|
|
38
|
+
// Fill rate: percentage of orders fulfilled completely
|
|
39
|
+
FillRate =
|
|
40
|
+
VAR _TotalOrders = COUNTROWS(FactOrders)
|
|
41
|
+
VAR _FilledOrders = CALCULATE(COUNTROWS(FactOrders), FactOrders[IsFilled] = TRUE())
|
|
42
|
+
RETURN DIVIDE(_FilledOrders, _TotalOrders)
|
|
43
|
+
|
|
44
|
+
// On-time delivery rate
|
|
45
|
+
OnTimeDeliveryRate =
|
|
46
|
+
VAR _TotalOrders = COUNTROWS(FactOrders)
|
|
47
|
+
VAR _OnTimeOrders = CALCULATE(COUNTROWS(FactOrders), FactOrders[IsOnTime] = TRUE())
|
|
48
|
+
RETURN DIVIDE(_OnTimeOrders, _TotalOrders)
|
|
49
|
+
|
|
50
|
+
// --- Supplier Metrics ---
|
|
51
|
+
|
|
52
|
+
// Average supplier lead time in days
|
|
53
|
+
AvgLeadTime =
|
|
54
|
+
AVERAGE(FactPurchaseOrder[LeadTimeDays])
|
|
55
|
+
|
|
56
|
+
// Supplier on-time rate (received by expected date)
|
|
57
|
+
SupplierOnTimeRate =
|
|
58
|
+
VAR _TotalPOs = COUNTROWS(FactPurchaseOrder)
|
|
59
|
+
VAR _OnTimePOs =
|
|
60
|
+
CALCULATE(
|
|
61
|
+
COUNTROWS(FactPurchaseOrder),
|
|
62
|
+
FactPurchaseOrder[LeadTimeDays] <= RELATED(DimSupplier[LeadTimeDays])
|
|
63
|
+
)
|
|
64
|
+
RETURN DIVIDE(_OnTimePOs, _TotalPOs)
|
|
65
|
+
|
|
66
|
+
// --- Cost Metrics ---
|
|
67
|
+
|
|
68
|
+
// Total inventory carrying cost (simplified: unitCost * quantity * holding rate)
|
|
69
|
+
CarryingCost =
|
|
70
|
+
SUMX(
|
|
71
|
+
FactInventory,
|
|
72
|
+
FactInventory[QuantityOnHand] * FactInventory[UnitCost] * 0.25 / 365
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
// Total purchase order value
|
|
76
|
+
TotalPOValue =
|
|
77
|
+
SUMX(FactPurchaseOrder, FactPurchaseOrder[Quantity] * FactPurchaseOrder[UnitCost])
|