Skip to content
Log in

Theory

Case: plan vs actual by price, volume and mix

Price volume mix analysis: splitting a plan vs actual miss into price, volume, mix and currency.

~9 min read · 10 exercises · 250 points

Before you start

September is in

On Klasna's product team, September's results have just come in. Sales beat the plan, and Leo credits the back-to-school promo. Hanna points out that contribution margin came in below plan: Klasna sold more and earned less.

This case closes the planning module. You'll take the gap between plan and actual apart into its causes, price, volume, mix and currency, and decide what the board should hear first.

Judge a month by contribution, not by sales

"Sales beat the plan" is the most common good-news headline, and often the most misleading. Sales can grow while the business earns less, when the extra sales come with discounts, cheaper products or costlier inputs.

Klasna's September: sales were 3,709,960 UAH against a plan of 3,647,800, +62,160. Contribution margin, what is left after tutor payouts, payment fees and the video bill, was 996,149.75 against 1,050,847, −54,697.25. The company sold more and earned less.

Contribution is the number that pays for salaries, the office and marketing, so it leads the note. Sales come second, as context for how the contribution moved.

Variance analysis then takes the contribution gap apart into causes: how many lessons (volume), which lessons (mix), at what price, and at what exchange rates. Split this way, the causes add up exactly to the total, and each one points to a different owner and a different decision.

  • Do
    "Contribution −54,697.25 against plan; sales +62,160."
  • Don't
    "Great month: we sold more than planned."

    More sales can still mean less money left.

Volume variance: how many lessons, valued at plan

The first piece of the bridge answers only one question: how many more (or fewer) units did we sell? Everything else stays at plan, so the extra units are valued at the plan's average contribution per unit:

Volume variance = (actual units − plan units) × plan average contribution per unit

The plan average is the plan's contribution divided by its units. Klasna's September plan: 1,050,847 UAH over 5,612 lessons = 187.25 UAH per lesson.

Actual lessons, summed over the six rows of the dataset: 3,640 + 540 + 1,060 + 170 + 400 + 80 = 5,890. That's 278 more than planned, so the volume variance is 278 × 187.25 = +52,055.50 UAH.

Dataset · 6 rows

September 2026: plan vs actual by subject and market

Families in Ukraine (ua) pay in UAH, families in the EU (eu) in EUR; prices are per lesson in that currency. Payment fee 2.5% of what families pay. Video + AI is billed in USD. Rates: plan EUR 45.00 and USD 42.00 UAH; actual September EUR 47.00 and USD 43.50 UAH.

subjectmarketcurrencyplan_lessonsactual_lessonsplan_price_per_lessonactual_price_per_lessonpayout_per_lesson_uahvideo_ai_usd_per_lesson
englishuaUAH318636406155854000.75
englisheuEUR52054015154000.75
mathsuaUAH112610606856854300.75
mathseuEUR18017016164300.75
programminguaUAH5004007207054750.75

First 5 of 6 rows

Download CSV

Using the plan average is deliberate. It treats the extra lessons as ordinary planned lessons. If they turned out to be cheaper or dearer lessons than usual, that shows up in the mix variance; if they were sold at a different price or rate, in the price and FX variances. Each effect is counted once.

  • Do
    (5,890 − 5,612) × 187.25 = +52,055.50 UAH.
  • Don't
    278 × 169.13 (the actual average) ≈ +47,018 UAH.

    The actual average already contains the price, mix and FX effects; volume uses the plan average.

Mix variance: which lessons came

Not every unit leaves the same contribution. At Klasna's plan prices an English lesson in Ukraine leaves 168.13 UAH, maths in the EU 240.50, programming in Ukraine 195.50; the plan's average is 187.25. If the lessons that came shift toward cheaper rows, the month earns less even at the same count.

Mix variance = Σ (actual units of each row × that row's plan contribution) − actual units in total × plan average contribution

Prices and rates stay at plan, so only the shift between rows shows. September brought 454 more English lessons in Ukraine, the lowest row, while programming fell by 120 and maths by 76. Same shelf size, a cheaper shelf: −11,557.50 UAH.

Dataset: September 2026: plan vs actual by subject and market · shown above

A negative mix with positive volume is a classic promo pattern: a discount pulls families toward the product it is on, which is often the one with the thinnest margin. It is also why "more lessons" isn't automatically good news. Ask which lessons.

  • Do
    "Mix −11,557.50: the promo pulled lessons into our lowest-margin row."
  • Don't
    "Mix is negative because we gave a discount."

    The discount itself sits in the price variance; mix is only the shift between rows.

Price variance: what the discounts cost, at plan rates

The price variance measures what changes in the price per unit did to contribution. Use the actual units, since those are the lessons the price applied to, and plan exchange rates, so a currency move can't sneak in:

Price variance = Σ actual units × (actual price − plan price) × plan rate × (1 − fee)

The fee matters: a 2.5% payment fee is charged on what families pay, so only 97.5% of a price change reaches contribution.

In Klasna's September only two rows changed price. English in Ukraine went from 615 to 585 UAH in the back-to-school promo: 3,640 × (−30) × 0.975 = −106,470. A partner school got a deal on programming in Ukraine, 720 → 705: 400 × (−15) × 0.975 = −5,850. The EU rows kept their euro prices. Total: −112,320 UAH, the biggest piece of the September bridge.

Dataset: September 2026: plan vs actual by subject and market · shown above

Note the base: the discount applies to every discounted lesson, including families who would have come anyway. That's what makes price cuts expensive.

  • Do
    3,640 × (−30) × 0.975 + 400 × (−15) × 0.975 = −112,320 UAH.
  • Don't
    3,186 × (−30) × 0.975 = −93,190.50 UAH.

    The discount applied to the 3,640 lessons actually delivered, not the 3,186 planned, and programming is missing.

FX variance: the currency month, kept apart

When some sales or costs are in foreign currency, an exchange-rate move changes contribution without anybody doing anything. Keep it in its own line so it isn't mistaken for performance.

Take the actual lessons and prices and compare them at actual rates minus plan rates. At Klasna two effects run in opposite directions when the hryvnia weakens:

  • EU sales in euros are worth more hryvnias. EU families paid 540 × 15 + 170 × 16 + 80 × 17 = 12,180 EUR. The euro went from 45.00 to 47.00, so each euro brought 2 UAH more, minus the 2.5% fee: 12,180 × 2 × 0.975 = +23,751 UAH.
  • The video + AI bill in dollars costs more. The dollar went from 42.00 to 43.50: 5,890 × 0.75 × 1.50 = −6,626.25 UAH.

Net FX: +17,124.75 UAH. Without the weaker hryvnia, September would look about 17 thousand worse. That's not the team's merit, and next month it can reverse.

September 2026: the contribution bridge · shown above

  • Do
    12,180 × (47 − 45) × 0.975 = +23,751 UAH.
  • Don't
    12,180 × 47 × 0.975 = 558,148.50 UAH of FX gain.

    That's the whole EU revenue in hryvnias; the FX effect is only the change in the rate.

Separate what the team did from what the currency did

A bridge is only useful if it tells you what to do next. The team can act on volume, mix and price; nobody at Klasna controls the hryvnia. So the first reading of a bridge splits it in two:

  • Performance = volume + mix + price. September: 52,055.50 − 11,557.50 − 112,320 = −71,822 UAH.
  • Currency = the FX variance. September: +17,124.75 UAH.

September 2026: the contribution bridge · shown above

Together they give the reported −54,697.25. Read separately, they tell a sharper story: the business missed by almost 72 thousand, and a weaker hryvnia hid about a quarter of that.

This matters for the coming months. If the hryvnia strengthens in October, the same performance will look worse, and the team will be blamed for the currency. If it weakens further, a poor month can look fine. Report both lines every month, and judge people only on the line they can move. The currency line belongs in the rolling forecast as an assumption, not in anyone's scorecard.

  • Do
    "Our own result: −71,822; the currency added +17,124.75."
  • Don't
    "We only missed by 54,697.25, not bad for a promo month."

    The currency flattered the month; the business missed by more.

A bridge that adds up exactly

A price, volume and mix bridge walks from the plan's contribution to the actual one, changing one factor at a time:

  1. Plan contribution: 1,050,847 UAH.
  2. Volume: extra units at the plan average: +52,055.50.
  3. Mix: which units came, at plan prices: −11,557.50.
  4. Price: actual units × price change, at plan rates, after the fee: −112,320.
  5. FX: the same units and prices at actual minus plan rates: +17,124.75.
  6. Check: 1,050,847 + 52,055.50 − 11,557.50 − 112,320 + 17,124.75 = 996,149.75, the actual contribution.

The order isn't magic, but it must be consistent: each step uses the factors already explained at actual and everything else at plan. Then every effect is counted exactly once, and the bridge closes to the hryvnia.

If your pieces don't add up, something is counted twice or missed: usually a price change measured at actual rates (mixing price and FX) or volume valued at the actual average (mixing volume and mix). Fix the method, don't plug the difference.

  • Do
    Plan → volume → mix → price → FX → actual, and the sum checks out.
  • Don't
    "The pieces come to −50,000; we'll put the other 4,697 under 'other'."

    An unexplained plug means the method double-counts or misses something.

Does a discount pay for itself?

A discount is paid on every discounted unit, including customers who would have bought anyway. It earns only on the extra units it brings. So the test is:

Contribution of the extra units at the new price ≥ discount × all discounted units?

Klasna's promo cut English in Ukraine from 615 to 585 UAH on all 3,640 lessons delivered. The cost: 3,640 × 30 × 0.975 = 106,470 UAH. It brought 454 extra lessons. Even generously valued at the plan's 168.13 each, as if every one of them came because of the promo, they leave 454 × 168.13 = 76,328.75. Net: about −30,141 UAH in the best case, before counting the mix shift toward the lowest-margin row.

The volume looks impressive in the sales line, which is why promos are so often declared a success. The contribution test is less flattering and more useful. A promo that pays usually targets new customers only, or a product with a margin wide enough to absorb the discount, and it is judged on contribution, not sales.

  • Do
    454 × 168.125 − 3,640 × 30 × 0.975 = −30,141.25 UAH: the promo didn't pay.
  • Don't
    454 × 168.13 − 454 × 30 × 0.975 ≈ +63,050 UAH: the promo paid.

    The discount went to all 3,640 lessons, not only the 454 new ones.

Ready to practise?

Answer the lesson's exercises and earn 250 points the first time you finish it.

Start the exercises