Power BI · COMPLETE FINANCIAL PROJECT

How I turned 216,858 journal entries into a financial report anyone can explore

Three companies. Two years of accounts. A single model that connects the balance sheet, income statement and cash flow without leaving Power BI.

−€1,165,650
Free cash flow previous year
→
€678,209
Free cash flow 2023

↓ Discover the project

Before we start

What is a financial report?

If you’ve never worked with accounting, think of it as three different questions about the same company.

Balance sheet

It’s a snapshot

What does the company own and owe today?

This is where assets such as cash or stock appear, along with debts and equity.

Income statement (P&L)

It’s a film

How has it made or lost money during the year?

This is where revenue, expenses, EBITDA and profit appear.

Cash flow

It answers another question

Has money come into or gone out of the till?

Because a company can make a profit and still run out of cash.

The challenge is that these three pieces should tell the same story. And that’s exactly what I tried to build.

The challenge

When each company tells a different story.

The data already existed. There were three different companies, each with its own journal, and together they had built up 216,858 entries across 2022 and 2023.

The problem came when you wanted to answer something as simple as:

How is the group really doing?

The balance sheet, P&L and cash flow could be viewed separately, but there was no consolidated view that let you move between them without rebuilding the analysis by hand.

The more versions of the same report there are, the easier it is for two people to reach different conclusions from supposedly identical data. My aim was to prevent exactly that.

The idea that changed the project

I wanted every KPI to be able to stand on its own.

While designing the model, I asked myself a question.

What happens if someone asks me where this number comes from?

I didn’t want to answer by opening Excel.

I wanted to answer with a click.

That’s why the whole report revolves around a very simple idea.

Every figure should be traceable down to the entry that created it.

That principle ended up shaping almost every decision in the project.

Today that path really exists: from the trial balance — €187,730,234.71 of debits matching exactly €187,730,234.71 of credits — I can drill down to a sub-account, from there to its general ledger, and from there to a specific entry. Without leaving the report.

How I built it

I started with the model, not the charts.

Many dashboards start by designing visuals.

I did exactly the opposite.

First I built a model able to support three different financial statements without duplicating logic or breaking calculations.

0

tables

0

relationships

0

DAX measures

At the centre are FactDiario, with the actual journal entries, and FactPresupuesto, with the budget data. Both connect to the same nine dimensions: Calendar, Companies, Sources, Accounts, Partners, and the four that give shape to each financial statement — dimPyG, dimBalance, dimCF and DimApuntes.

The model’s only bidirectional relationship connects FactDiario with DimApuntes. I left it that way because it was needed to calculate cash flow correctly when filtering by entry type. Everything else keeps a single filter direction, so the model behaves more predictably.

A decision that saved me a lot of trouble

Keeping actual and budget separate.

During the build I found that trying to mix both scenarios in a single table made the calculations much more complicated. Separating them meant any comparison worked exactly the same way throughout the report.

FactDiario and FactPresupuesto share the same dimensions, so the budget variance reuses the same filter context as any other measure — and so does the year-end projection. No duplicated logic anywhere in the model.

This separation is what makes it possible to compare actual vs budget at any level, from the group total down to a single company, without breaking consistency between the balance sheet, P&L and cash flow.

Schema

FactDiario · FactPresupuesto
↳ Calendario ↳ Empresas ↳ Orígenes ↳ CuentasContables ↳ Partners ↳ dimPyG (hierarchy) ↳ dimBalance (hierarchy) ↳ dimCF (hierarchy) ↳ DimApuntes (hierarchy)

The small detail that makes the report more reliable

The validation checklist.

There’s one page that usually goes unnoticed.

And yet it’s one of my favourites.

Before analysing results, the model automatically checks whether there are:

  • unclassified accounts,
  • unbalanced entries,
  • mapping problems.

The Unclassified accounts table is recalculated on every refresh. That means the report itself tries to catch errors before they show up as if they were real results.

It seemed more useful to build that safeguard into the model than to rely on manual reviews afterwards.

With the three years of data loaded, the checklist now comes out clean: zero unbalanced entries, zero unclassified accounts. It’s the first screen I look at before trusting any figure in the rest of the report.

The hardest part

Projecting a year end without inventing the data.

The measure that took me longest was probably the year-end projection.

Up to October I use actual data.

From there on, I use the budget.

But doing it without breaking charts or tables was far more complicated. There’s a configurable cut-off date in the model — set to 31 October 2023 — after which every measure automatically switches from actual data to budget, and the chart series stays visually continuous instead of leaving a gap between actual and projected.

The result, month by month: €309,284.99 of actuals accumulated up to the cut-off, against the €173,511.68 the original budget expected for the whole year. The combined year-end projection comes to €196,404.62 — neither the actual nor the budgeted figure, but the best estimate with the information available at each point.

That was probably when I learnt the most about DAX during this project.

What the dashboard tells you

Thirteen content pages. Seven that only appear when you need them.

The report has 20 pages in total. You navigate from a fixed header with five entry points — Home · Checklist · Trial balance · Balance sheet · P&L · Cash flow — but each block hides its own path into the detail.

Each block answers a different question.

  • Home → a panel with 12 KPIs that sums up the situation in seconds.
  • Checklist → can I trust the data before analysing it?
  • Trial balance → its own three-page block: from the aggregated account to the individual entry (Trial balance → General ledger → Entry detail).
  • Balance sheet → financial structure and how it evolves, with a second page for the month-by-month detail.
  • P&L → four views: quarterly trend, year-on-year comparison, variance against budget and year-end projection.
  • Cash flow → where the group’s cash comes from and where it goes.

The other 7 pages don’t appear in any menu: they’re tooltip pages, which Power BI shows floating when I hover over a point on the balance sheet, P&L or treasury trend charts. Instead of the basic tooltip, a mini-page appears with the figure properly formatted and the same visual identity as the rest of the report. Most reports use one or two pages like this; I used seven, one for each chart that needed it.

These are some of the 12 KPIs on the home panel:

€342,142

EBITDA 2023

12.70%

ROE

6.94%

ROA

2,07

Solvency

1,88

Acid test

Complete financial report dashboard — view 1 Complete financial report dashboard — view 2 Complete financial report dashboard — view 3
View the interactive dashboard Power BI · DAX · Drill-through · Accounting modelling

The figure that best sums up the project

Cash changed completely from one year to the next.

−€1,165,650 — €678,209

What mattered wasn’t the figure itself. What mattered was being able to explain which items made up that result without redoing the analysis from scratch.
That change was the moment I felt the balance sheet, P&L and cash flow stopped being three separate reports and became a single story.

Tools

Tech stack

Power BI

The complete model, navigation across the report’s 20 pages (13 content pages, 7 tooltip pages) and drill-through from any KPI down to the source journal entry.

DAX

Solvency and liquidity ratios, EBITDA calculations, year-on-year change, variance against budget and the year-end projection logic.

Accounting star schema

19 tables and 15 relationships: FactDiario and FactPresupuesto connected to nine shared and hierarchy dimensions.

Drill-through

Navigation from any high-level KPI down to the individual journal entry that creates it.

Validation checklist

Catches unbalanced entries and unclassified accounts before they reach the analysis.

Year-end projection

Extrapolates the expected result at year end, combining actual data up to the cut-off date.

What I learnt

The best dashboard starts long before the dashboard.

If I had to sum up what I learnt from this project, I wouldn’t talk about the 174 DAX measures.

I’d talk about the model.

I learnt that a good dashboard doesn’t depend only on visual design.

It depends on every figure making sense, being checkable and staying consistent when you change company, period or financial statement.

That change of mindset is probably the most valuable thing I take away from this project.

Wrapping up

From thousands of accounting movements to a single financial story.

This project let me bring together several things I’m particularly interested in: data modelling, DAX, visualisation and business analysis.

The result is a report that tries to do something very simple to say and much harder to build.

Any figure can be explained without leaving the dashboard.

Open the dashboard in Power BI

Interactive dashboard published in the Power BI Service

See the rest of the projects

Full Power BI portfolio