1. Lighthouse

Level 9 · Boss: the category margin review

The request

From Laura Simmons, Category Finance Partner

“The board wants margin by category for completed orders: the dollars, the margin percentage, and how much margin an average order brings in each category. Nine products still have no cost in the system. Leave their lines out of the margin instead of pretending they cost nothing.”

Your goal

Step 1 of 3. Add two calculated columns to order_items. Line Cost: quantity times the product's unit_cost (RELATED). Line Margin: line_total minus Line Cost, but blank when Line Cost is blank. The matrix shows the given Margin measure, SUM of Line Margin, by category.

  • Add the column Line Margin to order_itemsnot done yet
  • The Total row right toonot done yet

Step 1 · your calculated column

DAX
Visual
A matrix: rows = your new column on order_items, values = [Margin]
Slicers
orders[status] = completed
Measures in the report
Margin = SUM(order_items[Line Margin])
Data pane: tables and columns
  • order_items order_item_id, order_id, product_id, quantity, unit_price, discount_pct, line_total
  • orders order_id, customer_id, order_date, status, channel, shipping_fee, coupon_code
  • products product_id, name, category, subcategory, unit_price, unit_cost, launched_on, is_active
  • customers customer_id, first_name, last_name, email, city, state, signup_date, segment, referral_source
  • returns return_id, order_item_id, returned_on, reason, refund_amount
  • Date Date, Year, Quarter, Month Number, Month, Year Month, Year Quarter, Day, Weekday Number, Weekday

Loading the editor…

    VisualData view of order_items: your column appears in the visual once you press Check
    The visual before your answer
    order_item_idorder_idproduct_idquantityunit_pricediscount_pct
    11,001121931.990
    21,001154311.990
    31,002154411.990
    41,00219411490
    51,002193219.990
    61,002196225.990
    71,002156153.990
    81,003134192.9910

    Mote checks your result

    Press Check. Mote fills in your answer and compares it with what the report needs.

    Step 2 · your measure

    DAX
    Visual
    A matrix: rows = products[category]; values = [Margin], [Costed Sales], [Margin %]
    Slicers
    orders[status] = completed
    Measures in the report
    Margin = SUM(order_items[Line Margin])Costed Sales = SUMX(order_items, IF(ISBLANK(order_items[Line Cost]), BLANK(), order_items[line_total]))order_items[Line Cost] = order_items[quantity] * RELATED(products[unit_cost]) (calculated column)order_items[Line Margin] = IF(ISBLANK(order_items[Line Cost]), BLANK(), order_items[line_total] - order_items[Line Cost]) (calculated column)
    Data pane: tables and columns
    • order_items order_item_id, order_id, product_id, quantity, unit_price, discount_pct, line_total, Line Cost, Line Margin
    • orders order_id, customer_id, order_date, status, channel, shipping_fee, coupon_code
    • products product_id, name, category, subcategory, unit_price, unit_cost, launched_on, is_active
    • customers customer_id, first_name, last_name, email, city, state, signup_date, segment, referral_source
    • returns return_id, order_item_id, returned_on, reason, refund_amount
    • Date Date, Year, Quarter, Month Number, Month, Year Month, Year Quarter, Day, Weekday Number, Weekday

    Loading the editor…

      Visual[Margin %] fills in when you press Check
      The visual before your answer
      categoryMarginCosted SalesMargin %
      Decor$435,465.71$819,058.75
      Furniture$470,726.27$884,103.05
      Kitchen$442,411.71$799,150.28
      Lighting$559,405.70$1,001,843.51
      Outdoor$606,376.48$1,231,614.83
      Textiles$324,795.16$579,657.83
      Total$2,839,181.03$5,315,428.25

      Mote checks your result

      Press Check. Mote fills in your answer and compares it with what the report needs.

      Step 3 · your measure

      DAX
      Visual
      A matrix: rows = products[category]; values = [Margin], [Margin per Order]
      Slicers
      orders[status] = completed
      Measures in the report
      Margin = SUM(order_items[Line Margin])Costed Sales = SUMX(order_items, IF(ISBLANK(order_items[Line Cost]), BLANK(), order_items[line_total]))order_items[Line Cost] = order_items[quantity] * RELATED(products[unit_cost]) (calculated column)order_items[Line Margin] = IF(ISBLANK(order_items[Line Cost]), BLANK(), order_items[line_total] - order_items[Line Cost]) (calculated column)
      Data pane: tables and columns
      • order_items order_item_id, order_id, product_id, quantity, unit_price, discount_pct, line_total, Line Cost, Line Margin
      • orders order_id, customer_id, order_date, status, channel, shipping_fee, coupon_code
      • products product_id, name, category, subcategory, unit_price, unit_cost, launched_on, is_active
      • customers customer_id, first_name, last_name, email, city, state, signup_date, segment, referral_source
      • returns return_id, order_item_id, returned_on, reason, refund_amount
      • Date Date, Year, Quarter, Month Number, Month, Year Month, Year Quarter, Day, Weekday Number, Weekday

      Loading the editor…

        Visual[Margin per Order] fills in when you press Check
        The visual before your answer
        categoryMarginMargin per Order
        Decor$435,465.71
        Furniture$470,726.27
        Kitchen$442,411.71
        Lighting$559,405.70
        Outdoor$606,376.48
        Textiles$324,795.16
        Total$2,839,181.03

        Mote checks your result

        Press Check. Mote fills in your answer and compares it with what the report needs.

        The lesson

        This review uses everything in the chapter: columns that work row by row, measures that work cell by cell, and the model’s relationships deciding what each cell can see.

        What you are working in

        A practice report built for this site, since Power BI Desktop runs only on Windows. Step 1 adds calculated columns to order_items; steps 2 and 3 add measures to a matrix by category, filtered to completed orders. In Power BI Desktop the columns come from Table tools → New column with order_items selected, the measures from Home → New measure, and the completed-only filter is a page filter in the Filters pane.

        Step 1: margin per line

        Line Cost = order_items[quantity] * RELATED(products[unit_cost])

        For the nine products without a cost, RELATED returns blank and the product is blank. The margin needs care, because DAX treats a blank as 0 in subtraction: line_total - blank is the whole line total, a 100% margin that never happened. So test first:

        Line Margin =
        IF(
            ISBLANK(order_items[Line Cost]),
            BLANK(),
            order_items[line_total] - order_items[Line Cost]
        )

        A later column can use an earlier one; that’s why Line Cost comes first.

        Step 2: margin percentage

        Margin dollars over the sales that produced them. Use the given Costed Sales, which adds up line_total only on lines with a cost, so the numerator and the denominator cover the same lines. Dividing by all sales would mix lines that have a margin with lines that don’t, and push the percentage down in the categories with missing costs.

        Step 3: margin per order

        How much margin does an average order bring in each category? Margin over the number of orders. But which orders? The category filter flows from products to order_items and stops there: orders is on the one side of its relationship with order_items, so a single-direction relationship never filters it. COUNTROWS(orders) would return all completed orders on every row. The orders a category touches are the distinct order_ids among its lines:

        DISTINCTCOUNT(order_items[order_id])

        An order with a lamp and a rug counts once for Lighting and once for Textiles, but only once in the Total.

        Reading the results

        Margin per Order is highest where baskets are expensive, not necessarily where Margin % is highest. Show both: the percentage says how profitable each sale is, the per-order figure says how much each basket is worth to the business.

        Common mistakes

        • Subtracting a blank cost. It silently becomes a full-price margin.
        • All sales as the denominator. Margin % comes out too low wherever costs are missing.
        • Counting orders from orders. The category filter doesn’t reach that table.

        Pick what may run on this site. You can change this any time from "Cookie settings" at the bottom of every page.